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:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blendthumb/src/blendthumb.hh4
-rw-r--r--source/blender/blendthumb/src/blendthumb_extract.cc4
-rw-r--r--source/blender/blenfont/BLF_api.h135
-rw-r--r--source/blender/blenfont/intern/blf.c11
-rw-r--r--source/blender/blenfont/intern/blf_dir.c4
-rw-r--r--source/blender/blenfont/intern/blf_font.c5
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c9
-rw-r--r--source/blender/blenfont/intern/blf_internal.h16
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c5
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h78
-rw-r--r--source/blender/blenkernel/BKE_action.h187
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h63
-rw-r--r--source/blender/blenkernel/BKE_anim_path.h11
-rw-r--r--source/blender/blenkernel/BKE_anim_visualization.h21
-rw-r--r--source/blender/blenkernel/BKE_animsys.h60
-rw-r--r--source/blender/blenkernel/BKE_appdir.h100
-rw-r--r--source/blender/blenkernel/BKE_armature.h193
-rw-r--r--source/blender/blenkernel/BKE_asset.h3
-rw-r--r--source/blender/blenkernel/BKE_asset_catalog.hh17
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh27
-rw-r--r--source/blender/blenkernel/BKE_autoexec.h4
-rw-r--r--source/blender/blenkernel/BKE_blender.h11
-rw-r--r--source/blender/blenkernel/BKE_blender_copybuffer.h40
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h43
-rw-r--r--source/blender/blenkernel/BKE_blendfile_link_append.h222
-rw-r--r--source/blender/blenkernel/BKE_boids.h6
-rw-r--r--source/blender/blenkernel/BKE_bpath.h211
-rw-r--r--source/blender/blenkernel/BKE_brush.h73
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h67
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h6
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h3
-rw-r--r--source/blender/blenkernel/BKE_camera.h29
-rw-r--r--source/blender/blenkernel/BKE_cloth.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h112
-rw-r--r--source/blender/blenkernel/BKE_collision.h20
-rw-r--r--source/blender/blenkernel/BKE_colortools.h75
-rw-r--r--source/blender/blenkernel/BKE_constraint.h109
-rw-r--r--source/blender/blenkernel/BKE_context.h33
-rw-r--r--source/blender/blenkernel/BKE_crazyspace.h8
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h3
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh20
-rw-r--r--source/blender/blenkernel/BKE_curve.h108
-rw-r--r--source/blender/blenkernel/BKE_curve_to_mesh.hh14
-rw-r--r--source/blender/blenkernel/BKE_curveprofile.h83
-rw-r--r--source/blender/blenkernel/BKE_customdata.h313
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h10
-rw-r--r--source/blender/blenkernel/BKE_deform.h105
-rw-r--r--source/blender/blenkernel/BKE_displist.h6
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h3
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h40
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h20
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h10
-rw-r--r--source/blender/blenkernel/BKE_editmesh_tangent.h7
-rw-r--r--source/blender/blenkernel/BKE_effect.h29
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h247
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h51
-rw-r--r--source/blender/blenkernel/BKE_fluid.h4
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh323
-rw-r--r--source/blender/blenkernel/BKE_geometry_set_instances.hh15
-rw-r--r--source/blender/blenkernel/BKE_global.h88
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h408
-rw-r--r--source/blender/blenkernel/BKE_gpencil_curve.h29
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h276
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h126
-rw-r--r--source/blender/blenkernel/BKE_icons.h104
-rw-r--r--source/blender/blenkernel/BKE_idprop.h139
-rw-r--r--source/blender/blenkernel/BKE_idtype.h94
-rw-r--r--source/blender/blenkernel/BKE_image.h217
-rw-r--r--source/blender/blenkernel/BKE_ipo.h13
-rw-r--r--source/blender/blenkernel/BKE_key.h83
-rw-r--r--source/blender/blenkernel/BKE_keyconfig.h12
-rw-r--r--source/blender/blenkernel/BKE_lattice.h1
-rw-r--r--source/blender/blenkernel/BKE_layer.h128
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h289
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h227
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h75
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h31
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_main.h114
-rw-r--r--source/blender/blenkernel/BKE_main_idmap.h11
-rw-r--r--source/blender/blenkernel/BKE_mask.h128
-rw-r--r--source/blender/blenkernel/BKE_material.h88
-rw-r--r--source/blender/blenkernel/BKE_mball.h42
-rw-r--r--source/blender/blenkernel/BKE_mesh.h347
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.hh10
-rw-r--r--source/blender/blenkernel/BKE_mesh_iterators.h5
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h79
-rw-r--r--source/blender/blenkernel/BKE_mesh_mirror.h14
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h13
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h26
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h21
-rw-r--r--source/blender/blenkernel/BKE_modifier.h72
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h30
-rw-r--r--source/blender/blenkernel/BKE_multires.h72
-rw-r--r--source/blender/blenkernel/BKE_nla.h198
-rw-r--r--source/blender/blenkernel/BKE_node.h319
-rw-r--r--source/blender/blenkernel/BKE_object.h276
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h88
-rw-r--r--source/blender/blenkernel/BKE_ocean.h42
-rw-r--r--source/blender/blenkernel/BKE_packedFile.h44
-rw-r--r--source/blender/blenkernel/BKE_paint.h103
-rw-r--r--source/blender/blenkernel/BKE_particle.h121
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h75
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h81
-rw-r--r--source/blender/blenkernel/BKE_pointcloud.h2
-rw-r--r--source/blender/blenkernel/BKE_preferences.h10
-rw-r--r--source/blender/blenkernel/BKE_report.h7
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h129
-rw-r--r--source/blender/blenkernel/BKE_scene.h122
-rw-r--r--source/blender/blenkernel/BKE_screen.h80
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h22
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h86
-rw-r--r--source/blender/blenkernel/BKE_softbody.h39
-rw-r--r--source/blender/blenkernel/BKE_spline.hh168
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h8
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h18
-rw-r--r--source/blender/blenkernel/BKE_text.h48
-rw-r--r--source/blender/blenkernel/BKE_texture.h12
-rw-r--r--source/blender/blenkernel/BKE_tracking.h267
-rw-r--r--source/blender/blenkernel/BKE_type_conversions.hh (renamed from source/blender/nodes/NOD_type_conversions.hh)6
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h103
-rw-r--r--source/blender/blenkernel/BKE_unit.h54
-rw-r--r--source/blender/blenkernel/BKE_vfont.h3
-rw-r--r--source/blender/blenkernel/BKE_vfontdata.h6
-rw-r--r--source/blender/blenkernel/BKE_volume.h5
-rw-r--r--source/blender/blenkernel/BKE_volume_to_mesh.hh2
-rw-r--r--source/blender/blenkernel/BKE_workspace.h59
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h4
-rw-r--r--source/blender/blenkernel/CMakeLists.txt10
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h17
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_legacy.c4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc67
-rw-r--r--source/blender/blenkernel/intern/action.c128
-rw-r--r--source/blender/blenkernel/intern/anim_data.c83
-rw-r--r--source/blender/blenkernel/intern/anim_path.c12
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c71
-rw-r--r--source/blender/blenkernel/intern/anim_visualization.c14
-rw-r--r--source/blender/blenkernel/intern/appdir.c107
-rw-r--r--source/blender/blenkernel/intern/armature.c192
-rw-r--r--source/blender/blenkernel/intern/armature_deform.c1
-rw-r--r--source/blender/blenkernel/intern/armature_update.c90
-rw-r--r--source/blender/blenkernel/intern/asset.cc5
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc31
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_path.cc2
-rw-r--r--source/blender/blenkernel/intern/asset_library.cc4
-rw-r--r--source/blender/blenkernel/intern/asset_library_service.cc3
-rw-r--r--source/blender/blenkernel/intern/asset_library_service_test.cc4
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc135
-rw-r--r--source/blender/blenkernel/intern/autoexec.c4
-rw-r--r--source/blender/blenkernel/intern/blender.c9
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c153
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c4
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c70
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c1615
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c914
-rw-r--r--source/blender/blenkernel/intern/bpath_test.cc181
-rw-r--r--source/blender/blenkernel/intern/brush.c36
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc63
-rw-r--r--source/blender/blenkernel/intern/cachefile.c15
-rw-r--r--source/blender/blenkernel/intern/callbacks.c1
-rw-r--r--source/blender/blenkernel/intern/camera.c8
-rw-r--r--source/blender/blenkernel/intern/cloth.c3
-rw-r--r--source/blender/blenkernel/intern/collection.c112
-rw-r--r--source/blender/blenkernel/intern/collision.c8
-rw-r--r--source/blender/blenkernel/intern/colortools.c30
-rw-r--r--source/blender/blenkernel/intern/constraint.c55
-rw-r--r--source/blender/blenkernel/intern/context.c13
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c5
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc18
-rw-r--r--source/blender/blenkernel/intern/curve.cc (renamed from source/blender/blenkernel/intern/curve.c)560
-rw-r--r--source/blender/blenkernel/intern/curve_bevel.c44
-rw-r--r--source/blender/blenkernel/intern/curve_deform.c6
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc56
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc14
-rw-r--r--source/blender/blenkernel/intern/curveprofile.cc79
-rw-r--r--source/blender/blenkernel/intern/customdata.c105
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c10
-rw-r--r--source/blender/blenkernel/intern/data_transfer_intern.h4
-rw-r--r--source/blender/blenkernel/intern/deform.c134
-rw-r--r--source/blender/blenkernel/intern/displist.cc45
-rw-r--r--source/blender/blenkernel/intern/displist_tangent.c4
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c20
-rw-r--r--source/blender/blenkernel/intern/editmesh.c16
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c6
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c7
-rw-r--r--source/blender/blenkernel/intern/effect.c62
-rw-r--r--source/blender/blenkernel/intern/fcurve.c108
-rw-r--r--source/blender/blenkernel/intern/fcurve_cache.c5
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c26
-rw-r--r--source/blender/blenkernel/intern/fluid.c6
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c56
-rw-r--r--source/blender/blenkernel/intern/freestyle.c4
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc227
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc175
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc62
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc9
-rw-r--r--source/blender/blenkernel/intern/geometry_component_volume.cc7
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc196
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc389
-rw-r--r--source/blender/blenkernel/intern/gpencil.c403
-rw-r--r--source/blender/blenkernel/intern/gpencil_curve.c29
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc370
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c221
-rw-r--r--source/blender/blenkernel/intern/hair.c5
-rw-r--r--source/blender/blenkernel/intern/icons.cc98
-rw-r--r--source/blender/blenkernel/intern/idprop.c124
-rw-r--r--source/blender/blenkernel/intern/idtype.c71
-rw-r--r--source/blender/blenkernel/intern/image.c169
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc (renamed from source/blender/blenkernel/intern/image_gpu.c)128
-rw-r--r--source/blender/blenkernel/intern/ipo.c13
-rw-r--r--source/blender/blenkernel/intern/key.c72
-rw-r--r--source/blender/blenkernel/intern/keyconfig.c5
-rw-r--r--source/blender/blenkernel/intern/lattice.c2
-rw-r--r--source/blender/blenkernel/intern/layer.c174
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c8
-rw-r--r--source/blender/blenkernel/intern/lib_id.c280
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c49
-rw-r--r--source/blender/blenkernel/intern/lib_id_eval.c5
-rw-r--r--source/blender/blenkernel/intern/lib_override.c304
-rw-r--r--source/blender/blenkernel/intern/lib_query.c70
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c34
-rw-r--r--source/blender/blenkernel/intern/library.c23
-rw-r--r--source/blender/blenkernel/intern/light.c2
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c2
-rw-r--r--source/blender/blenkernel/intern/linestyle.c6
-rw-r--r--source/blender/blenkernel/intern/main.c106
-rw-r--r--source/blender/blenkernel/intern/main_idmap.c12
-rw-r--r--source/blender/blenkernel/intern/mask.c32
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c5
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c3
-rw-r--r--source/blender/blenkernel/intern/material.c25
-rw-r--r--source/blender/blenkernel/intern/mball.c72
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c18
-rw-r--r--source/blender/blenkernel/intern/mesh.cc143
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc10
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc5
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc81
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c9
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c88
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c32
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c50
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc62
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c21
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c34
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c21
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c22
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c55
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc3
-rw-r--r--source/blender/blenkernel/intern/modifier.c83
-rw-r--r--source/blender/blenkernel/intern/movieclip.c25
-rw-r--r--source/blender/blenkernel/intern/multires.c15
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c4
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.h123
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c7
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_vertcos.c1
-rw-r--r--source/blender/blenkernel/intern/nla.c212
-rw-r--r--source/blender/blenkernel/intern/node.cc261
-rw-r--r--source/blender/blenkernel/intern/object.cc451
-rw-r--r--source/blender/blenkernel/intern/object_deform.c84
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc55
-rw-r--r--source/blender/blenkernel/intern/object_update.c19
-rw-r--r--source/blender/blenkernel/intern/ocean.c12
-rw-r--r--source/blender/blenkernel/intern/ocean_spectrum.c17
-rw-r--r--source/blender/blenkernel/intern/packedFile.c21
-rw-r--r--source/blender/blenkernel/intern/paint.c39
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c4
-rw-r--r--source/blender/blenkernel/intern/particle.c59
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c7
-rw-r--r--source/blender/blenkernel/intern/particle_system.c22
-rw-r--r--source/blender/blenkernel/intern/pbvh.c16
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c6
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h9
-rw-r--r--source/blender/blenkernel/intern/pointcache.c93
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc5
-rw-r--r--source/blender/blenkernel/intern/preferences.c10
-rw-r--r--source/blender/blenkernel/intern/report.c5
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c25
-rw-r--r--source/blender/blenkernel/intern/scene.c113
-rw-r--r--source/blender/blenkernel/intern/screen.c75
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c14
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c80
-rw-r--r--source/blender/blenkernel/intern/simulation.cc2
-rw-r--r--source/blender/blenkernel/intern/softbody.c19
-rw-r--r--source/blender/blenkernel/intern/sound.c26
-rw-r--r--source/blender/blenkernel/intern/speaker.c2
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc35
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc63
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc3
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc9
-rw-r--r--source/blender/blenkernel/intern/studiolight.c6
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c5
-rw-r--r--source/blender/blenkernel/intern/text.c52
-rw-r--r--source/blender/blenkernel/intern/texture.c9
-rw-r--r--source/blender/blenkernel/intern/tracking.c121
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_detect.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_plane_tracker.c1
-rw-r--r--source/blender/blenkernel/intern/tracking_region_tracker.c6
-rw-r--r--source/blender/blenkernel/intern/tracking_solver.c22
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c36
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c17
-rw-r--r--source/blender/blenkernel/intern/type_conversions.cc (renamed from source/blender/nodes/intern/type_conversions.cc)31
-rw-r--r--source/blender/blenkernel/intern/undo_system.c146
-rw-r--r--source/blender/blenkernel/intern/unit.c17
-rw-r--r--source/blender/blenkernel/intern/vfont.c23
-rw-r--r--source/blender/blenkernel/intern/vfontdata_freetype.c8
-rw-r--r--source/blender/blenkernel/intern/volume.cc17
-rw-r--r--source/blender/blenkernel/intern/workspace.c46
-rw-r--r--source/blender/blenkernel/intern/world.c2
-rw-r--r--source/blender/blenkernel/intern/writeavi.c1
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c26
-rw-r--r--source/blender/blenkernel/nla_private.h33
-rw-r--r--source/blender/blenkernel/tracking_private.h38
-rw-r--r--source/blender/blenlib/BLI_array.h49
-rw-r--r--source/blender/blenlib/BLI_array_store.h67
-rw-r--r--source/blender/blenlib/BLI_array_utils.h60
-rw-r--r--source/blender/blenlib/BLI_astar.h50
-rw-r--r--source/blender/blenlib/BLI_bitmap.h59
-rw-r--r--source/blender/blenlib/BLI_bitmap_draw_2d.h20
-rw-r--r--source/blender/blenlib/BLI_boxpack_2d.h29
-rw-r--r--source/blender/blenlib/BLI_buffer.h28
-rw-r--r--source/blender/blenlib/BLI_convexhull_2d.h33
-rw-r--r--source/blender/blenlib/BLI_dlrbTree.h138
-rw-r--r--source/blender/blenlib/BLI_dynstr.h62
-rw-r--r--source/blender/blenlib/BLI_edgehash.h91
-rw-r--r--source/blender/blenlib/BLI_expr_pylike_eval.h22
-rw-r--r--source/blender/blenlib/BLI_fileops.h167
-rw-r--r--source/blender/blenlib/BLI_ghash.h243
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h20
-rw-r--r--source/blender/blenlib/BLI_hash_md5.h19
-rw-r--r--source/blender/blenlib/BLI_hash_mm2a.h3
-rw-r--r--source/blender/blenlib/BLI_heap.h36
-rw-r--r--source/blender/blenlib/BLI_heap_simple.h15
-rw-r--r--source/blender/blenlib/BLI_index_mask.hh23
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h126
-rw-r--r--source/blender/blenlib/BLI_lasso_2d.h3
-rw-r--r--source/blender/blenlib/BLI_linklist.h13
-rw-r--r--source/blender/blenlib/BLI_listbase.h160
-rw-r--r--source/blender/blenlib/BLI_math_base.h76
-rw-r--r--source/blender/blenlib/BLI_math_boolean.hh27
-rw-r--r--source/blender/blenlib/BLI_math_color.h87
-rw-r--r--source/blender/blenlib/BLI_math_geom.h633
-rw-r--r--source/blender/blenlib/BLI_math_interp.h3
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h228
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h212
-rw-r--r--source/blender/blenlib/BLI_math_solvers.h62
-rw-r--r--source/blender/blenlib/BLI_math_statistics.h26
-rw-r--r--source/blender/blenlib/BLI_math_time.h29
-rw-r--r--source/blender/blenlib/BLI_math_vector.h269
-rw-r--r--source/blender/blenlib/BLI_memarena.h18
-rw-r--r--source/blender/blenlib/BLI_memblock.h9
-rw-r--r--source/blender/blenlib/BLI_memiter.h21
-rw-r--r--source/blender/blenlib/BLI_mempool.h44
-rw-r--r--source/blender/blenlib/BLI_mesh_intersect.hh28
-rw-r--r--source/blender/blenlib/BLI_noise.h78
-rw-r--r--source/blender/blenlib/BLI_noise.hh162
-rw-r--r--source/blender/blenlib/BLI_path_util.h284
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d.h16
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d_beautify.h21
-rw-r--r--source/blender/blenlib/BLI_rand.h27
-rw-r--r--source/blender/blenlib/BLI_rand.hh6
-rw-r--r--source/blender/blenlib/BLI_rect.h56
-rw-r--r--source/blender/blenlib/BLI_scanfill.h6
-rw-r--r--source/blender/blenlib/BLI_smallhash.h22
-rw-r--r--source/blender/blenlib/BLI_stack.h49
-rw-r--r--source/blender/blenlib/BLI_string.h318
-rw-r--r--source/blender/blenlib/BLI_string_search.h30
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h116
-rw-r--r--source/blender/blenlib/BLI_string_utils.h78
-rw-r--r--source/blender/blenlib/BLI_task.h201
-rw-r--r--source/blender/blenlib/BLI_task.hh15
-rw-r--r--source/blender/blenlib/BLI_threads.h20
-rw-r--r--source/blender/blenlib/BLI_timecode.h34
-rw-r--r--source/blender/blenlib/BLI_utildefines.h3
-rw-r--r--source/blender/blenlib/BLI_uvproject.h24
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh241
-rw-r--r--source/blender/blenlib/BLI_voxel.h6
-rw-r--r--source/blender/blenlib/intern/BLI_array.c5
-rw-r--r--source/blender/blenlib/intern/BLI_assert.c13
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c61
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c33
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c225
-rw-r--r--source/blender/blenlib/intern/BLI_ghash_utils.c12
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c31
-rw-r--r--source/blender/blenlib/intern/BLI_heap_simple.c15
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c47
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c10
-rw-r--r--source/blender/blenlib/intern/BLI_memarena.c14
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c5
-rw-r--r--source/blender/blenlib/intern/BLI_memiter.c10
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c61
-rw-r--r--source/blender/blenlib/intern/BLI_mempool_private.h18
-rw-r--r--source/blender/blenlib/intern/DLRB_tree.c15
-rw-r--r--source/blender/blenlib/intern/array_store.c60
-rw-r--r--source/blender/blenlib/intern/array_utils.c60
-rw-r--r--source/blender/blenlib/intern/astar.c50
-rw-r--r--source/blender/blenlib/intern/bitmap.c5
-rw-r--r--source/blender/blenlib/intern/bitmap_draw_2d.c20
-rw-r--r--source/blender/blenlib/intern/boxpack_2d.c29
-rw-r--r--source/blender/blenlib/intern/buffer.c7
-rw-r--r--source/blender/blenlib/intern/convexhull_2d.c33
-rw-r--r--source/blender/blenlib/intern/edgehash.c90
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c14
-rw-r--r--source/blender/blenlib/intern/fileops.c27
-rw-r--r--source/blender/blenlib/intern/filereader_zstd.c3
-rw-r--r--source/blender/blenlib/intern/gsqueue.c20
-rw-r--r--source/blender/blenlib/intern/hash_md5.c10
-rw-r--r--source/blender/blenlib/intern/hash_mm2a.c1
-rw-r--r--source/blender/blenlib/intern/index_mask.cc20
-rw-r--r--source/blender/blenlib/intern/lasso_2d.c1
-rw-r--r--source/blender/blenlib/intern/listbase.c157
-rw-r--r--source/blender/blenlib/intern/math_base.c22
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c36
-rw-r--r--source/blender/blenlib/intern/math_boolean.cc15
-rw-r--r--source/blender/blenlib/intern/math_color.c33
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c20
-rw-r--r--source/blender/blenlib/intern/math_geom.c438
-rw-r--r--source/blender/blenlib/intern/math_geom_inline.c29
-rw-r--r--source/blender/blenlib/intern/math_interp.c3
-rw-r--r--source/blender/blenlib/intern/math_matrix.c190
-rw-r--r--source/blender/blenlib/intern/math_rotation.c103
-rw-r--r--source/blender/blenlib/intern/math_solvers.c46
-rw-r--r--source/blender/blenlib/intern/math_statistics.c20
-rw-r--r--source/blender/blenlib/intern/math_time.c7
-rw-r--r--source/blender/blenlib/intern/math_vector.c112
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c51
-rw-r--r--source/blender/blenlib/intern/memory_utils.c3
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc13
-rw-r--r--source/blender/blenlib/intern/mesh_intersect.cc156
-rw-r--r--source/blender/blenlib/intern/noise.c76
-rw-r--r--source/blender/blenlib/intern/noise.cc205
-rw-r--r--source/blender/blenlib/intern/path_util.c275
-rw-r--r--source/blender/blenlib/intern/polyfill_2d.c16
-rw-r--r--source/blender/blenlib/intern/polyfill_2d_beautify.c21
-rw-r--r--source/blender/blenlib/intern/rand.cc29
-rw-r--r--source/blender/blenlib/intern/rct.c88
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c5
-rw-r--r--source/blender/blenlib/intern/smallhash.c14
-rw-r--r--source/blender/blenlib/intern/stack.c49
-rw-r--r--source/blender/blenlib/intern/storage.c61
-rw-r--r--source/blender/blenlib/intern/storage_apple.mm19
-rw-r--r--source/blender/blenlib/intern/string.c568
-rw-r--r--source/blender/blenlib/intern/string_search.cc42
-rw-r--r--source/blender/blenlib/intern/string_utf8.c135
-rw-r--r--source/blender/blenlib/intern/string_utils.c68
-rw-r--r--source/blender/blenlib/intern/system.c3
-rw-r--r--source/blender/blenlib/intern/system_win32.c3
-rw-r--r--source/blender/blenlib/intern/task_iterator.c36
-rw-r--r--source/blender/blenlib/intern/threads.cc38
-rw-r--r--source/blender/blenlib/intern/timecode.c33
-rw-r--r--source/blender/blenlib/intern/uuid.cc2
-rw-r--r--source/blender/blenlib/intern/uvproject.c3
-rw-r--r--source/blender/blenlib/intern/voxel.c2
-rw-r--r--source/blender/blenlib/tests/BLI_color_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_virtual_array_test.cc2
-rw-r--r--source/blender/blenloader/BLO_blend_validate.h7
-rw-r--r--source/blender/blenloader/BLO_read_write.h120
-rw-r--r--source/blender/blenloader/BLO_readfile.h198
-rw-r--r--source/blender/blenloader/BLO_undofile.h21
-rw-r--r--source/blender/blenloader/BLO_writefile.h16
-rw-r--r--source/blender/blenloader/CMakeLists.txt2
-rw-r--r--source/blender/blenloader/intern/blend_validate.c5
-rw-r--r--source/blender/blenloader/intern/readblenentry.c96
-rw-r--r--source/blender/blenloader/intern/readfile.c555
-rw-r--r--source/blender/blenloader/intern/readfile.h56
-rw-r--r--source/blender/blenloader/intern/readfile_tempload.c2
-rw-r--r--source/blender/blenloader/intern/undofile.c9
-rw-r--r--source/blender/blenloader/intern/versioning_260.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c103
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc43
-rw-r--r--source/blender/blenloader/intern/versioning_common.h36
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c9
-rw-r--r--source/blender/blenloader/intern/versioning_dna.c10
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c2
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c1
-rw-r--r--source/blender/blenloader/intern/writefile.c60
-rw-r--r--source/blender/blentranslation/BLT_lang.h9
-rw-r--r--source/blender/blentranslation/BLT_translation.h5
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c13
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c97
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h92
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c287
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h290
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c13
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.h17
-rw-r--r--source/blender/bmesh/intern/bmesh_error.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c46
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h46
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c45
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h60
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c119
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h119
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c73
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h86
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c81
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h88
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.c31
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.h31
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_duplicate.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_duplicate.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.c44
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.h41
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.c28
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.h28
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_tessellate.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c187
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h187
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h272
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c148
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h42
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c186
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h180
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c16
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h12
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c533
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h526
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.c23
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.h23
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c60
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h60
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c53
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h52
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c17
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c11
-rw-r--r--source/blender/bmesh/operators/bmo_create.c7
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c1
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c42
-rw-r--r--source/blender/bmesh/operators/bmo_split_edges.c1
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c6
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c3
-rw-r--r--source/blender/bmesh/operators/bmo_unsubdivide.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c9
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.h9
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c12
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h12
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c7
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc8
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.h10
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate.h16
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c14
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c9
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.h9
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c8
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h8
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_path_uv.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c7
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.h6
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.h4
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.h6
-rw-r--r--source/blender/compositor/COM_compositor.h11
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.cc8
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.h8
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cc4
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h4
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc3
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h3
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.cc18
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.h22
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc12
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h12
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.cc1
-rw-r--r--source/blender/compositor/intern/COM_MetaData.cc4
-rw-r--r--source/blender/compositor/intern/COM_MetaData.h6
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.cc43
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h42
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.h2
-rw-r--r--source/blender/compositor/intern/COM_SharedOperationBuffers.cc34
-rw-r--r--source/blender/compositor/intern/COM_SharedOperationBuffers.h29
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cc5
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.h5
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cc1
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cc3
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc6
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cc5
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_TransformOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_TransformOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cc1
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h116
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h43
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h14
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h94
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc70
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h21
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc20
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h5
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc7
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc11
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc8
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_update.cc1
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc7
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc10
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h22
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h8
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc15
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h18
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc30
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h12
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.cc1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h4
-rw-r--r--source/blender/draw/CMakeLists.txt3
-rw-r--r--source/blender/draw/DRW_engine.h52
-rw-r--r--source/blender/draw/DRW_select_buffer.h28
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h15
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c9
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h96
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c11
-rw-r--r--source/blender/draw/engines/eevee/eevee_sampling.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows_cube.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c2
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl2
-rw-r--r--source/blender/draw/engines/external/external_engine.c3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c8
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h12
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c1
-rw-r--r--source/blender/draw/engines/image/image_drawing_mode_image_space.hh (renamed from source/blender/draw/engines/image/image_drawing_mode.hh)22
-rw-r--r--source/blender/draw/engines/image/image_engine.cc11
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c37
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c1
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h7
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c38
-rw-r--r--source/blender/draw/engines/select/select_debug_engine.c1
-rw-r--r--source/blender/draw/engines/select/select_engine.c1
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_antialiasing.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c3
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c1
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h14
-rw-r--r--source/blender/draw/engines/workbench/workbench_transparent.c2
-rw-r--r--source/blender/draw/intern/DRW_render.h244
-rw-r--r--source/blender/draw/intern/draw_cache.c48
-rw-r--r--source/blender/draw/intern/draw_cache.h52
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc7
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.c9
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h146
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c27
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.c1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c11
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c9
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c1
-rw-r--r--source/blender/draw/intern/draw_color_management.cc1
-rw-r--r--source/blender/draw/intern/draw_color_management.h3
-rw-r--r--source/blender/draw/intern/draw_common.c8
-rw-r--r--source/blender/draw/intern/draw_common.h14
-rw-r--r--source/blender/draw/intern/draw_debug.c1
-rw-r--r--source/blender/draw/intern/draw_debug.h3
-rw-r--r--source/blender/draw/intern/draw_fluid.c3
-rw-r--r--source/blender/draw/intern/draw_hair.c1
-rw-r--r--source/blender/draw/intern/draw_hair_private.h6
-rw-r--r--source/blender/draw/intern/draw_instance_data.c23
-rw-r--r--source/blender/draw/intern/draw_instance_data.h48
-rw-r--r--source/blender/draw/intern/draw_manager.c144
-rw-r--r--source/blender/draw/intern/draw_manager.h5
-rw-r--r--source/blender/draw/intern/draw_manager_data.c40
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c17
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c3
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.h7
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c2
-rw-r--r--source/blender/draw/intern/draw_manager_text.c1
-rw-r--r--source/blender/draw/intern/draw_manager_text.h1
-rw-r--r--source/blender/draw/intern/draw_select_buffer.c26
-rw-r--r--source/blender/draw/intern/draw_texture_pool.cc7
-rw-r--r--source/blender/draw/intern/draw_texture_pool.h7
-rw-r--r--source/blender/draw/intern/draw_view.c4
-rw-r--r--source/blender/draw/intern/draw_view_data.cc11
-rw-r--r--source/blender/draw/intern/draw_view_data.h11
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc3
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc5
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc1
-rw-r--r--source/blender/draw/intern/shaders/common_fxaa_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl2
-rw-r--r--source/blender/editors/animation/CMakeLists.txt12
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c28
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c18
-rw-r--r--source/blender/editors/animation/anim_deps.c6
-rw-r--r--source/blender/editors/animation/anim_draw.c82
-rw-r--r--source/blender/editors/animation/anim_filter.c21
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c8
-rw-r--r--source/blender/editors/animation/anim_markers.c31
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c14
-rw-r--r--source/blender/editors/animation/drivers.c53
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c11
-rw-r--r--source/blender/editors/animation/keyframes_edit.c34
-rw-r--r--source/blender/editors/animation/keyframes_general.c116
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc2
-rw-r--r--source/blender/editors/animation/keyframes_keylist_test.cc144
-rw-r--r--source/blender/editors/animation/keyframing.c125
-rw-r--r--source/blender/editors/animation/keyingsets.c40
-rw-r--r--source/blender/editors/armature/armature_add.c7
-rw-r--r--source/blender/editors/armature/armature_edit.c8
-rw-r--r--source/blender/editors/armature/armature_intern.h94
-rw-r--r--source/blender/editors/armature/armature_naming.c16
-rw-r--r--source/blender/editors/armature/armature_ops.c3
-rw-r--r--source/blender/editors/armature/armature_relations.c3
-rw-r--r--source/blender/editors/armature/armature_select.c14
-rw-r--r--source/blender/editors/armature/armature_utils.c84
-rw-r--r--source/blender/editors/armature/editarmature_undo.c1
-rw-r--r--source/blender/editors/armature/pose_edit.c9
-rw-r--r--source/blender/editors/armature/pose_select.c16
-rw-r--r--source/blender/editors/armature/pose_transform.c4
-rw-r--r--source/blender/editors/armature/pose_utils.c13
-rw-r--r--source/blender/editors/asset/CMakeLists.txt2
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.h2
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.hh25
-rw-r--r--source/blender/editors/asset/ED_asset_filter.h14
-rw-r--r--source/blender/editors/asset/ED_asset_handle.h6
-rw-r--r--source/blender/editors/asset/ED_asset_indexer.h50
-rw-r--r--source/blender/editors/asset/ED_asset_library.h20
-rw-r--r--source/blender/editors/asset/ED_asset_list.h26
-rw-r--r--source/blender/editors/asset/ED_asset_temp_id_consumer.h5
-rw-r--r--source/blender/editors/asset/intern/asset_catalog.cc23
-rw-r--r--source/blender/editors/asset/intern/asset_filter.cc12
-rw-r--r--source/blender/editors/asset/intern/asset_handle.cc6
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc781
-rw-r--r--source/blender/editors/asset/intern/asset_library_reference_enum.cc46
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc36
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc330
-rw-r--r--source/blender/editors/curve/curve_intern.h13
-rw-r--r--source/blender/editors/curve/editcurve.c23
-rw-r--r--source/blender/editors/curve/editcurve_paint.c4
-rw-r--r--source/blender/editors/curve/editcurve_select.c2
-rw-r--r--source/blender/editors/curve/editcurve_undo.c1
-rw-r--r--source/blender/editors/curve/editfont.c5
-rw-r--r--source/blender/editors/curve/editfont_undo.c1
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c3
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_intern.h7
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_utils.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c10
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c8
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c11
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c18
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c1
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_add_blank.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_add_lineart.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_edit_curve.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h130
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c15
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_trace.h32
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_utils.c32
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c189
-rw-r--r--source/blender/editors/include/BIF_glutil.h26
-rw-r--r--source/blender/editors/include/ED_anim_api.h366
-rw-r--r--source/blender/editors/include/ED_armature.h137
-rw-r--r--source/blender/editors/include/ED_buttons.h5
-rw-r--r--source/blender/editors/include/ED_clip.h15
-rw-r--r--source/blender/editors/include/ED_curve.h24
-rw-r--r--source/blender/editors/include/ED_file_indexer.h153
-rw-r--r--source/blender/editors/include/ED_fileselect.h30
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h10
-rw-r--r--source/blender/editors/include/ED_gpencil.h268
-rw-r--r--source/blender/editors/include/ED_image.h37
-rw-r--r--source/blender/editors/include/ED_info.h5
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h127
-rw-r--r--source/blender/editors/include/ED_keyframing.h349
-rw-r--r--source/blender/editors/include/ED_lattice.h4
-rw-r--r--source/blender/editors/include/ED_markers.h63
-rw-r--r--source/blender/editors/include/ED_mask.h49
-rw-r--r--source/blender/editors/include/ED_mball.h18
-rw-r--r--source/blender/editors/include/ED_mesh.h196
-rw-r--r--source/blender/editors/include/ED_node.h46
-rw-r--r--source/blender/editors/include/ED_numinput.h6
-rw-r--r--source/blender/editors/include/ED_object.h161
-rw-r--r--source/blender/editors/include/ED_outliner.h17
-rw-r--r--source/blender/editors/include/ED_paint.h16
-rw-r--r--source/blender/editors/include/ED_particle.h6
-rw-r--r--source/blender/editors/include/ED_render.h22
-rw-r--r--source/blender/editors/include/ED_scene.h7
-rw-r--r--source/blender/editors/include/ED_screen.h261
-rw-r--r--source/blender/editors/include/ED_sculpt.h9
-rw-r--r--source/blender/editors/include/ED_select_utils.h14
-rw-r--r--source/blender/editors/include/ED_sequencer.h10
-rw-r--r--source/blender/editors/include/ED_space_api.h20
-rw-r--r--source/blender/editors/include/ED_text.h9
-rw-r--r--source/blender/editors/include/ED_transform.h17
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h23
-rw-r--r--source/blender/editors/include/ED_undo.h49
-rw-r--r--source/blender/editors/include/ED_util.h34
-rw-r--r--source/blender/editors/include/ED_uvedit.h14
-rw-r--r--source/blender/editors/include/ED_view3d.h426
-rw-r--r--source/blender/editors/include/ED_view3d_offscreen.h18
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/include/UI_interface.h575
-rw-r--r--source/blender/editors/include/UI_interface.hh3
-rw-r--r--source/blender/editors/include/UI_interface_icons.h18
-rw-r--r--source/blender/editors/include/UI_resources.h99
-rw-r--r--source/blender/editors/include/UI_tree_view.hh195
-rw-r--r--source/blender/editors/include/UI_view2d.h193
-rw-r--r--source/blender/editors/interface/CMakeLists.txt2
-rw-r--r--source/blender/editors/interface/interface.c211
-rw-r--r--source/blender/editors/interface/interface_align.c7
-rw-r--r--source/blender/editors/interface/interface_anim.c5
-rw-r--r--source/blender/editors/interface/interface_button_group.c4
-rw-r--r--source/blender/editors/interface/interface_context_menu.c3
-rw-r--r--source/blender/editors/interface/interface_context_path.cc4
-rw-r--r--source/blender/editors/interface/interface_draw.c20
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c11
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c19
-rw-r--r--source/blender/editors/interface/interface_eyedropper_intern.h18
-rw-r--r--source/blender/editors/interface/interface_handlers.c184
-rw-r--r--source/blender/editors/interface/interface_icons.c25
-rw-r--r--source/blender/editors/interface/interface_intern.h264
-rw-r--r--source/blender/editors/interface/interface_layout.c79
-rw-r--r--source/blender/editors/interface/interface_ops.c138
-rw-r--r--source/blender/editors/interface/interface_panel.c111
-rw-r--r--source/blender/editors/interface/interface_query.c9
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.c3
-rw-r--r--source/blender/editors/interface/interface_region_hud.c1
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.c7
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c8
-rw-r--r--source/blender/editors/interface/interface_region_popover.c7
-rw-r--r--source/blender/editors/interface/interface_region_popup.c8
-rw-r--r--source/blender/editors/interface/interface_region_search.cc29
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c11
-rw-r--r--source/blender/editors/interface/interface_style.c25
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc2
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc2
-rw-r--r--source/blender/editors/interface/interface_template_list.cc8
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.cc (renamed from source/blender/editors/interface/interface_template_search_menu.c)286
-rw-r--r--source/blender/editors/interface/interface_templates.c321
-rw-r--r--source/blender/editors/interface/interface_undo.c11
-rw-r--r--source/blender/editors/interface/interface_utils.c36
-rw-r--r--source/blender/editors/interface/interface_view.cc8
-rw-r--r--source/blender/editors/interface/interface_widgets.c339
-rw-r--r--source/blender/editors/interface/resources.c18
-rw-r--r--source/blender/editors/interface/tree_view.cc292
-rw-r--r--source/blender/editors/interface/view2d.c110
-rw-r--r--source/blender/editors/interface/view2d_gizmo_navigate.c1
-rw-r--r--source/blender/editors/interface/view2d_ops.c3
-rw-r--r--source/blender/editors/lattice/editlattice_tools.c2
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c1
-rw-r--r--source/blender/editors/mask/mask_draw.c58
-rw-r--r--source/blender/editors/mask/mask_editaction.c11
-rw-r--r--source/blender/editors/mask/mask_intern.h12
-rw-r--r--source/blender/editors/mask/mask_ops.c4
-rw-r--r--source/blender/editors/mask/mask_query.c3
-rw-r--r--source/blender/editors/mask/mask_relationships.c1
-rw-r--r--source/blender/editors/mask/mask_select.c1
-rw-r--r--source/blender/editors/mesh/editface.c11
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c1
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c1
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c7
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c1
-rw-r--r--source/blender/editors/mesh/editmesh_select.c41
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c1
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c1
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c53
-rw-r--r--source/blender/editors/mesh/mesh_data.c23
-rw-r--r--source/blender/editors/mesh/mesh_intern.h55
-rw-r--r--source/blender/editors/mesh/mesh_ops.c1
-rw-r--r--source/blender/editors/mesh/meshtools.c30
-rw-r--r--source/blender/editors/metaball/editmball_undo.c1
-rw-r--r--source/blender/editors/metaball/mball_edit.c11
-rw-r--r--source/blender/editors/object/object_add.c27
-rw-r--r--source/blender/editors/object/object_constraint.c11
-rw-r--r--source/blender/editors/object/object_data_transfer.c1
-rw-r--r--source/blender/editors/object/object_edit.c35
-rw-r--r--source/blender/editors/object/object_facemap_ops.c2
-rw-r--r--source/blender/editors/object/object_intern.h34
-rw-r--r--source/blender/editors/object/object_modes.c9
-rw-r--r--source/blender/editors/object/object_modifier.c24
-rw-r--r--source/blender/editors/object/object_relations.c9
-rw-r--r--source/blender/editors/object/object_remesh.cc3
-rw-r--r--source/blender/editors/object/object_select.c31
-rw-r--r--source/blender/editors/object/object_shader_fx.c2
-rw-r--r--source/blender/editors/object/object_utils.c4
-rw-r--r--source/blender/editors/object/object_vgroup.c25
-rw-r--r--source/blender/editors/object/object_volume.c1
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c3
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c1
-rw-r--r--source/blender/editors/physics/physics_intern.h24
-rw-r--r--source/blender/editors/render/render_intern.h9
-rw-r--r--source/blender/editors/render/render_internal.c1
-rw-r--r--source/blender/editors/render/render_preview.c164
-rw-r--r--source/blender/editors/render/render_shading.c4
-rw-r--r--source/blender/editors/render/render_update.c3
-rw-r--r--source/blender/editors/render/render_view.c1
-rw-r--r--source/blender/editors/scene/scene_edit.c5
-rw-r--r--source/blender/editors/screen/area.c79
-rw-r--r--source/blender/editors/screen/area_query.c11
-rw-r--r--source/blender/editors/screen/area_utils.c6
-rw-r--r--source/blender/editors/screen/glutil.c23
-rw-r--r--source/blender/editors/screen/screen_context.c89
-rw-r--r--source/blender/editors/screen/screen_draw.c12
-rw-r--r--source/blender/editors/screen/screen_edit.c86
-rw-r--r--source/blender/editors/screen/screen_geometry.c18
-rw-r--r--source/blender/editors/screen/screen_intern.h65
-rw-r--r--source/blender/editors/screen/screen_ops.c31
-rw-r--r--source/blender/editors/screen/screendump.c5
-rw-r--r--source/blender/editors/screen/workspace_edit.c22
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c13
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c48
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c104
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc188
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c39
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h128
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c11
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c152
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c34
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h156
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c1
-rw-r--r--source/blender/editors/space_action/action_data.c3
-rw-r--r--source/blender/editors/space_action/action_draw.c57
-rw-r--r--source/blender/editors/space_action/action_intern.h7
-rw-r--r--source/blender/editors/space_action/space_action.c10
-rw-r--r--source/blender/editors/space_api/spacetypes.c5
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h6
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c1
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c1
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c8
-rw-r--r--source/blender/editors/space_clip/clip_draw.c1
-rw-r--r--source/blender/editors/space_clip/clip_editor.c11
-rw-r--r--source/blender/editors/space_clip/clip_intern.h16
-rw-r--r--source/blender/editors/space_clip/clip_ops.c15
-rw-r--r--source/blender/editors/space_clip/clip_utils.c3
-rw-r--r--source/blender/editors/space_clip/space_clip.c1
-rw-r--r--source/blender/editors/space_console/space_console.c1
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc205
-rw-r--r--source/blender/editors/space_file/file_draw.c6
-rw-r--r--source/blender/editors/space_file/file_indexer.cc96
-rw-r--r--source/blender/editors/space_file/file_indexer.h (renamed from source/blender/blenkernel/intern/extern_implementations.cc)25
-rw-r--r--source/blender/editors/space_file/file_intern.h58
-rw-r--r--source/blender/editors/space_file/file_ops.c54
-rw-r--r--source/blender/editors/space_file/file_panels.c18
-rw-r--r--source/blender/editors/space_file/file_utils.c3
-rw-r--r--source/blender/editors/space_file/filelist.c468
-rw-r--r--source/blender/editors/space_file/filelist.h48
-rw-r--r--source/blender/editors/space_file/filesel.c58
-rw-r--r--source/blender/editors/space_file/space_file.c14
-rw-r--r--source/blender/editors/space_graph/graph_draw.c21
-rw-r--r--source/blender/editors/space_graph/graph_intern.h50
-rw-r--r--source/blender/editors/space_graph/graph_select.c11
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c306
-rw-r--r--source/blender/editors/space_graph/graph_utils.c17
-rw-r--r--source/blender/editors/space_graph/graph_view.c2
-rw-r--r--source/blender/editors/space_graph/space_graph.c1
-rw-r--r--source/blender/editors/space_image/image_buttons.c1
-rw-r--r--source/blender/editors/space_image/image_draw.c6
-rw-r--r--source/blender/editors/space_image/image_edit.c7
-rw-r--r--source/blender/editors/space_image/image_intern.h12
-rw-r--r--source/blender/editors/space_image/image_ops.c17
-rw-r--r--source/blender/editors/space_image/image_sequence.c1
-rw-r--r--source/blender/editors/space_image/image_undo.c6
-rw-r--r--source/blender/editors/space_image/space_image.c1
-rw-r--r--source/blender/editors/space_info/info_ops.c10
-rw-r--r--source/blender/editors/space_info/info_report.c1
-rw-r--r--source/blender/editors/space_info/info_stats.cc5
-rw-r--r--source/blender/editors/space_info/space_info.c1
-rw-r--r--source/blender/editors/space_info/textview.c7
-rw-r--r--source/blender/editors/space_info/textview.h7
-rw-r--r--source/blender/editors/space_nla/nla_channels.c2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c12
-rw-r--r--source/blender/editors/space_nla/nla_edit.c15
-rw-r--r--source/blender/editors/space_nla/nla_intern.h18
-rw-r--r--source/blender/editors/space_nla/nla_ops.c3
-rw-r--r--source/blender/editors/space_nla/space_nla.c1
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_node/drawnode.cc2061
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc291
-rw-r--r--source/blender/editors/space_node/node_add.cc93
-rw-r--r--source/blender/editors/space_node/node_draw.cc1526
-rw-r--r--source/blender/editors/space_node/node_edit.cc248
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc16
-rw-r--r--source/blender/editors/space_node/node_group.cc197
-rw-r--r--source/blender/editors/space_node/node_intern.hh272
-rw-r--r--source/blender/editors/space_node/node_ops.cc2
-rw-r--r--source/blender/editors/space_node/node_relationships.cc867
-rw-r--r--source/blender/editors/space_node/node_select.cc173
-rw-r--r--source/blender/editors/space_node/node_templates.cc11
-rw-r--r--source/blender/editors/space_node/node_view.cc85
-rw-r--r--source/blender/editors/space_node/space_node.cc71
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c9
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c21
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h110
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c9
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c19
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c34
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.h8
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_orphaned.cc1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_sequencer.cc2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc1
-rw-r--r--source/blender/editors/space_script/space_script.c1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c12
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c53
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h31
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c203
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c76
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc38
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh64
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc38
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh60
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc479
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh28
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc366
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh42
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc118
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh68
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_draw.cc8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_intern.hh9
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc171
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_panels.cc (renamed from source/blender/functions/FN_multi_function_parallel.hh)34
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc413
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc6
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c1
-rw-r--r--source/blender/editors/space_text/space_text.c1
-rw-r--r--source/blender/editors/space_text/text_draw.c10
-rw-r--r--source/blender/editors/space_text/text_format.c13
-rw-r--r--source/blender/editors/space_text/text_format.h21
-rw-r--r--source/blender/editors/space_text/text_intern.h9
-rw-r--r--source/blender/editors/space_text/text_undo.c3
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c56
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c16
-rw-r--r--source/blender/editors/space_view3d/view3d_cursor_snap.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c67
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c25
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h66
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_fly.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c127
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c38
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c161
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c71
-rw-r--r--source/blender/editors/transform/transform.c10
-rw-r--r--source/blender/editors/transform/transform.h43
-rw-r--r--source/blender/editors/transform/transform_constraints.c25
-rw-r--r--source/blender/editors/transform/transform_constraints.h25
-rw-r--r--source/blender/editors/transform/transform_convert.c36
-rw-r--r--source/blender/editors/transform/transform_convert.h82
-rw-r--r--source/blender/editors/transform/transform_convert_action.c1
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c7
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c22
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c10
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c9
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_skin.c1
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c1
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c1
-rw-r--r--source/blender/editors/transform/transform_convert_object.c1
-rw-r--r--source/blender/editors/transform/transform_convert_object_texspace.c3
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c1
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c13
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c1
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c8
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.h9
-rw-r--r--source/blender/editors/transform/transform_generics.c108
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c79
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c3
-rw-r--r--source/blender/editors/transform/transform_mode.c19
-rw-r--r--source/blender/editors/transform/transform_mode.h15
-rw-r--r--source/blender/editors/transform/transform_mode_align.c1
-rw-r--r--source/blender/editors/transform/transform_mode_baketime.c1
-rw-r--r--source/blender/editors/transform/transform_mode_bbone_resize.c2
-rw-r--r--source/blender/editors/transform/transform_mode_bend.c1
-rw-r--r--source/blender/editors/transform/transform_mode_boneenvelope.c2
-rw-r--r--source/blender/editors/transform/transform_mode_boneroll.c3
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_bevelweight.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c2
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c3
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c3
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c3
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_mirror.c1
-rw-r--r--source/blender/editors/transform/transform_mode_push_pull.c3
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c1
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c1
-rw-r--r--source/blender/editors/transform/transform_mode_shear.c3
-rw-r--r--source/blender/editors/transform/transform_mode_shrink_fatten.c3
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c2
-rw-r--r--source/blender/editors/transform/transform_mode_tilt.c3
-rw-r--r--source/blender/editors/transform/transform_mode_timescale.c1
-rw-r--r--source/blender/editors/transform/transform_mode_timeslide.c1
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c1
-rw-r--r--source/blender/editors/transform/transform_mode_tosphere.c3
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c1
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c1
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c3
-rw-r--r--source/blender/editors/transform/transform_orientations.c17
-rw-r--r--source/blender/editors/transform/transform_orientations.h13
-rw-r--r--source/blender/editors/transform/transform_snap.c49
-rw-r--r--source/blender/editors/transform/transform_snap.h12
-rw-r--r--source/blender/editors/transform/transform_snap_animation.c9
-rw-r--r--source/blender/editors/transform/transform_snap_object.c160
-rw-r--r--source/blender/editors/undo/ed_undo.c146
-rw-r--r--source/blender/editors/undo/memfile_undo.c58
-rw-r--r--source/blender/editors/undo/undo_intern.h2
-rw-r--r--source/blender/editors/util/ed_draw.c15
-rw-r--r--source/blender/editors/util/ed_util.c20
-rw-r--r--source/blender/editors/util/ed_util_ops.cc4
-rw-r--r--source/blender/editors/util/gizmo_utils.c1
-rw-r--r--source/blender/editors/util/numinput.c4
-rw-r--r--source/blender/editors/util/select_utils.c10
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h13
-rw-r--r--source/blender/editors/uvedit/uvedit_islands.c3
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c1
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c17
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c2
-rw-r--r--source/blender/freestyle/FRS_freestyle.h4
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp4
-rw-r--r--source/blender/freestyle/intern/image/GaussianFilter.h14
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h2
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h2
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp66
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.h63
-rw-r--r--source/blender/functions/CMakeLists.txt5
-rw-r--r--source/blender/functions/FN_cpp_type.hh12
-rw-r--r--source/blender/functions/FN_field.hh161
-rw-r--r--source/blender/functions/FN_field_cpp_type.hh95
-rw-r--r--source/blender/functions/FN_generic_span.hh10
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh62
-rw-r--r--source/blender/functions/FN_multi_function.hh36
-rw-r--r--source/blender/functions/FN_multi_function_builder.hh34
-rw-r--r--source/blender/functions/FN_multi_function_params.hh29
-rw-r--r--source/blender/functions/FN_multi_function_procedure_executor.hh5
-rw-r--r--source/blender/functions/FN_multi_function_procedure_optimization.hh61
-rw-r--r--source/blender/functions/FN_multi_function_signature.hh47
-rw-r--r--source/blender/functions/intern/field.cc184
-rw-r--r--source/blender/functions/intern/generic_virtual_array.cc180
-rw-r--r--source/blender/functions/intern/multi_function.cc132
-rw-r--r--source/blender/functions/intern/multi_function_builder.cc36
-rw-r--r--source/blender/functions/intern/multi_function_parallel.cc93
-rw-r--r--source/blender/functions/intern/multi_function_params.cc44
-rw-r--r--source/blender/functions/intern/multi_function_procedure.cc2
-rw-r--r--source/blender/functions/intern/multi_function_procedure_executor.cc141
-rw-r--r--source/blender/functions/intern/multi_function_procedure_optimization.cc90
-rw-r--r--source/blender/functions/tests/FN_field_test.cc12
-rw-r--r--source/blender/functions/tests/FN_multi_function_procedure_test.cc14
-rw-r--r--source/blender/functions/tests/FN_multi_function_test.cc2
-rw-r--r--source/blender/geometry/CMakeLists.txt3
-rw-r--r--source/blender/geometry/GEO_mesh_to_curve.hh5
-rw-r--r--source/blender/geometry/GEO_realize_instances.hh52
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc5
-rw-r--r--source/blender/geometry/intern/realize_instances.cc1347
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_lineart.h1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c16
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h12
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillength.c107
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c350
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h28
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c12
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c36
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c4
-rw-r--r--source/blender/gpu/GPU_batch.h37
-rw-r--r--source/blender/gpu/GPU_batch_presets.h6
-rw-r--r--source/blender/gpu/GPU_batch_utils.h16
-rw-r--r--source/blender/gpu/GPU_buffers.h47
-rw-r--r--source/blender/gpu/GPU_capabilities.h3
-rw-r--r--source/blender/gpu/GPU_context.h6
-rw-r--r--source/blender/gpu/GPU_debug.h7
-rw-r--r--source/blender/gpu/GPU_framebuffer.h29
-rw-r--r--source/blender/gpu/GPU_immediate.h29
-rw-r--r--source/blender/gpu/GPU_immediate_util.h89
-rw-r--r--source/blender/gpu/GPU_material.h22
-rw-r--r--source/blender/gpu/GPU_matrix.h33
-rw-r--r--source/blender/gpu/GPU_platform.h3
-rw-r--r--source/blender/gpu/GPU_select.h33
-rw-r--r--source/blender/gpu/GPU_shader.h26
-rw-r--r--source/blender/gpu/GPU_state.h24
-rw-r--r--source/blender/gpu/GPU_texture.h44
-rw-r--r--source/blender/gpu/GPU_uniform_buffer.h6
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h48
-rw-r--r--source/blender/gpu/GPU_vertex_format.h35
-rw-r--r--source/blender/gpu/GPU_viewport.h26
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc14
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c2
-rw-r--r--source/blender/gpu/intern/gpu_batch_utils.c9
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c12
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc47
-rw-r--r--source/blender/gpu/intern/gpu_context.cc10
-rw-r--r--source/blender/gpu/intern/gpu_debug.cc7
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc43
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc2
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c126
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc2
-rw-r--r--source/blender/gpu/intern/gpu_material.c13
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc26
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c2
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h9
-rw-r--r--source/blender/gpu/intern/gpu_platform.cc11
-rw-r--r--source/blender/gpu/intern/gpu_select.c23
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_private.h5
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc2
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc22
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc9
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh4
-rw-r--r--source/blender/gpu/intern/gpu_state.cc11
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc14
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer.cc8
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc13
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc27
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c29
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc12
-rw-r--r--source/blender/gpu/opengl/gl_batch.cc5
-rw-r--r--source/blender/gpu/opengl/gl_batch.hh19
-rw-r--r--source/blender/gpu/opengl/gl_context.hh6
-rw-r--r--source/blender/gpu/opengl/gl_debug.cc1
-rw-r--r--source/blender/gpu/opengl/gl_debug.hh8
-rw-r--r--source/blender/gpu/opengl/gl_debug_layer.cc5
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.cc2
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.cc4
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.hh6
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc2
-rw-r--r--source/blender/gpu/opengl/gl_shader.hh6
-rw-r--r--source/blender/gpu/opengl/gl_state.cc2
-rw-r--r--source/blender/gpu/opengl/gl_state.hh6
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc22
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh19
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc2
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.hh6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl147
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl3
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp9
-rw-r--r--source/blender/imbuf/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h198
-rw-r--r--source/blender/imbuf/IMB_imbuf.h239
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h29
-rw-r--r--source/blender/imbuf/IMB_moviecache.h3
-rw-r--r--source/blender/imbuf/IMB_thumbs.h39
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h107
-rw-r--r--source/blender/imbuf/intern/IMB_filter.h3
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c15
-rw-r--r--source/blender/imbuf/intern/bmp.c1
-rw-r--r--source/blender/imbuf/intern/cache.c2
-rw-r--r--source/blender/imbuf/intern/colormanagement.c59
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c12
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.cpp18
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h18
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.cpp5
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h5
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp2
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h7
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.cpp1
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.h6
-rw-r--r--source/blender/imbuf/intern/divers.c27
-rw-r--r--source/blender/imbuf/intern/filter.c8
-rw-r--r--source/blender/imbuf/intern/imageprocess.c186
-rw-r--r--source/blender/imbuf/intern/iris.c6
-rw-r--r--source/blender/imbuf/intern/moviecache.c2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp23
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h4
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h27
-rw-r--r--source/blender/imbuf/intern/rectop.c35
-rw-r--r--source/blender/imbuf/intern/scaling.c11
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c2
-rw-r--r--source/blender/imbuf/intern/thumbs.c3
-rw-r--r--source/blender/imbuf/intern/tiff.c24
-rw-r--r--source/blender/imbuf/intern/transform.cc604
-rw-r--r--source/blender/imbuf/intern/util.c2
-rw-r--r--source/blender/imbuf/intern/util_gpu.c5
-rw-r--r--source/blender/io/alembic/exporter/abc_archive.cc2
-rw-r--r--source/blender/io/alembic/exporter/abc_subdiv_disabler.cc2
-rw-r--r--source/blender/io/alembic/exporter/abc_subdiv_disabler.h4
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_points.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_axis_conversion.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_axis_conversion.h17
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc26
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.h8
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.cc6
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.h7
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.cc1
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.h1
-rw-r--r--source/blender/io/alembic/intern/abc_util.cc9
-rw-r--r--source/blender/io/alembic/intern/abc_util.h9
-rw-r--r--source/blender/io/collada/AnimationExporter.cpp27
-rw-r--r--source/blender/io/collada/AnimationExporter.h48
-rw-r--r--source/blender/io/collada/AnimationImporter.cpp29
-rw-r--r--source/blender/io/collada/AnimationImporter.h56
-rw-r--r--source/blender/io/collada/ArmatureExporter.cpp2
-rw-r--r--source/blender/io/collada/ArmatureExporter.h8
-rw-r--r--source/blender/io/collada/ArmatureImporter.cpp13
-rw-r--r--source/blender/io/collada/ArmatureImporter.h17
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp11
-rw-r--r--source/blender/io/collada/BCAnimationSampler.h14
-rw-r--r--source/blender/io/collada/BCMath.cpp2
-rw-r--r--source/blender/io/collada/BCMath.h4
-rw-r--r--source/blender/io/collada/BCSampleData.cpp1
-rw-r--r--source/blender/io/collada/BCSampleData.h1
-rw-r--r--source/blender/io/collada/BlenderContext.cpp6
-rw-r--r--source/blender/io/collada/BlenderContext.h6
-rw-r--r--source/blender/io/collada/ControllerExporter.cpp3
-rw-r--r--source/blender/io/collada/ControllerExporter.h6
-rw-r--r--source/blender/io/collada/DocumentImporter.cpp58
-rw-r--r--source/blender/io/collada/DocumentImporter.h60
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp4
-rw-r--r--source/blender/io/collada/GeometryExporter.h8
-rw-r--r--source/blender/io/collada/Materials.cpp1
-rw-r--r--source/blender/io/collada/Materials.h1
-rw-r--r--source/blender/io/collada/MeshImporter.cpp69
-rw-r--r--source/blender/io/collada/MeshImporter.h70
-rw-r--r--source/blender/io/collada/SkinInfo.cpp14
-rw-r--r--source/blender/io/collada/SkinInfo.h26
-rw-r--r--source/blender/io/collada/collada_internal.cpp1
-rw-r--r--source/blender/io/collada/collada_internal.h1
-rw-r--r--source/blender/io/collada/collada_utils.cpp68
-rw-r--r--source/blender/io/collada/collada_utils.h61
-rw-r--r--source/blender/io/gpencil/gpencil_io.h6
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.cc10
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.hh10
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_capi.cc2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc11
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh15
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.cc37
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.hh41
-rw-r--r--source/blender/io/usd/intern/usd_capi_export.cc2
-rw-r--r--source/blender/io/usd/intern/usd_reader_curve.cc6
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.cc10
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.h16
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc1
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.h1
-rw-r--r--source/blender/io/usd/intern/usd_reader_nurbs.cc4
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.cc10
-rw-r--r--source/blender/io/usd/intern/usd_reader_stage.h14
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.cc3
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.h14
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_action_types.h8
-rw-r--r--source/blender/makesdna/DNA_curve_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_curve_types.h13
-rw-r--r--source/blender/makesdna/DNA_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_effect_types.h2
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h2
-rw-r--r--source/blender/makesdna/DNA_genfile.h64
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h26
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h66
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h257
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h26
-rw-r--r--source/blender/makesdna/DNA_meta_types.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h10
-rw-r--r--source/blender/makesdna/DNA_node_types.h58
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h6
-rw-r--r--source/blender/makesdna/DNA_pointcache_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_screen_types.h6
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h6
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c8
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c57
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h30
-rw-r--r--source/blender/makesdna/intern/dna_utils.c32
-rw-r--r--source/blender/makesdna/intern/dna_utils.h17
-rw-r--r--source/blender/makesrna/RNA_access.h258
-rw-r--r--source/blender/makesrna/RNA_define.h52
-rw-r--r--source/blender/makesrna/RNA_enum_items.h6
-rw-r--r--source/blender/makesrna/RNA_enum_types.h6
-rw-r--r--source/blender/makesrna/intern/rna_access.c207
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c64
-rw-r--r--source/blender/makesrna/intern/rna_access_internal.h7
-rw-r--r--source/blender/makesrna/intern/rna_action.c114
-rw-r--r--source/blender/makesrna/intern/rna_armature.c4
-rw-r--r--source/blender/makesrna/intern/rna_asset.c5
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c3
-rw-r--r--source/blender/makesrna/intern/rna_curve.c12
-rw-r--r--source/blender/makesrna/intern/rna_define.c36
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c259
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c49
-rw-r--r--source/blender/makesrna/intern/rna_internal.h17
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c12
-rw-r--r--source/blender/makesrna/intern/rna_main.c11
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c80
-rw-r--r--source/blender/makesrna/intern/rna_nla.c4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c262
-rw-r--r--source/blender/makesrna/intern/rna_pose.c1
-rw-r--r--source/blender/makesrna/intern/rna_rna.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c5
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c3
-rw-r--r--source/blender/makesrna/intern/rna_space.c62
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_wm.c5
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h4
-rw-r--r--source/blender/modifiers/MOD_nodes.h5
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c10
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc73
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc414
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c1
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c14
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c19
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.h15
-rw-r--r--source/blender/modifiers/intern/MOD_util.c6
-rw-r--r--source/blender/modifiers/intern/MOD_util.h6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c21
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.h30
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c4
-rw-r--r--source/blender/nodes/CMakeLists.txt105
-rw-r--r--source/blender/nodes/NOD_common.h4
-rw-r--r--source/blender/nodes/NOD_derived_node_tree.hh42
-rw-r--r--source/blender/nodes/NOD_function.h2
-rw-r--r--source/blender/nodes/NOD_geometry.h16
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh56
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh33
-rw-r--r--source/blender/nodes/NOD_math_functions.hh10
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh77
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh7
-rw-r--r--source/blender/nodes/NOD_socket_declarations.hh68
-rw-r--r--source/blender/nodes/NOD_socket_declarations_geometry.hh7
-rw-r--r--source/blender/nodes/NOD_socket_search_link.hh151
-rw-r--r--source/blender/nodes/NOD_static_types.h16
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc14
-rw-r--r--source/blender/nodes/composite/node_composite_util.cc5
-rw-r--r--source/blender/nodes/composite/node_composite_util.hh5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_alphaOver.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_antialiasing.cc30
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.cc67
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehimage.cc21
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_boxmask.cc40
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.cc13
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channelMatte.cc70
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc47
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorMatte.cc48
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorSpill.cc75
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.cc86
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc223
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.cc7
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_composite.cc12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cornerpin.cc46
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_crop.cc49
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc14
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_defocus.cc73
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.cc47
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_despeckle.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diffMatte.cc41
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.cc43
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_displace.cc33
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc48
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc51
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_exposure.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_filter.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_flip.cc30
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.cc65
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_idMask.cc12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.cc68
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_inpaint.cc25
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.cc15
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keying.cc56
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc51
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lensdist.cc44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapRange.cc46
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapUV.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapValue.cc49
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mask.cc43
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.cc29
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mixrgb.cc27
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_movieclip.cc52
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc55
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normal.cc31
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normalize.cc17
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.cc168
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc16
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc75
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_posterize.cc25
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_premulkey.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rgb.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rotate.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.cc45
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_setalpha.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_splitViewer.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc51
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sunbeams.cc36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switch.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.cc22
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_texture.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_tonemap.cc30
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.cc56
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_transform.cc45
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_translate.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_valToRgb.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_value.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_vecBlur.cc46
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.cc31
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_zcombine.cc46
-rw-r--r--source/blender/nodes/function/node_function_util.cc5
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc7
-rw-r--r--source/blender/nodes/function/nodes/node_fn_compare.cc540
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc121
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc7
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc67
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt97
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc11
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc37
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc)42
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc)44
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc)24
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc)35
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc)94
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc)32
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc)36
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc)22
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc)126
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc)46
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc)20
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc)32
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc)37
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc)32
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc)28
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc)30
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc)16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc (renamed from source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc)26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc96
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc155
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc172
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_common.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc94
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc77
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc31
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc49
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc43
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc81
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc68
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc33
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc)127
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc67
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc88
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc81
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc342
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc847
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc55
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_id.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_index.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc93
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc188
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc96
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc158
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc101
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc155
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc59
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_position.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_radius.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc111
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc40
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc130
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc72
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc361
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_replace.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc183
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc106
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc66
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc140
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc41
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc56
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc88
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc54
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material.cc58
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc122
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_join.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc44
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc79
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc112
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc82
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc81
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc53
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc18
-rw-r--r--source/blender/nodes/intern/extern_implementations.cc35
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc79
-rw-r--r--source/blender/nodes/intern/math_functions.cc12
-rw-r--r--source/blender/nodes/intern/node_common.cc163
-rw-r--r--source/blender/nodes/intern/node_common.h10
-rw-r--r--source/blender/nodes/intern/node_declaration.cc8
-rw-r--r--source/blender/nodes/intern/node_exec.cc2
-rw-r--r--source/blender/nodes/intern/node_exec.h2
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc19
-rw-r--r--source/blender/nodes/intern/node_socket.cc108
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc184
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc8
-rw-r--r--source/blender/nodes/intern/node_util.c119
-rw-r--r--source/blender/nodes/intern/node_util.h67
-rw-r--r--source/blender/nodes/intern/socket_search_link.cc199
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt166
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c20
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc (renamed from source/blender/nodes/shader/node_shader_util.c)46
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc397
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_mixRgb.cc)4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc (renamed from source/blender/nodes/shader/nodes/node_shader_valToRgb.cc)4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c)0
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc)4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc (renamed from source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc)4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c (renamed from source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c)0
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc23
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc98
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c (renamed from source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c)0
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_transform.c (renamed from source/blender/nodes/shader/nodes/node_shader_vectTransform.c)0
-rw-r--r--source/blender/nodes/texture/node_texture_util.c2
-rw-r--r--source/blender/nodes/texture/node_texture_util.h3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_distance.c1
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_image.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_mixRgb.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c2
-rw-r--r--source/blender/python/BPY_extern.h36
-rw-r--r--source/blender/python/BPY_extern_python.h2
-rw-r--r--source/blender/python/BPY_extern_run.h130
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c3
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.h3
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c15
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h17
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c7
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.h15
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c1
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.h1
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c3
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.h3
-rw-r--r--source/blender/python/generic/bgl.c7
-rw-r--r--source/blender/python/generic/bgl.h9
-rw-r--r--source/blender/python/generic/bpy_threads.c2
-rw-r--r--source/blender/python/generic/idprop_py_api.c9
-rw-r--r--source/blender/python/generic/idprop_py_api.h9
-rw-r--r--source/blender/python/generic/py_capi_rna.c24
-rw-r--r--source/blender/python/generic/py_capi_rna.h24
-rw-r--r--source/blender/python/generic/py_capi_utils.c72
-rw-r--r--source/blender/python/generic/py_capi_utils.h86
-rw-r--r--source/blender/python/generic/python_utildefines.h12
-rw-r--r--source/blender/python/gpu/gpu_py.c1
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.c7
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.h7
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c21
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.h4
-rw-r--r--source/blender/python/gpu/gpu_py_select.c1
-rw-r--r--source/blender/python/gpu/gpu_py_texture.c1
-rw-r--r--source/blender/python/intern/bpy.c27
-rw-r--r--source/blender/python/intern/bpy.h2
-rw-r--r--source/blender/python/intern/bpy_app_translations.c4
-rw-r--r--source/blender/python/intern/bpy_capi_utils.c3
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h6
-rw-r--r--source/blender/python/intern/bpy_driver.c42
-rw-r--r--source/blender/python/intern/bpy_driver.h8
-rw-r--r--source/blender/python/intern/bpy_interface.c23
-rw-r--r--source/blender/python/intern/bpy_interface_run.c32
-rw-r--r--source/blender/python/intern/bpy_library_load.c249
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c8
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.h8
-rw-r--r--source/blender/python/intern/bpy_props.c18
-rw-r--r--source/blender/python/intern/bpy_props.h4
-rw-r--r--source/blender/python/intern/bpy_rna.c16
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/intern/bpy_rna_array.c3
-rw-r--r--source/blender/python/intern/bpy_rna_data.c2
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c3
-rw-r--r--source/blender/python/intern/bpy_rna_driver.h3
-rw-r--r--source/blender/python/mathutils/mathutils.c17
-rw-r--r--source/blender/python/mathutils/mathutils.h40
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c3
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h3
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c23
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h12
-rw-r--r--source/blender/render/RE_bake.h4
-rw-r--r--source/blender/render/RE_engine.h4
-rw-r--r--source/blender/render/RE_pipeline.h145
-rw-r--r--source/blender/render/RE_texture.h55
-rw-r--r--source/blender/render/intern/bake.c4
-rw-r--r--source/blender/render/intern/engine.c1
-rw-r--r--source/blender/render/intern/initrender.c8
-rw-r--r--source/blender/render/intern/pipeline.c38
-rw-r--r--source/blender/render/intern/pipeline.h4
-rw-r--r--source/blender/render/intern/render_result.c19
-rw-r--r--source/blender/render/intern/render_result.h37
-rw-r--r--source/blender/render/intern/texture_pointdensity.c3
-rw-r--r--source/blender/render/intern/texture_procedural.c21
-rw-r--r--source/blender/render/intern/zbuf.c4
-rw-r--r--source/blender/render/intern/zbuf.h7
-rw-r--r--source/blender/sequencer/SEQ_add.h99
-rw-r--r--source/blender/sequencer/SEQ_clipboard.h7
-rw-r--r--source/blender/sequencer/SEQ_edit.h44
-rw-r--r--source/blender/sequencer/SEQ_iterator.h154
-rw-r--r--source/blender/sequencer/SEQ_prefetch.h4
-rw-r--r--source/blender/sequencer/SEQ_relations.h22
-rw-r--r--source/blender/sequencer/SEQ_render.h18
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h64
-rw-r--r--source/blender/sequencer/SEQ_time.h28
-rw-r--r--source/blender/sequencer/SEQ_transform.h47
-rw-r--r--source/blender/sequencer/SEQ_utils.h21
-rw-r--r--source/blender/sequencer/intern/clipboard.c7
-rw-r--r--source/blender/sequencer/intern/disk_cache.c2
-rw-r--r--source/blender/sequencer/intern/effects.c3
-rw-r--r--source/blender/sequencer/intern/effects.h7
-rw-r--r--source/blender/sequencer/intern/image_cache.c3
-rw-r--r--source/blender/sequencer/intern/image_cache.h4
-rw-r--r--source/blender/sequencer/intern/iterator.c161
-rw-r--r--source/blender/sequencer/intern/modifier.c1
-rw-r--r--source/blender/sequencer/intern/multiview.c1
-rw-r--r--source/blender/sequencer/intern/multiview.h3
-rw-r--r--source/blender/sequencer/intern/prefetch.c6
-rw-r--r--source/blender/sequencer/intern/prefetch.h9
-rw-r--r--source/blender/sequencer/intern/proxy.c21
-rw-r--r--source/blender/sequencer/intern/render.c49
-rw-r--r--source/blender/sequencer/intern/sequence_lookup.c21
-rw-r--r--source/blender/sequencer/intern/sequencer.c42
-rw-r--r--source/blender/sequencer/intern/sequencer.h4
-rw-r--r--source/blender/sequencer/intern/strip_add.c100
-rw-r--r--source/blender/sequencer/intern/strip_edit.c38
-rw-r--r--source/blender/sequencer/intern/strip_relations.c31
-rw-r--r--source/blender/sequencer/intern/strip_time.c36
-rw-r--r--source/blender/sequencer/intern/strip_time.h9
-rw-r--r--source/blender/sequencer/intern/strip_transform.c46
-rw-r--r--source/blender/sequencer/intern/utils.c23
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.c17
-rw-r--r--source/blender/shader_fx/intern/FX_ui_common.h15
-rw-r--r--source/blender/simulation/intern/ConstrainedConjugateGradient.h6
-rw-r--r--source/blender/simulation/intern/hair_volume.cpp6
-rw-r--r--source/blender/simulation/intern/implicit.h65
-rw-r--r--source/blender/simulation/intern/implicit_blender.c16
-rw-r--r--source/blender/windowmanager/WM_api.h613
-rw-r--r--source/blender/windowmanager/WM_keymap.h32
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h21
-rw-r--r--source/blender/windowmanager/WM_types.h6
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h121
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c45
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c30
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c6
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h20
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c35
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c7
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c5
-rw-r--r--source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h42
-rw-r--r--source/blender/windowmanager/intern/wm.c17
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c8
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c43
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c1
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c24
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c102
-rw-r--r--source/blender/windowmanager/intern/wm_files.c166
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c1262
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c3
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c23
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c25
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c18
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c13
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c5
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c53
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c33
-rw-r--r--source/blender/windowmanager/intern/wm_operator_utils.c7
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c73
-rw-r--r--source/blender/windowmanager/intern/wm_panel_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c4
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c1
-rw-r--r--source/blender/windowmanager/intern/wm_surface.c18
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c19
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c16
-rw-r--r--source/blender/windowmanager/intern/wm_window.c100
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus.c13
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h3
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c10
-rw-r--r--source/blender/windowmanager/message_bus/wm_message_bus.h12
-rw-r--r--source/blender/windowmanager/wm.h53
-rw-r--r--source/blender/windowmanager/wm_event_system.h41
-rw-r--r--source/blender/windowmanager/wm_event_types.h2
-rw-r--r--source/blender/windowmanager/wm_files.h23
-rw-r--r--source/blender/windowmanager/wm_surface.h5
-rw-r--r--source/blender/windowmanager/wm_window.h63
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_actionmap.c45
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c6
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h12
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c2
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c47
1991 files changed, 57549 insertions, 38505 deletions
diff --git a/source/blender/blendthumb/src/blendthumb.hh b/source/blender/blendthumb/src/blendthumb.hh
index c029a1766d6..0bcb160519e 100644
--- a/source/blender/blendthumb/src/blendthumb.hh
+++ b/source/blender/blendthumb/src/blendthumb.hh
@@ -53,6 +53,10 @@ enum eThumbStatus {
std::optional<blender::Vector<uint8_t>> blendthumb_create_png_data_from_thumb(
const Thumbnail *thumb);
+/**
+ * This function extracts the thumbnail from the .blend file into thumb.
+ * Returns #BT_OK for success and the relevant error code otherwise.
+ */
eThumbStatus blendthumb_create_thumb_from_file(struct FileReader *rawfile, Thumbnail *thumb);
/* INTEGER CODES */
diff --git a/source/blender/blendthumb/src/blendthumb_extract.cc b/source/blender/blendthumb/src/blendthumb_extract.cc
index f1c5567bab5..2d14a88c904 100644
--- a/source/blender/blendthumb/src/blendthumb_extract.cc
+++ b/source/blender/blendthumb/src/blendthumb_extract.cc
@@ -179,10 +179,6 @@ static eThumbStatus blendthumb_extract_from_file_impl(FileReader *file,
return BT_INVALID_THUMB;
}
-/**
- * This function extracts the thumbnail from the .blend file into thumb.
- * Returns #BT_OK for success and the relevant error code otherwise.
- */
eThumbStatus blendthumb_create_thumb_from_file(FileReader *rawfile, Thumbnail *thumb)
{
/* Read header in order to identify file type. */
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index fa8e764139d..bd1fa4ce4e5 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -43,9 +43,14 @@ void BLF_exit(void);
void BLF_cache_clear(void);
+/**
+ * Optional cache flushing function, called before #blf_batch_draw.
+ */
void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void));
-/* Loads a font, or returns an already loaded font and increments its reference count. */
+/**
+ * Loads a font, or returns an already loaded font and increments its reference count.
+ */
int BLF_load(const char *name) ATTR_NONNULL();
int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
@@ -57,17 +62,22 @@ void BLF_unload_id(int fontid);
char *BLF_display_name_from_file(const char *filename);
-/* Check if font supports a particular glyph. */
+/**
+ * Check if font supports a particular glyph.
+ */
bool BLF_has_glyph(int fontid, unsigned int unicode);
-/* Attach a file with metrics information from memory. */
+/**
+ * Attach a file with metrics information from memory.
+ */
void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size);
void BLF_aspect(int fontid, float x, float y, float z);
void BLF_position(int fontid, float x, float y, float z);
void BLF_size(int fontid, float size, int dpi);
-/* goal: small but useful color API */
+/* Goal: small but useful color API. */
+
void BLF_color4ubv(int fontid, const unsigned char rgba[4]);
void BLF_color3ubv(int fontid, const unsigned char rgb[3]);
void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha);
@@ -80,26 +90,32 @@ void BLF_color3f(int fontid, float r, float g, float b);
void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha);
/* Also available: `UI_FontThemeColor(fontid, colorid)`. */
-/* Set a 4x4 matrix to be multiplied before draw the text.
+/**
+ * Set a 4x4 matrix to be multiplied before draw the text.
* Remember that you need call BLF_enable(BLF_MATRIX)
* to enable this.
*
* The order of the matrix is like GL:
- *
+ * \code{.unparsed}
* | m[0] m[4] m[8] m[12] |
* | m[1] m[5] m[9] m[13] |
* | m[2] m[6] m[10] m[14] |
* | m[3] m[7] m[11] m[15] |
+ * \endcode
*/
void BLF_matrix(int fontid, const float m[16]);
-/* Batch draw-calls together as long as
- * the model-view matrix and the font remain unchanged. */
+/**
+ * Batch draw-calls together as long as
+ * the model-view matrix and the font remain unchanged.
+ */
void BLF_batch_draw_begin(void);
void BLF_batch_draw_flush(void);
void BLF_batch_draw_end(void);
-/* Draw the string using the current font. */
+/**
+ * Draw the string using the current font.
+ */
void BLF_draw_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info)
ATTR_NONNULL(2);
void BLF_draw(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2);
@@ -113,6 +129,14 @@ typedef bool (*BLF_GlyphBoundsFn)(const char *str,
const int glyph_bearing[2],
void *user_data);
+/**
+ * Run \a user_fn for each character, with the bound-box that would be used for drawing.
+ *
+ * \param user_fn: Callback that runs on each glyph, returning false early exits.
+ * \param user_data: User argument passed to \a user_fn.
+ *
+ * \note The font position, clipping, matrix and rotation are not applied.
+ */
void BLF_boundbox_foreach_glyph_ex(int fontid,
const char *str,
size_t str_len,
@@ -125,14 +149,19 @@ void BLF_boundbox_foreach_glyph(int fontid,
BLF_GlyphBoundsFn user_fn,
void *user_data) ATTR_NONNULL(2);
-/* Get the string byte offset that fits within a given width */
+/**
+ * Get the string byte offset that fits within a given width.
+ */
size_t BLF_width_to_strlen(
int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_NONNULL(2);
-/* Same as BLF_width_to_strlen but search from the string end */
+/**
+ * Same as BLF_width_to_strlen but search from the string end.
+ */
size_t BLF_width_to_rstrlen(
int fontid, const char *str, size_t str_len, float width, float *r_width) ATTR_NONNULL(2);
-/* This function return the bounding box of the string
+/**
+ * This function return the bounding box of the string
* and are not multiplied by the aspect.
*/
void BLF_boundbox_ex(int fontid,
@@ -142,7 +171,8 @@ void BLF_boundbox_ex(int fontid,
struct ResultBLF *r_info) ATTR_NONNULL(2);
void BLF_boundbox(int fontid, const char *str, size_t str_len, struct rctf *box) ATTR_NONNULL();
-/* The next both function return the width and height
+/**
+ * The next both function return the width and height
* of the string, using the current font and both value
* are multiplied by the aspect of the font.
*/
@@ -155,24 +185,29 @@ float BLF_height_ex(int fontid, const char *str, size_t str_len, struct ResultBL
float BLF_height(int fontid, const char *str, size_t str_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-/* Return dimensions of the font without any sample text. */
+/**
+ * Return dimensions of the font without any sample text.
+ */
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT;
float BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT;
-/* The following function return the width and height of the string, but
+/**
+ * The following function return the width and height of the string, but
* just in one call, so avoid extra freetype2 stuff.
*/
void BLF_width_and_height(
int fontid, const char *str, size_t str_len, float *r_width, float *r_height) ATTR_NONNULL();
-/* For fixed width fonts only, returns the width of a
+/**
+ * For fixed width fonts only, returns the width of a
* character.
*/
float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT;
-/* By default, rotation and clipping are disable and
+/**
+ * By default, rotation and clipping are disable and
* have to be enable/disable using BLF_enable/disable.
*/
void BLF_rotation(int fontid, float angle);
@@ -186,27 +221,31 @@ void BLF_blur(int fontid, int size);
void BLF_enable(int fontid, int option);
void BLF_disable(int fontid, int option);
-/* Shadow options, level is the blur level, can be 3, 5 or 0 and
- * the other argument are the rgba color.
- * Take care that shadow need to be enable using BLF_enable!!!
+/**
+ * Shadow options, level is the blur level, can be 3, 5 or 0 and
+ * the other argument are the RGBA color.
+ * Take care that shadow need to be enable using #BLF_enable!
*/
void BLF_shadow(int fontid, int level, const float rgba[4]) ATTR_NONNULL(3);
-/* Set the offset for shadow text, this is the current cursor
+/**
+ * Set the offset for shadow text, this is the current cursor
* position plus this offset, don't need call BLF_position before
* this function, the current position is calculate only on
* BLF_draw, so it's safe call this whenever you like.
*/
void BLF_shadow_offset(int fontid, int x, int y);
-/* Set the buffer, size and number of channels to draw, one thing to take care is call
+/**
+ * Set the buffer, size and number of channels to draw, one thing to take care is call
* this function with NULL pointer when we finish, for example:
+ * \code{.c}
+ * BLF_buffer(my_fbuf, my_cbuf, 100, 100, 4, true, NULL);
*
- * BLF_buffer(my_fbuf, my_cbuf, 100, 100, 4, true, NULL);
+ * ... set color, position and draw ...
*
- * ... set color, position and draw ...
- *
- * BLF_buffer(NULL, NULL, NULL, 0, 0, false, NULL);
+ * BLF_buffer(NULL, NULL, NULL, 0, 0, false, NULL);
+ * \endcode
*/
void BLF_buffer(int fontid,
float *fbuf,
@@ -216,29 +255,46 @@ void BLF_buffer(int fontid,
int nch,
struct ColorManagedDisplay *display);
-/* Set the color to be used for text. */
+/**
+ * Set the color to be used for text.
+ */
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2);
-/* Draw the string into the buffer, this function draw in both buffer,
+/**
+ * Draw the string into the buffer, this function draw in both buffer,
* float and unsigned char _BUT_ it's not necessary set both buffer, NULL is valid here.
*/
void BLF_draw_buffer_ex(int fontid, const char *str, size_t str_len, struct ResultBLF *r_info)
ATTR_NONNULL(2);
void BLF_draw_buffer(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2);
-/* Add a path to the font dir paths. */
+/**
+ * Add a path to the font dir paths.
+ */
void BLF_dir_add(const char *path) ATTR_NONNULL();
-/* Remove a path from the font dir paths. */
+/**
+ * Remove a path from the font dir paths.
+ */
void BLF_dir_rem(const char *path) ATTR_NONNULL();
-/* Return an array with all the font dir (this can be used for filesel) */
+/**
+ * Return an array with all the font dir (this can be used for file-selector).
+ */
char **BLF_dir_get(int *ndir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Free the data return by BLF_dir_get. */
+/**
+ * Free the data return by #BLF_dir_get.
+ */
void BLF_dir_free(char **dirs, int count) ATTR_NONNULL();
/* blf_thumbs.c */
+
+/**
+ * This function is used for generating thumbnail previews.
+ *
+ * \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
+ */
void BLF_thumb_preview(const char *filename,
const char **draw_str,
const char **i18n_draw_str,
@@ -251,16 +307,25 @@ void BLF_thumb_preview(const char *filename,
int channels) ATTR_NONNULL();
/* blf_default.c */
+
void BLF_default_dpi(int dpi);
void BLF_default_size(int size);
void BLF_default_set(int fontid);
-int BLF_default(void); /* get default font ID so we can pass it to other functions */
-/* Draw the string using the default font, size and dpi. */
+/**
+ * Get default font ID so we can pass it to other functions.
+ */
+int BLF_default(void);
+/**
+ * Draw the string using the default font, size and DPI.
+ */
void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL();
-/* Set size and DPI, and return default font ID. */
+/**
+ * Set size and DPI, and return default font ID.
+ */
int BLF_set_default(void);
/* blf_font_default.c */
+
int BLF_load_default(const bool unique);
int BLF_load_mono_default(const bool unique);
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index d6773916abd..c69a0b1eb73 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -66,7 +66,8 @@
/* Font array. */
static FontBLF *global_font[BLF_MAX_FONT] = {NULL};
-/* XXX, should these be made into global_font_'s too? */
+/* XXX: should these be made into global_font_'s too? */
+
int blf_mono_font = -1;
int blf_mono_font_render = -1;
@@ -568,14 +569,6 @@ int BLF_draw_mono(int fontid, const char *str, const size_t str_len, int cwidth)
return columns;
}
-/**
- * Run \a user_fn for each character, with the bound-box that would be used for drawing.
- *
- * \param user_fn: Callback that runs on each glyph, returning false early exits.
- * \param user_data: User argument passed to \a user_fn.
- *
- * \note The font position, clipping, matrix and rotation are not applied.
- */
void BLF_boundbox_foreach_glyph_ex(int fontid,
const char *str,
size_t str_len,
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index f4a20faf109..8eb148a8a9a 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -148,10 +148,6 @@ char *blf_dir_search(const char *file)
return s;
}
-/**
- * Some font have additional file with metrics information,
- * in general, the extension of the file is: `.afm` or `.pfm`
- */
char *blf_dir_metrics_search(const char *filename)
{
char *mfile;
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index c81d18ba7de..14d3a208f69 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -63,6 +63,7 @@
#endif
/* Batching buffer for drawing. */
+
BatchBLF g_batch;
/* freetype2 handle ONLY for this file! */
@@ -394,7 +395,6 @@ void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct
blf_glyph_cache_release(font);
}
-/* use fixed column width, but an utf8 character may occupy multiple columns */
int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth)
{
GlyphBLF *g;
@@ -1168,9 +1168,6 @@ void blf_font_exit(void)
blf_batch_draw_exit();
}
-/**
- * Optional cache flushing function, called before #blf_batch_draw.
- */
void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void))
{
blf_draw_cache_flush = cache_flush_fn;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 5f14ef433e9..4f25f99b65c 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -73,9 +73,6 @@ static FT_Fixed to_16dot16(double val)
/** \name Glyph Cache
* \{ */
-/**
- * Find a glyph cache that matches a size, DPI & styles.
- */
GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi)
{
GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first;
@@ -89,9 +86,6 @@ GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi)
return NULL;
}
-/**
- * Create a new glyph cache for the current size, DPI & styles.
- */
GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
{
GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new");
@@ -451,9 +445,6 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
return NULL;
}
-/**
- * Create (or load from cache) a fully-rendered bitmap glyph.
- */
GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
{
GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode);
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index cec20995dc6..02e4a896a31 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -37,6 +37,10 @@ unsigned int blf_next_p2(unsigned int x);
unsigned int blf_hash(unsigned int val);
char *blf_dir_search(const char *file);
+/**
+ * Some font have additional file with metrics information,
+ * in general, the extension of the file is: `.afm` or `.pfm`
+ */
char *blf_dir_metrics_search(const char *filename);
/* int blf_dir_split(const char *str, char *file, int *size); */ /* UNUSED */
@@ -65,6 +69,9 @@ void blf_font_draw_ascii(struct FontBLF *font,
const char *str,
size_t str_len,
struct ResultBLF *r_info);
+/**
+ * Use fixed column width, but an utf8 character may occupy multiple columns.
+ */
int blf_font_draw_mono(struct FontBLF *font, const char *str, size_t str_len, int cwidth);
void blf_font_draw_buffer(struct FontBLF *font,
const char *str,
@@ -130,13 +137,22 @@ int blf_font_count_missing_chars(struct FontBLF *font,
void blf_font_free(struct FontBLF *font);
+/**
+ * Find a glyph cache that matches a size, DPI & styles.
+ */
struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, float size, unsigned int dpi);
+/**
+ * Create a new glyph cache for the current size, DPI & styles.
+ */
struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font);
struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font);
void blf_glyph_cache_release(struct FontBLF *font);
void blf_glyph_cache_clear(struct FontBLF *font);
void blf_glyph_cache_free(struct GlyphCacheBLF *gc);
+/**
+ * Create (or load from cache) a fully-rendered bitmap glyph.
+ */
struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode);
void blf_glyph_free(struct GlyphBLF *g);
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index bbdb26a61b6..06bbd0cf521 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -43,11 +43,6 @@
#include "BLI_strict_flags.h"
-/**
- * This function is used for generating thumbnail previews.
- *
- * \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
- */
void BLF_thumb_preview(const char *filename,
const char **draw_str,
const char **i18n_draw_str,
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index c95190d2c83..0fff6d27031 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -242,8 +242,17 @@ struct DerivedMesh {
void (*release)(DerivedMesh *dm);
};
+/**
+ * Utility function to initialize a #DerivedMesh's function pointers to
+ * the default implementation (for those functions which have a default).
+ */
void DM_init_funcs(DerivedMesh *dm);
+/**
+ * Utility function to initialize a #DerivedMesh for the desired number
+ * of vertices, edges and faces (doesn't allocate memory for them, just
+ * sets up the custom data layers)>
+ */
void DM_init(DerivedMesh *dm,
DerivedMeshType type,
int numVerts,
@@ -252,6 +261,10 @@ void DM_init(DerivedMesh *dm,
int numLoops,
int numPolys);
+/**
+ * Utility function to initialize a DerivedMesh for the desired number
+ * of vertices, edges and faces, with a layer setup copied from source
+ */
void DM_from_template_ex(DerivedMesh *dm,
DerivedMesh *source,
DerivedMeshType type,
@@ -276,43 +289,59 @@ void DM_from_template(DerivedMesh *dm,
*/
bool DM_release(DerivedMesh *dm);
+/**
+ * set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is
+ * zero for the layer type, so only layer types specified by the mask
+ * will be copied
+ */
void DM_set_only_copy(DerivedMesh *dm, const struct CustomData_MeshMasks *mask);
-/* adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
+/* Adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
* backed by an external data array
* alloctype defines how the layer is allocated or copied, and how it is
- * freed, see BKE_customdata.h for the different options
- */
+ * freed, see BKE_customdata.h for the different options. */
+
void DM_add_vert_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_edge_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_tessface_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
void DM_add_poly_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
-/* custom data access functions
- * return pointer to data from first layer which matches type
- * if they return NULL for valid indices, data doesn't exist
- * note these return pointers - any change modifies the internals of the mesh
- */
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Access Functions
+ *
+ * \return pointer to data from first layer which matches type
+ * if they return NULL for valid indices, data doesn't exist.
+ * \note these return pointers - any change modifies the internals of the mesh.
+ * \{ */
+
void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_tessface_data(struct DerivedMesh *dm, int index, int type);
void *DM_get_poly_data(struct DerivedMesh *dm, int index, int type);
-/* custom data layer access functions
- * return pointer to first data layer which matches type (a flat array)
- * if they return NULL, data doesn't exist
- * note these return pointers - any change modifies the internals of the mesh
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Layer Access Functions
+ *
+ * \return pointer to first data layer which matches type (a flat array)
+ * if they return NULL, data doesn't exist.
+ * \note these return pointers - any change modifies the internals of the mesh.
+ * \{ */
+
void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_poly_data_layer(struct DerivedMesh *dm, int type);
void *DM_get_loop_data_layer(struct DerivedMesh *dm, int type);
-/* custom data copy functions
+/** \} */
+
+/**
+ * Custom data copy functions
* copy count elements from source_index in source to dest_index in dest
- * these copy all layers for which the CD_FLAG_NOCOPY flag is not set
+ * these copy all layers for which the CD_FLAG_NOCOPY flag is not set.
*/
void DM_copy_vert_data(struct DerivedMesh *source,
struct DerivedMesh *dest,
@@ -320,13 +349,26 @@ void DM_copy_vert_data(struct DerivedMesh *source,
int dest_index,
int count);
-/* Sets up mpolys for a DM based on face iterators in source. */
+/**
+ * Sets up mpolys for a DM based on face iterators in source.
+ */
void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
void DM_ensure_normals(DerivedMesh *dm);
+/**
+ * Ensure the array is large enough.
+ *
+ * \note This function must always be thread-protected by caller.
+ * It should only be used by internal code.
+ */
void DM_ensure_looptri_data(DerivedMesh *dm);
+/**
+ * Interpolates vertex data from the vertices indexed by `src_indices` in the
+ * source mesh using the given weights and stores the result in the vertex
+ * indexed by `dest_index` in the `dest` mesh.
+ */
void DM_interp_vert_data(struct DerivedMesh *source,
struct DerivedMesh *dest,
int *src_indices,
@@ -336,7 +378,9 @@ void DM_interp_vert_data(struct DerivedMesh *source,
void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
-/* same as above but won't use render settings */
+/**
+ * Same as above but won't use render settings.
+ */
struct Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *,
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 763e540fdd9..ea8ee3f93b1 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -79,50 +79,86 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ALL = (ACT_TRANS_ONLY | ACT_TRANS_PROP),
} eAction_TransformFlags;
-/* Return flags indicating which transforms the given object/posechannel has
+/**
+ * Return flags indicating which transforms the given object/posechannel has
* - if 'curves' is provided, a list of links to these curves are also returned
- * whose nodes WILL NEED FREEING
+ * whose nodes WILL NEED FREEING.
*/
short action_get_item_transforms(struct bAction *act,
struct Object *ob,
struct bPoseChannel *pchan,
ListBase *curves);
-/* Some kind of bounding box operation on the action */
+/**
+ * Calculate the extents of given action.
+ */
void calc_action_range(const struct bAction *act, float *start, float *end, short incl_modifiers);
-/* Does action have any motion data at all? */
+/* Retrieve the intended playback frame range, using the manually set range if available,
+ * or falling back to scanning F-Curves for their first & last frames otherwise. */
+void BKE_action_get_frame_range(const struct bAction *act, float *r_start, float *r_end);
+
+/**
+ * Check if the given action has any keyframes.
+ */
bool action_has_motion(const struct bAction *act);
+/**
+ * Is the action configured as cyclic.
+ */
+bool BKE_action_is_cyclic(const struct bAction *act);
+
/* Action Groups API ----------------- */
-/* Get the active action-group for an Action */
+/**
+ * Get the active action-group for an Action.
+ */
struct bActionGroup *get_active_actiongroup(struct bAction *act);
-/* Make the given Action Group the active one */
+/**
+ * Make the given Action-Group the active one.
+ */
void set_active_action_group(struct bAction *act, struct bActionGroup *agrp, short select);
-/* Sync colors used for action/bone group with theme settings */
+/**
+ * Sync colors used for action/bone group with theme settings.
+ */
void action_group_colors_sync(struct bActionGroup *grp, const struct bActionGroup *ref_grp);
-/* Add a new action group with the given name to the action */
+/**
+ * Add a new action group with the given name to the action>
+ */
struct bActionGroup *action_groups_add_new(struct bAction *act, const char name[]);
-/* Add given channel into (active) group */
+/**
+ * Add given channel into (active) group
+ * - assumes that channel is not linked to anything anymore
+ * - always adds at the end of the group
+ */
void action_groups_add_channel(struct bAction *act,
struct bActionGroup *agrp,
struct FCurve *fcurve);
-/* Remove the given channel from all groups */
+/**
+ * Remove the given channel from all groups.
+ */
void action_groups_remove_channel(struct bAction *act, struct FCurve *fcu);
-/* Reconstruct group channel pointers. */
+/**
+ * Reconstruct group channel pointers.
+ * Assumes that the groups referred to by the FCurves are already in act->groups.
+ * Reorders the main channel list to match group order.
+ */
void BKE_action_groups_reconstruct(struct bAction *act);
-/* Find a group with the given name */
+/**
+ * Find a group with the given name.
+ */
struct bActionGroup *BKE_action_group_find_name(struct bAction *act, const char name[]);
-/* Clear all 'temp' flags on all groups */
+/**
+ * Clear all 'temp' flags on all groups.
+ */
void action_groups_clear_tempflags(struct bAction *act);
/**
@@ -139,21 +175,47 @@ bool BKE_action_has_single_frame(const struct bAction *act);
/* Pose API ----------------- */
void BKE_pose_channel_free(struct bPoseChannel *pchan);
+/**
+ * Deallocates a pose channel.
+ * Does not free the pose channel itself.
+ */
void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user);
+/**
+ * Clears the runtime cache of a pose channel without free.
+ */
void BKE_pose_channel_runtime_reset(struct bPoseChannel_Runtime *runtime);
+/**
+ * Reset all non-persistent fields.
+ */
void BKE_pose_channel_runtime_reset_on_copy(struct bPoseChannel_Runtime *runtime);
+/**
+ * Deallocates runtime cache of a pose channel
+ */
void BKE_pose_channel_runtime_free(struct bPoseChannel_Runtime *runtime);
+/**
+ * Deallocates runtime cache of a pose channel's B-Bone shape.
+ */
void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime);
void BKE_pose_channels_free(struct bPose *pose);
+/**
+ * Removes and deallocates all channels from a pose.
+ * Does not free the pose itself.
+ */
void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user);
+/**
+ * Removes the hash for quick lookup of channels, must be done when adding/removing channels.
+ */
void BKE_pose_channels_hash_ensure(struct bPose *pose);
void BKE_pose_channels_hash_free(struct bPose *pose);
+/**
+ * Selectively remove pose channels.
+ */
void BKE_pose_channels_remove(struct Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data),
void *user_data);
@@ -161,18 +223,63 @@ void BKE_pose_channels_remove(struct Object *ob,
void BKE_pose_free_data_ex(struct bPose *pose, bool do_id_user);
void BKE_pose_free_data(struct bPose *pose);
void BKE_pose_free(struct bPose *pose);
+/**
+ * Removes and deallocates all data from a pose, and also frees the pose.
+ */
void BKE_pose_free_ex(struct bPose *pose, bool do_id_user);
+/**
+ * Allocate a new pose on the heap, and copy the src pose and its channels
+ * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
+ *
+ * \param dst: Should be freed already, makes entire duplicate.
+ */
void BKE_pose_copy_data_ex(struct bPose **dst,
const struct bPose *src,
const int flag,
const bool copy_constraints);
void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, const bool copy_constraints);
+/**
+ * Copy the internal members of each pose channel including constraints
+ * and ID-Props, used when duplicating bones in edit-mode.
+ * (unlike copy_pose_channel_data which only does posing-related stuff).
+ *
+ * \note use when copying bones in edit-mode (on returned value from #BKE_pose_channel_ensure)
+ */
void BKE_pose_channel_copy_data(struct bPoseChannel *pchan, const struct bPoseChannel *pchan_from);
void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan);
+/**
+ * Return a pointer to the pose channel of the given name
+ * from this pose.
+ */
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
+/**
+ * Find the active pose-channel for an object
+ * (we can't just use pose, as layer info is in armature)
+ *
+ * \note #Object, not #bPose is used here, as we need layer info from Armature.
+ */
struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
+/**
+ * Use this when detecting the "other selected bone",
+ * when we have multiple armatures in pose mode.
+ *
+ * In this case the active-selected is an obvious choice when finding the target for a
+ * constraint for eg. however from the users perspective the active pose bone of the
+ * active object is the _real_ active bone, so any other non-active selected bone
+ * is a candidate for being the other selected bone, see: T58447.
+ */
struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob);
+/**
+ * Looks to see if the channel with the given name already exists
+ * in this pose - if not a new one is allocated and initialized.
+ *
+ * \note Use with care, not on Armature poses but for temporal ones.
+ * \note (currently used for action constraints and in rebuild_pose).
+ */
struct bPoseChannel *BKE_pose_channel_ensure(struct bPose *pose, const char *name);
+/**
+ * \see #ED_armature_ebone_get_mirrored (edit-mode, matching function)
+ */
struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, const char *name);
void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose);
@@ -181,37 +288,60 @@ void BKE_pose_check_uuids_unique_and_report(const struct bPose *pose);
bool BKE_pose_channels_is_valid(const struct bPose *pose);
#endif
-/* sets constraint flags */
+/**
+ * Checks for IK constraint, Spline IK, and also for Follow-Path constraint.
+ * can do more constraints flags later. pose should be entirely OK.
+ */
void BKE_pose_update_constraint_flags(struct bPose *pose);
-/* tag constraint flags for update */
+/**
+ * Tag constraint flags for update.
+ */
void BKE_pose_tag_update_constraint_flags(struct bPose *pose);
-/* return the name of structure pointed by pose->ikparam */
+/**
+ * Return the name of structure pointed by `pose->ikparam`.
+ */
const char *BKE_pose_ikparam_get_name(struct bPose *pose);
-/* allocate and initialize pose->ikparam according to pose->iksolver */
+/**
+ * Allocate and initialize `pose->ikparam` according to `pose->iksolver`.
+ */
void BKE_pose_ikparam_init(struct bPose *pose);
-/* initialize a bItasc structure with default value */
+/**
+ * Initialize a #bItasc structure with default value.
+ */
void BKE_pose_itasc_init(struct bItasc *itasc);
-/* Checks if a bone is part of an IK chain or not */
+/**
+ * Checks if a bone is part of an IK chain or not.
+ */
bool BKE_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan);
/* Bone Groups API --------------------- */
-/* Adds a new bone-group */
+/**
+ * Adds a new bone-group (name may be NULL).
+ */
struct bActionGroup *BKE_pose_add_group(struct bPose *pose, const char *name);
-/* Remove a bone-group */
+/**
+ * Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
+ * index might be invalid ( < 1), in which case it will be find from grp.
+ */
void BKE_pose_remove_group(struct bPose *pose, struct bActionGroup *grp, const int index);
-/* Remove the matching bone-group from its index */
+/**
+ * Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)).
+ */
void BKE_pose_remove_group_index(struct bPose *pose, const int index);
/* Assorted Evaluation ----------------- */
-/* Used for the Action Constraint */
+/**
+ * For the calculation of the effects of an Action at the given frame on an object
+ * This is currently only used for the Action Constraint
+ */
void what_does_obaction(struct Object *ob,
struct Object *workob,
struct bPose *pose,
@@ -222,11 +352,18 @@ void what_does_obaction(struct Object *ob,
/* for proxy */
void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto,
const struct bPoseChannel *pchanfrom);
+/**
+ * Both poses should be in sync.
+ */
bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
-/* Clear transforms. */
+/**
+ * Zero the pose transforms for the entire pose or only for selected bones.
+ */
void BKE_pose_rest(struct bPose *pose, bool selected_bones_only);
-/* Tag pose for recalc. Also tag all related data to be recalc. */
+/**
+ * Tag pose for recalculation. Also tag all related data to be recalculated.
+ */
void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose);
void BKE_pose_blend_write(struct BlendWriter *writer, struct bPose *pose, struct bArmature *arm);
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
index 14ab9f21424..a65efbd707c 100644
--- a/source/blender/blenkernel/BKE_anim_data.h
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -43,43 +43,81 @@ struct bAction;
/* ************************************* */
/* AnimData API */
-/* Check if the given ID-block can have AnimData */
+/**
+ * Check if the given ID-block can have AnimData.
+ */
bool id_type_can_have_animdata(const short id_type);
bool id_can_have_animdata(const struct ID *id);
-/* Get AnimData from the given ID-block */
+/**
+ * Get #AnimData from the given ID-block.
+ */
struct AnimData *BKE_animdata_from_id(struct ID *id);
-/* Ensure AnimData is present in the ID-block (when supported). */
+/**
+ * Ensure #AnimData exists in the given ID-block (when supported).
+ */
struct AnimData *BKE_animdata_ensure_id(struct ID *id);
-/* Set active action used by AnimData from the given ID-block */
+/**
+ * Set active action used by AnimData from the given ID-block.
+ *
+ * Called when user tries to change the active action of an #AnimData block
+ * (via RNA, Outliner, etc.)
+ *
+ * \param reports: Can be NULL.
+ * \param id: The owner of the animation data
+ * \param act: The Action to set, or NULL to clear.
+ *
+ * \return true when the action was successfully updated, false otherwise.
+ */
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
bool BKE_animdata_action_editable(const struct AnimData *adt);
-/* Ensure that the action's idroot is set correctly given the ID type of the owner.
- * Return true if it is, false if it was already set to an incompatible type. */
+/**
+ * Ensure that the action's idroot is set correctly given the ID type of the owner.
+ * Return true if it is, false if it was already set to an incompatible type.
+ */
bool BKE_animdata_action_ensure_idroot(const struct ID *owner, struct bAction *action);
-/* Free AnimData */
+/**
+ * Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer.
+ */
void BKE_animdata_free(struct ID *id, const bool do_id_user);
-/* Return true if the ID-block has non-empty AnimData. */
+/**
+ * Return true if the ID-block has non-empty AnimData.
+ */
bool BKE_animdata_id_is_animated(const struct ID *id);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_animdata_foreach_id(struct AnimData *adt, struct LibraryForeachIDData *data);
-/* Copy AnimData */
+/**
+ * Make a copy of the given AnimData - to be used when copying data-blocks.
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return The copied animdata.
+ */
struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
-/* Copy AnimData */
+/**
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return true is successfully copied.
+ */
bool BKE_animdata_copy_id(struct Main *bmain,
struct ID *id_to,
struct ID *id_from,
const int flag);
-/* Copy AnimData Actions */
+/**
+ * Copy AnimData Actions.
+ */
void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id);
void BKE_animdata_duplicate_id_action(struct Main *bmain,
@@ -98,6 +136,9 @@ typedef enum eAnimData_MergeCopy_Modes {
ADT_MERGECOPY_SRC_REF = 2,
} eAnimData_MergeCopy_Modes;
+/**
+ * Merge copies of the data from the src AnimData into the destination AnimData.
+ */
void BKE_animdata_merge_copy(struct Main *bmain,
struct ID *dst_id,
struct ID *src_id,
diff --git a/source/blender/blenkernel/BKE_anim_path.h b/source/blender/blenkernel/BKE_anim_path.h
index 9db63080fd9..6bc09eb35ed 100644
--- a/source/blender/blenkernel/BKE_anim_path.h
+++ b/source/blender/blenkernel/BKE_anim_path.h
@@ -35,12 +35,21 @@ struct Object;
int BKE_anim_path_get_array_size(const struct CurveCache *curve_cache);
float BKE_anim_path_get_length(const struct CurveCache *curve_cache);
-/* This function populates the 'ob->runtime.curve_cache->anim_path_accum_length' data.
+/**
+ * This function populates the 'ob->runtime.curve_cache->anim_path_accum_length' data.
* You should never have to call this manually as it should already have been called by
* 'BKE_displist_make_curveTypes'. Do not call this manually unless you know what you are doing.
*/
void BKE_anim_path_calc_data(struct Object *ob);
+/**
+ * Calculate the deformation implied by the curve path at a given parametric position,
+ * and returns whether this operation succeeded.
+ *
+ * \param ctime: Time is normalized range <0-1>.
+ *
+ * \return success.
+ */
bool BKE_where_on_path(const struct Object *ob,
float ctime,
float r_vec[4],
diff --git a/source/blender/blenkernel/BKE_anim_visualization.h b/source/blender/blenkernel/BKE_anim_visualization.h
index 4e86abeed8d..3b8c91b7fd2 100644
--- a/source/blender/blenkernel/BKE_anim_visualization.h
+++ b/source/blender/blenkernel/BKE_anim_visualization.h
@@ -38,13 +38,34 @@ struct bPoseChannel;
/* ---------------------------------------------------- */
/* Animation Visualization */
+/**
+ * Initialize the default settings for animation visualization.
+ */
void animviz_settings_init(struct bAnimVizSettings *avs);
+/**
+ * Make a copy of motion-path data, so that viewing with copy on write works.
+ */
struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
+/**
+ * Free the given motion path's cache.
+ */
void animviz_free_motionpath_cache(struct bMotionPath *mpath);
+/**
+ * Free the given motion path instance and its data.
+ * \note this frees the motion path given!
+ */
void animviz_free_motionpath(struct bMotionPath *mpath);
+/**
+ * Setup motion paths for the given data.
+ * \note Only used when explicitly calculating paths on bones which may/may not be consider already
+ *
+ * \param scene: Current scene (for frame ranges, etc.)
+ * \param ob: Object to add paths for (must be provided)
+ * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
+ */
struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports,
struct Scene *scene,
struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 07da9d75e59..6197cb93c95 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -69,12 +69,17 @@ AnimationEvalContext BKE_animsys_eval_context_construct_at(
/* ************************************* */
/* KeyingSets API */
-/* Used to create a new 'custom' KeyingSet for the user,
- * that will be automatically added to the stack */
+/**
+ * Used to create a new 'custom' KeyingSet for the user,
+ * that will be automatically added to the stack.
+ */
struct KeyingSet *BKE_keyingset_add(
struct ListBase *list, const char idname[], const char name[], short flag, short keyingflag);
-/* Add a path to a KeyingSet */
+/**
+ * Add a path to a KeyingSet. Nothing is returned for now.
+ * Checks are performed to ensure that destination is appropriate for the KeyingSet in question
+ */
struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks,
struct ID *id,
const char group_name[],
@@ -83,7 +88,10 @@ struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks,
short flag,
short groupmode);
-/* Find the destination matching the criteria given */
+/**
+ * Find the destination matching the criteria given.
+ * TODO: do we want some method to perform partial matches too?
+ */
struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks,
struct ID *id,
const char group_name[],
@@ -208,11 +216,32 @@ void BKE_fcurves_id_cb(struct ID *id, ID_FCurve_Edit_Callback func, void *user_d
typedef struct NlaKeyframingContext NlaKeyframingContext;
+/**
+ * Prepare data necessary to compute correct keyframe values for NLA strips
+ * with non-Replace mode or influence different from 1.
+ *
+ * \param cache: List used to cache contexts for reuse when keying
+ * multiple channels in one operation.
+ * \param ptr: RNA pointer to the Object with the animation.
+ * \return Keyframing context, or NULL if not necessary.
+ */
struct NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
struct AnimData *adt,
const struct AnimationEvalContext *anim_eval_context);
+/**
+ * Apply correction from the NLA context to the values about to be keyframed.
+ *
+ * \param context: Context to use (may be NULL).
+ * \param prop_ptr: Property about to be keyframed.
+ * \param[in,out] values: Array of property values to adjust.
+ * \param count: Number of values in the array.
+ * \param index: Index of the element about to be updated, or -1.
+ * \param[out] r_force_all: Set to true if all channels must be inserted. May be NULL.
+ * \return False if correction fails due to a division by zero,
+ * or null r_force_all when all channels are required.
+ */
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,
@@ -220,6 +249,9 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
int count,
int index,
bool *r_force_all);
+/**
+ * Free all cached contexts from the list.
+ */
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache);
/* ************************************* */
@@ -240,16 +272,32 @@ bool BKE_animsys_rna_path_resolve(struct PointerRNA *ptr,
const int array_index,
struct PathResolvedRNA *r_result);
bool BKE_animsys_read_from_rna_path(struct PathResolvedRNA *anim_rna, float *r_value);
+/**
+ * Write the given value to a setting using RNA, and return success.
+ */
bool BKE_animsys_write_to_rna_path(struct PathResolvedRNA *anim_rna, const float value);
-/* Evaluation loop for evaluating animation data. */
+/**
+ * Evaluation loop for evaluation animation data
+ *
+ * This assumes that the animation-data provided belongs to the ID block in question,
+ * and that the flags for which parts of the animation-data settings need to be recalculated
+ * have been set already by the depsgraph. Now, we use the recalculate.
+ */
void BKE_animsys_evaluate_animdata(struct ID *id,
struct AnimData *adt,
const struct AnimationEvalContext *anim_eval_context,
eAnimData_Recalc recalc,
const bool flush_to_original);
-/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
+/**
+ * Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
+ *
+ * This will evaluate only the animation info available in the animation data-blocks
+ * encountered. In order to enforce the system by which some settings controlled by a
+ * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
+ * standard 'root') block are overridden by a larger 'user'
+ */
void BKE_animsys_evaluate_all_animation(struct Main *main,
struct Depsgraph *depsgraph,
float ctime);
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 65485058dd7..dd589282bdd 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -17,6 +17,9 @@
/** \file
* \ingroup bke
+ *
+ * \note on naming: typical _get() suffix is omitted here,
+ * since its the main purpose of the API.
*/
#include <stddef.h>
@@ -29,54 +32,139 @@ extern "C" {
struct ListBase;
+/**
+ * Sanity check to ensure correct API use in debug mode.
+ *
+ * Run this once the first level of arguments has been passed so we can be sure
+ * `--env-system-datafiles`, and other `--env-*` arguments has been passed.
+ *
+ * Without this any callers to this module that run early on,
+ * will miss out on changes from parsing arguments.
+ */
void BKE_appdir_init(void);
void BKE_appdir_exit(void);
-/* note on naming: typical _get() suffix is omitted here,
- * since its the main purpose of the API. */
+/**
+ * Get the folder that's the "natural" starting point for browsing files on an OS.
+ * - Unix: `$HOME`
+ * - Windows: `%userprofile%/Documents`
+ *
+ * \note On Windows `Users/{MyUserName}/Documents` is used as it's the default location to save
+ * documents.
+ */
const char *BKE_appdir_folder_default(void) ATTR_WARN_UNUSED_RESULT;
const char *BKE_appdir_folder_root(void) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
const char *BKE_appdir_folder_default_or_root(void) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
+/**
+ * Get the user's home directory, i.e.
+ * - Unix: `$HOME`
+ * - Windows: `%userprofile%`
+ */
const char *BKE_appdir_folder_home(void);
+/**
+ * Get the user's document directory, i.e.
+ * - Linux: `$HOME/Documents`
+ * - Windows: `%userprofile%/Documents`
+ *
+ * If this can't be found using OS queries (via Ghost), try manually finding it.
+ *
+ * \returns True if the path is valid and points to an existing directory.
+ */
bool BKE_appdir_folder_documents(char *dir);
+/**
+ * Get the user's cache directory, i.e.
+ * - Linux: `$HOME/.cache/blender/`
+ * - Windows: `%USERPROFILE%\AppData\Local\Blender Foundation\Blender\`
+ * - MacOS: `/Library/Caches/Blender`
+ *
+ * \returns True if the path is valid. It doesn't create or checks format
+ * if the `blender` folder exists. It does check if the parent of the path exists.
+ */
bool BKE_appdir_folder_caches(char *r_path, size_t path_len);
+/**
+ * Get a folder out of the \a folder_id presets for paths.
+ *
+ * \param subfolder: The name of a directory to check for,
+ * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
+ * \return The path if found, NULL string if not.
+ */
bool BKE_appdir_folder_id_ex(const int folder_id,
const char *subfolder,
char *path,
size_t path_len);
const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder);
+/**
+ * Returns the path to a folder in the user area, creating it if it doesn't exist.
+ */
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder);
+/**
+ * Returns the path to a folder in the user area without checking that it actually exists first.
+ */
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder);
+/**
+ * Returns the path of the top-level version-specific local, user or system directory.
+ * If check_is_dir, then the result will be NULL if the directory doesn't exist.
+ */
const char *BKE_appdir_folder_id_version(const int folder_id,
const int version,
const bool check_is_dir);
+/**
+ * Check if this is an install with user files kept together
+ * with the Blender executable and its installation files.
+ */
bool BKE_appdir_app_is_portable_install(void);
+/**
+ * Return true if templates exist
+ */
bool BKE_appdir_app_template_any(void);
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len);
bool BKE_appdir_app_template_has_userpref(const char *app_template);
void BKE_appdir_app_templates(struct ListBase *templates);
-/* Initialize path to program executable */
+/**
+ * Initialize path to program executable.
+ */
void BKE_appdir_program_path_init(const char *argv0);
+/**
+ * Path to executable
+ */
const char *BKE_appdir_program_path(void);
+/**
+ * Path to directory of executable
+ */
const char *BKE_appdir_program_dir(void);
-/* Return OS fonts directory. */
+/**
+ * Gets a good default directory for fonts.
+ */
bool BKE_appdir_font_folder_default(char *dir);
-/* find python executable */
+/**
+ * Find Python executable.
+ */
bool BKE_appdir_program_python_search(char *fullpath,
const size_t fullpath_len,
const int version_major,
const int version_minor);
-/* Initialize path to temporary directory. */
+/**
+ * Initialize path to temporary directory.
+ */
void BKE_tempdir_init(const char *userdir);
+/**
+ * Path to persistent temporary directory (with trailing slash)
+ */
const char *BKE_tempdir_base(void);
+/**
+ * Path to temporary directory (with trailing slash)
+ */
const char *BKE_tempdir_session(void);
+/**
+ * Delete content of this instance's temp dir.
+ */
void BKE_tempdir_session_purge(void);
/* folder_id */
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index e13475fd78c..fcba7d9d365 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -166,8 +166,20 @@ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
bool BKE_pose_minmax(
struct Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select);
+/**
+ * Finds the best possible extension to the name on a particular axis.
+ * (For renaming, check for unique names afterwards)
+ * \param strip_number: removes number extensions (TODO: not used).
+ * \param axis: The axis to name on.
+ * \param head: The head co-ordinate of the bone on the specified axis.
+ * \param tail: The tail co-ordinate of the bone on the specified axis.
+ */
bool bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail);
+/**
+ * Walk the list until the bone is found (slow!),
+ * use #BKE_armature_bone_from_name_map for multiple lookups.
+ */
struct Bone *BKE_armature_find_bone_name(struct bArmature *arm, const char *name);
void BKE_armature_bone_hash_make(struct bArmature *arm);
@@ -177,40 +189,87 @@ bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag);
void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm);
+/**
+ * Using `vec` with dist to bone `b1 - b2`.
+ */
float distfactor_to_bone(
const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist);
+/**
+ * Updates vectors and matrices on rest-position level, only needed
+ * after editing armature itself, now only on reading file.
+ */
void BKE_armature_where_is(struct bArmature *arm);
+/**
+ * Recursive part, calculates rest-position of entire tree of children.
+ * \note Used when exiting edit-mode too.
+ */
void BKE_armature_where_is_bone(struct Bone *bone,
const struct Bone *bone_parent,
const bool use_recursion);
+/**
+ * Clear pointers of object's pose
+ * (needed in remap case, since we cannot always wait for a complete pose rebuild).
+ */
void BKE_pose_clear_pointers(struct bPose *pose);
void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose);
+/**
+ * Update the links for the B-Bone handles from Bone data.
+ */
void BKE_pchan_rebuild_bbone_handles(struct bPose *pose, struct bPoseChannel *pchan);
void BKE_pose_channels_clear_with_null_bone(struct bPose *pose, const bool do_id_user);
+/**
+ * Only after leave edit-mode, duplicating, validating older files, library syncing.
+ *
+ * \note pose->flag is set for it.
+ *
+ * \param bmain: May be NULL, only used to tag depsgraph as being dirty.
+ */
void BKE_pose_rebuild(struct Main *bmain,
struct Object *ob,
struct bArmature *arm,
const bool do_id_user);
+/**
+ * Ensures object's pose is rebuilt if needed.
+ *
+ * \param bmain: May be NULL, only used to tag depsgraph as being dirty.
+ */
void BKE_pose_ensure(struct Main *bmain,
struct Object *ob,
struct bArmature *arm,
const bool do_id_user);
+/**
+ * \note This is the only function adding poses.
+ * \note This only reads anim data from channels, and writes to channels.
+ */
void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+/**
+ * The main armature solver, does all constraints excluding IK.
+ *
+ * \param pchan: pose-channel - validated, as having bone and parent pointer.
+ * \param do_extra: when zero skips loc/size/rot, constraints and strip modifiers.
+ */
void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan,
float ctime,
bool do_extra);
+/**
+ * Calculate tail of pose-channel.
+ */
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
-/* Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that
- * relate to those bones are evaluated. */
+/**
+ * Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that
+ * relate to those bones are evaluated.
+ */
void BKE_pose_apply_action_selected_bones(struct Object *ob,
struct bAction *action,
struct AnimationEvalContext *anim_eval_context);
-/* Evaluate the action and apply it to the pose. Ignore selection state of the bones. */
+/**
+ * Evaluate the action and apply it to the pose. Ignore selection state of the bones.
+ */
void BKE_pose_apply_action_all_bones(struct Object *ob,
struct bAction *action,
struct AnimationEvalContext *anim_eval_context);
@@ -221,24 +280,63 @@ void BKE_pose_apply_action_blend(struct Object *ob,
float blend_factor);
void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3]);
+
+/**
+ * Calculates the rest matrix of a bone based on its vector and a roll around that vector.
+ */
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3]);
+/**
+ * Computes vector and roll based on a rotation.
+ * "mat" must contain only a rotation, and no scaling.
+ */
void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll);
+/**
+ * Computes roll around the vector that best approximates the matrix.
+ * If `vec` is the Y vector from purely rotational `mat`, result should be exact.
+ */
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll);
/* Common Conversions Between Co-ordinate Spaces */
+
+/**
+ * Convert World-Space Matrix to Pose-Space Matrix.
+ */
void BKE_armature_mat_world_to_pose(struct Object *ob,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Convert World-Space Location to Pose-Space Location
+ * \note this cannot be used to convert to pose-space location of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_loc_world_to_pose(struct Object *ob, const float inloc[3], float outloc[3]);
+/**
+ * Convert Pose-Space Matrix to Bone-Space Matrix.
+ * \note this cannot be used to convert to pose-space transforms of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_mat_pose_to_bone(struct bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Convert Pose-Space Location to Bone-Space Location
+ * \note this cannot be used to convert to pose-space location of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ */
void BKE_armature_loc_pose_to_bone(struct bPoseChannel *pchan,
const float inloc[3],
float outloc[3]);
+/**
+ * Convert Bone-Space Matrix to Pose-Space Matrix.
+ */
void BKE_armature_mat_bone_to_pose(struct bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Remove rest-position effects from pose-transform for obtaining
+ * 'visual' transformation of pose-channel.
+ * (used by the Visual-Keyframing stuff).
+ */
void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
float pose_mat[4][4],
float arm_mat[4][4]);
@@ -249,13 +347,34 @@ void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph,
const float inmat[4][4],
float outmat[4][4]);
+/**
+ * Same as #BKE_object_mat3_to_rot().
+ */
void BKE_pchan_mat3_to_rot(struct bPoseChannel *pchan, const float mat[3][3], bool use_compat);
+/**
+ * Same as #BKE_object_rot_to_mat3().
+ */
void BKE_pchan_rot_to_mat3(const struct bPoseChannel *pchan, float r_mat[3][3]);
+/**
+ * Apply a 4x4 matrix to the pose bone,
+ * similar to #BKE_object_apply_mat4().
+ */
void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, const float mat[4][4], bool use_compat);
+/**
+ * Convert the loc/rot/size to \a r_chanmat (typically #bPoseChannel.chan_mat).
+ */
void BKE_pchan_to_mat4(const struct bPoseChannel *pchan, float r_chanmat[4][4]);
+
+/**
+ * Convert the loc/rot/size to mat4 (`pchan.chan_mat`),
+ * used in `constraint.c` too.
+ */
void BKE_pchan_calc_mat(struct bPoseChannel *pchan);
-/* Simple helper, computes the offset bone matrix. */
+/**
+ * Simple helper, computes the offset bone matrix:
+ * `offs_bone = yoffs(b-1) + root(b) + bonemat(b)`.
+ */
void BKE_bone_offset_matrix_get(const struct Bone *bone, float offs_bone[4][4]);
/* Transformation inherited from the parent bone. These matrices apply the effects of
@@ -277,9 +396,38 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
const float inmat[4][4],
float outmat[4][4]);
-/* Get the current parent transformation for the given pose bone. */
+/**
+ * Get the current parent transformation for the given pose bone.
+ *
+ * Construct the matrices (rot/scale and loc)
+ * to apply the PoseChannels into the armature (object) space.
+ * I.e. (roughly) the `pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)` in the
+ * `pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b)`
+ * ...function.
+ *
+ * This allows to get the transformations of a bone in its object space,
+ * *before* constraints (and IK) get applied (used by pose evaluation code).
+ * And reverse: to find pchan transformations needed to place a bone at a given loc/rot/scale
+ * in object space (used by interactive transform, and snapping code).
+ *
+ * Note that, with the HINGE/NO_SCALE/NO_LOCAL_LOCATION options, the location matrix
+ * will differ from the rotation/scale matrix...
+ *
+ * \note This cannot be used to convert to pose-space transforms of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing).
+ * (NOTE(@mont29): I don't understand that, so I keep it :p).
+ */
void BKE_bone_parent_transform_calc_from_pchan(const struct bPoseChannel *pchan,
struct BoneParentTransform *r_bpt);
+/**
+ * Compute the parent transform using data decoupled from specific data structures.
+ *
+ * \param bone_flag: #Bone.flag containing settings.
+ * \param offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent).
+ * \param parent_arm_mat: arm_mat of parent, or NULL.
+ * \param parent_pose_mat: pose_mat of parent, or NULL.
+ * \param r_bpt: OUTPUT parent transform.
+ */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
int inherit_scale_mode,
const float offs_bone[4][4],
@@ -287,7 +435,13 @@ void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
const float parent_pose_mat[4][4],
struct BoneParentTransform *r_bpt);
-/* Rotation Mode Conversions - Used for PoseChannels + Objects... */
+/**
+ * Rotation Mode Conversions - Used for Pose-Channels + Objects.
+ *
+ * Called from RNA when rotation mode changes
+ * - the result should be that the rotations given in the provided pointers have had conversions
+ * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed.
+ */
void BKE_rotMode_change_values(
float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode);
@@ -320,18 +474,31 @@ typedef struct BBoneSplineParameters {
float curve_in_x, curve_in_z, curve_out_x, curve_out_z;
} BBoneSplineParameters;
+/**
+ * Get "next" and "prev" bones - these are used for handle calculations.
+ */
void BKE_pchan_bbone_handles_get(struct bPoseChannel *pchan,
struct bPoseChannel **r_prev,
struct bPoseChannel **r_next);
+/**
+ * Compute B-Bone spline parameters for the given channel.
+ */
void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
const bool rest,
struct BBoneSplineParameters *r_param);
+/**
+ * Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space.
+ */
void BKE_pchan_bbone_spline_setup(struct bPoseChannel *pchan,
const bool rest,
const bool for_deform,
Mat4 *result_array);
+/**
+ * Computes the bezier handle vectors and rolls coming from custom handles.
+ */
void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float h1[3],
float *r_roll1,
@@ -339,14 +506,28 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float *r_roll2,
bool ease,
bool offsets);
+/**
+ * Fills the array with the desired amount of `bone->segments` elements.
+ * This calculation is done within unit bone space.
+ */
int BKE_pchan_bbone_spline_compute(struct BBoneSplineParameters *param,
const bool for_deform,
Mat4 *result_array);
+/**
+ * Compute and cache the B-Bone shape in the channel runtime struct.
+ */
void BKE_pchan_bbone_segments_cache_compute(struct bPoseChannel *pchan);
+/**
+ * Copy cached B-Bone segments from one channel to another.
+ */
void BKE_pchan_bbone_segments_cache_copy(struct bPoseChannel *pchan,
struct bPoseChannel *pchan_from);
+/**
+ * Calculate index and blend factor for the two B-Bone segment nodes
+ * affecting the point at 0 <= pos <= 1.
+ */
void BKE_pchan_bbone_deform_segment_index(const struct bPoseChannel *pchan,
float pos,
int *r_index,
diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h
index 722d142b56c..58c50fb736f 100644
--- a/source/blender/blenkernel/BKE_asset.h
+++ b/source/blender/blenkernel/BKE_asset.h
@@ -57,6 +57,9 @@ struct AssetTagEnsureResult {
};
struct AssetTag *BKE_asset_metadata_tag_add(struct AssetMetaData *asset_data, const char *name);
+/**
+ * Make sure there is a tag with name \a name, create one if needed.
+ */
struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(struct AssetMetaData *asset_data,
const char *name);
void BKE_asset_metadata_tag_remove(struct AssetMetaData *asset_data, struct AssetTag *tag);
diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh
index 3478eebbeb4..ecc839050b7 100644
--- a/source/blender/blenkernel/BKE_asset_catalog.hh
+++ b/source/blender/blenkernel/BKE_asset_catalog.hh
@@ -98,6 +98,15 @@ class AssetCatalogService {
bool write_to_disk(const CatalogFilePath &blend_file_path);
/**
+ * Ensure that the next call to #on_blend_save_post() will choose a new location for the CDF
+ * suitable for the location of the blend file (regardless of where the current catalogs come
+ * from), and that catalogs will be merged with already-existing ones in that location.
+ *
+ * Use this for a "Save as..." that has to write the catalogs to the new blend file location,
+ * instead of updating the previously read CDF. */
+ void prepare_to_merge_on_write();
+
+ /**
* Merge on-disk changes into the in-memory asset catalogs.
* This should be called before writing the asset catalogs to disk.
*
@@ -238,6 +247,11 @@ class AssetCatalogService {
*/
void create_missing_catalogs();
+ /**
+ * For every catalog, mark it as "dirty".
+ */
+ void tag_all_catalogs_as_unsaved_changes();
+
/* For access by subclasses, as those will not be marked as friend by #AssetCatalogCollection. */
AssetCatalogDefinitionFile *get_catalog_definition_file();
OwningAssetCatalogMap &get_catalogs();
@@ -363,6 +377,9 @@ class AssetCatalogDefinitionFile {
/* For now this is the only version of the catalog definition files that is supported.
* Later versioning code may be added to handle older files. */
const static int SUPPORTED_VERSION;
+ /* String that's matched in the catalog definition file to know that the line is the version
+ * declaration. It has to start with a space to ensure it won't match any hypothetical future
+ * field that starts with "VERSION". */
const static std::string VERSION_MARKER;
const static std::string HEADER;
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 47f62b52a0f..fd30813a506 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -155,6 +155,10 @@ using fn::GVMutableArray;
const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types);
+/**
+ * Domains with a higher "information density" have a higher priority,
+ * in order to choose a domain that will not lose data through domain conversion.
+ */
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
/**
@@ -345,8 +349,15 @@ class CustomDataAttributes {
void reallocate(const int size);
+ void clear();
+
std::optional<blender::fn::GSpan> get_for_read(const AttributeIDRef &attribute_id) const;
+ /**
+ * Return a virtual array for a stored attribute, or a single value virtual array with the
+ * default value if the attribute doesn't exist. If no default value is provided, the default
+ * value for the type will be used.
+ */
blender::fn::GVArray get_for_read(const AttributeIDRef &attribute_id,
const CustomDataType data_type,
const void *default_value) const;
@@ -514,19 +525,3 @@ template<typename T> inline MutableSpan<T> OutputAttribute::as_span()
/** \} */
} // namespace blender::bke
-
-/* -------------------------------------------------------------------- */
-/** \name External Template Instantiations
- *
- * Defined in `intern/extern_implementations.cc`.
- * \{ */
-
-namespace blender::bke {
-extern template class OutputAttribute_Typed<float>;
-extern template class OutputAttribute_Typed<int>;
-extern template class OutputAttribute_Typed<float3>;
-extern template class OutputAttribute_Typed<bool>;
-extern template class OutputAttribute_Typed<ColorGeometry4f>;
-} // namespace blender::bke
-
-/** \} */
diff --git a/source/blender/blenkernel/BKE_autoexec.h b/source/blender/blenkernel/BKE_autoexec.h
index 84d83ae5d30..55bb3e8877f 100644
--- a/source/blender/blenkernel/BKE_autoexec.h
+++ b/source/blender/blenkernel/BKE_autoexec.h
@@ -23,6 +23,10 @@
extern "C" {
#endif
+/**
+ * \param path: The path to check against.
+ * \return Success
+ */
bool BKE_autoexec_match(const char *path);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 813472715fa..8c0512edb1d 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -29,6 +29,9 @@ extern "C" {
struct UserDef;
+/**
+ * Only to be called on exit Blender.
+ */
void BKE_blender_free(void);
void BKE_blender_globals_init(void);
@@ -38,11 +41,19 @@ void BKE_blender_userdef_data_swap(struct UserDef *userdef_a, struct UserDef *us
void BKE_blender_userdef_data_set(struct UserDef *userdef);
void BKE_blender_userdef_data_set_and_free(struct UserDef *userdef);
+/**
+ * Write U from userdef.
+ * This function defines which settings a template will override for the user preferences.
+ */
void BKE_blender_userdef_app_template_data_swap(struct UserDef *userdef_a,
struct UserDef *userdef_b);
void BKE_blender_userdef_app_template_data_set(struct UserDef *userdef);
void BKE_blender_userdef_app_template_data_set_and_free(struct UserDef *userdef);
+/**
+ * When loading a new userdef from file,
+ * or when exiting Blender.
+ */
void BKE_blender_userdef_data_free(struct UserDef *userdef, bool clear_fonts);
/* Blenders' own atexit (avoids leaking) */
diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h
index 4dd7145e66d..abfb37ef959 100644
--- a/source/blender/blenkernel/BKE_blender_copybuffer.h
+++ b/source/blender/blenkernel/BKE_blender_copybuffer.h
@@ -30,16 +30,54 @@ struct Main;
struct ReportList;
struct bContext;
-/* copybuffer (wrapper for BKE_blendfile_write_partial) */
+/* Copy-buffer (wrapper for BKE_blendfile_write_partial). */
+
+/**
+ * Initialize a copy operation.
+ */
void BKE_copybuffer_copy_begin(struct Main *bmain_src);
+/**
+ * Mark an ID to be copied. Should only be called after a call to #BKE_copybuffer_copy_begin.
+ */
void BKE_copybuffer_copy_tag_ID(struct ID *id);
+/**
+ * Finalize a copy operation into given .blend file 'buffer'.
+ *
+ * \param filename: Full path to the .blend file used as copy/paste buffer.
+ *
+ * \return true on success, false otherwise.
+ */
bool BKE_copybuffer_copy_end(struct Main *bmain_src,
const char *filename,
struct ReportList *reports);
+/**
+ * Paste data-blocks from the given .blend file 'buffer' (i.e. append them).
+ *
+ * Unlike #BKE_copybuffer_paste, it does not perform any instantiation of collections/objects/etc.
+ *
+ * \param libname: Full path to the .blend file used as copy/paste buffer.
+ * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
+ *
+ * \return true on success, false otherwise.
+ */
bool BKE_copybuffer_read(struct Main *bmain_dst,
const char *libname,
struct ReportList *reports,
const uint64_t id_types_mask);
+/**
+ * Paste data-blocks from the given .blend file 'buffer' (i.e. append them).
+ *
+ * Similar to #BKE_copybuffer_read, but also handles instantiation of collections/objects/etc.
+ *
+ * \param libname: Full path to the .blend file used as copy/paste buffer.
+ * \param flag: A combination of #eBLOLibLinkFlags and ##eFileSel_Params_Flag to control
+ * link/append behavior.
+ * \note Ignores #FILE_LINK flag, since it always appends IDs.
+ * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
+ *
+ * \return Number of IDs directly pasted from the buffer
+ * (does not includes indirectly linked ones).
+ */
int BKE_copybuffer_paste(struct bContext *C,
const char *libname,
const int flag,
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 966d6c95421..d0ab8be9a29 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 3
+#define BLENDER_FILE_SUBVERSION 5
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 3e0a343a766..b3211b1dbbc 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -33,6 +33,14 @@ struct ReportList;
struct UserDef;
struct bContext;
+/**
+ * Shared setup function that makes the data from `bfd` into the current blend file,
+ * replacing the contents of #G.main.
+ * This uses the bfd #BKE_blendfile_read and similarly named functions.
+ *
+ * This is done in a separate step so the caller may perform actions after it is known the file
+ * loaded correctly but before the file replaces the existing blend file contents.
+ */
void BKE_blendfile_read_setup_ex(struct bContext *C,
struct BlendFileData *bfd,
const struct BlendFileReadParams *params,
@@ -46,28 +54,56 @@ void BKE_blendfile_read_setup(struct bContext *C,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ */
struct BlendFileData *BKE_blendfile_read(const char *filepath,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ */
struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
+ * \note `memfile` is the undo buffer.
+ */
struct BlendFileData *BKE_blendfile_read_from_memfile(struct Main *bmain,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * Utility to make a file 'empty' used for startup to optionally give an empty file.
+ * Handy for tests.
+ */
void BKE_blendfile_read_make_empty(struct bContext *C);
+/**
+ * Only read the #UserDef from a .blend.
+ */
struct UserDef *BKE_blendfile_userdef_read(const char *filepath, struct ReportList *reports);
struct UserDef *BKE_blendfile_userdef_read_from_memory(const void *filebuf,
int filelength,
struct ReportList *reports);
struct UserDef *BKE_blendfile_userdef_from_defaults(void);
+/**
+ * Only write the #UserDef in a `.blend`.
+ * \return success.
+ */
bool BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports);
+/**
+ * Only write the #UserDef in a `.blend`, merging with the existing blend file.
+ * \return success.
+ *
+ * \note In the future we should re-evaluate user preferences,
+ * possibly splitting out system/hardware specific preferences.
+ */
bool BKE_blendfile_userdef_write_app_template(const char *filepath, struct ReportList *reports);
bool BKE_blendfile_userdef_write_all(struct ReportList *reports);
@@ -81,9 +117,14 @@ bool BKE_blendfile_workspace_config_write(struct Main *bmain,
struct ReportList *reports);
void BKE_blendfile_workspace_config_data_free(struct WorkspaceConfigFileData *workspace_config);
-/* partial blend file writing */
+/* Partial blend file writing. */
+
void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
+/**
+ * \param remap_mode: Choose the kind of path remapping or none #eBLO_WritePathRemap.
+ * \return Success.
+ */
bool BKE_blendfile_write_partial(struct Main *bmain_src,
const char *filepath,
const int write_flags,
diff --git a/source/blender/blenkernel/BKE_blendfile_link_append.h b/source/blender/blenkernel/BKE_blendfile_link_append.h
new file mode 100644
index 00000000000..aaa31352316
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blendfile_link_append.h
@@ -0,0 +1,222 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct BlendHandle;
+struct ID;
+struct Library;
+struct LibraryLink_Params;
+struct Main;
+struct ReportList;
+struct Scene;
+struct ViewLayer;
+struct View3D;
+
+typedef struct BlendfileLinkAppendContext BlendfileLinkAppendContext;
+typedef struct BlendfileLinkAppendContextItem BlendfileLinkAppendContextItem;
+
+/**
+ * Allocate and initialize a new context to link/append data-blocks.
+ */
+BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(
+ struct LibraryLink_Params *params);
+/**
+ * Free a link/append context.
+ */
+void BKE_blendfile_link_append_context_free(struct BlendfileLinkAppendContext *lapp_context);
+/**
+ * Set or clear flags in given \a lapp_context.
+ *
+ * \param flag: A combination of:
+ * - #eFileSel_Params_Flag from `DNA_space_types.h` &
+ * - #eBLOLibLinkFlags * from `BLO_readfile.h`.
+ * \param do_set: Set the given \a flag if true, clear it otherwise.
+ */
+void BKE_blendfile_link_append_context_flag_set(struct BlendfileLinkAppendContext *lapp_context,
+ const int flag,
+ const bool do_set);
+
+/**
+ * Store reference to a Blender's embedded memfile into the context.
+ *
+ * \note This is required since embedded startup blender file is handled in `ED` module, which
+ * cannot be linked in BKE code.
+ */
+void BKE_blendfile_link_append_context_embedded_blendfile_set(
+ struct BlendfileLinkAppendContext *lapp_context,
+ const void *blendfile_mem,
+ int blendfile_memsize);
+/** Clear reference to Blender's embedded startup file into the context. */
+void BKE_blendfile_link_append_context_embedded_blendfile_clear(
+ struct BlendfileLinkAppendContext *lapp_context);
+
+/**
+ * Add a new source library to search for items to be linked to the given link/append context.
+ *
+ * \param libname: the absolute path to the library blend file.
+ * \param blo_handle: the blend file handle of the library, NULL is not available. Note that this
+ * is only borrowed for linking purpose, no releasing or other management will
+ * be performed by #BKE_blendfile_link_append code on it.
+ *
+ * \note *Never* call #BKE_blendfile_link_append_context_library_add()
+ * after having added some items.
+ */
+void BKE_blendfile_link_append_context_library_add(struct BlendfileLinkAppendContext *lapp_context,
+ const char *libname,
+ struct BlendHandle *blo_handle);
+/**
+ * Add a new item (data-block name and `idcode`) to be searched and linked/appended from libraries
+ * associated to the given context.
+ *
+ * \param userdata: an opaque user-data pointer stored in generated link/append item.
+ *
+ * TODO: Add a more friendly version of this that combines it with the call to
+ * #BKE_blendfile_link_append_context_item_library_index_enable to enable the added item for all
+ * added library sources.
+ */
+struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
+ struct BlendfileLinkAppendContext *lapp_context,
+ const char *idname,
+ const short idcode,
+ void *userdata);
+
+#define BLENDFILE_LINK_APPEND_INVALID -1
+/**
+ * Search for all ID matching given `id_types_filter` in given `library_index`, and add them to
+ * the list of items to process.
+ *
+ * \note #BKE_blendfile_link_append_context_library_add should never be called on the same
+ *`lapp_context` after this function.
+ *
+ * \param id_types_filter: A set of `FILTER_ID` bitflags, the types of IDs to add to the items
+ * list.
+ * \param library_index: The index of the library to look into, in given `lapp_context`.
+ *
+ * \return The number of items found and added to the list, or `BLENDFILE_LINK_APPEND_INVALID` if
+ * it could not open the .blend file.
+ */
+int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports,
+ const uint64_t id_types_filter,
+ const int library_index);
+
+/**
+ * Enable search of the given \a item into the library stored at given index in the link/append
+ * context.
+ */
+void BKE_blendfile_link_append_context_item_library_index_enable(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct BlendfileLinkAppendContextItem *item,
+ const int library_index);
+/**
+ * Check if given link/append context is empty (has no items to process) or not.
+ */
+bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context);
+
+void *BKE_blendfile_link_append_context_item_userdata_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+struct ID *BKE_blendfile_link_append_context_item_newid_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+short BKE_blendfile_link_append_context_item_idcode_get(
+ struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item);
+
+typedef enum eBlendfileLinkAppendForeachItemFlag {
+ /** Loop over directly linked items (i.e. those explicitly defined by user code). */
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT = 1 << 0,
+ /** Loop over indirectly linked items (i.e. those defined by internal code, as dependencies of
+ * direct ones).
+ *
+ * IMPORTANT: Those 'indirect' items currently may not cover **all** indirectly linked data.
+ * See comments in #foreach_libblock_link_append_callback. */
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 0,
+} eBlendfileLinkAppendForeachItemFlag;
+/**
+ * Callback called by #BKE_blendfile_link_append_context_item_foreach over each (or a subset of
+ * each) of the items in given #BlendfileLinkAppendContext.
+ *
+ * \param userdata: An opaque void pointer passed to the `callback_function`.
+ *
+ * \return `true` if iteration should continue, `false` otherwise.
+ */
+typedef bool (*BKE_BlendfileLinkAppendContexteItemFunction)(
+ struct BlendfileLinkAppendContext *lapp_context,
+ struct BlendfileLinkAppendContextItem *item,
+ void *userdata);
+/**
+ * Iterate over all (or a subset) of the items listed in given #BlendfileLinkAppendContext,
+ * and call the `callback_function` on them.
+ *
+ * \param flag: Control which type of items to process (see
+ * #eBlendfileLinkAppendForeachItemFlag enum flags).
+ * \param userdata: An opaque void pointer passed to the `callback_function`.
+ */
+void BKE_blendfile_link_append_context_item_foreach(
+ struct BlendfileLinkAppendContext *lapp_context,
+ BKE_BlendfileLinkAppendContexteItemFunction callback_function,
+ const eBlendfileLinkAppendForeachItemFlag flag,
+ void *userdata);
+
+/**
+ * Perform append operation, using modern ID usage looper to detect which ID should be kept
+ * linked, made local, duplicated as local, re-used from local etc.
+ *
+ * The IDs processed by this functions are the one that have been linked by a previous call to
+ * #BKE_blendfile_link on the same `lapp_context`.
+ */
+void BKE_blendfile_append(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports);
+/**
+ * Perform linking operation on all items added to given `lapp_context`.
+ */
+void BKE_blendfile_link(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports);
+
+/**
+ * Try to relocate all linked IDs added to `lapp_context`, belonging to the given `library`.
+ *
+ * This function searches for matching IDs (type and name) in all libraries added to the given
+ * `lapp_context`.
+ *
+ * Typical usages include:
+ * - Relocating a library:
+ * - Add the new target library path to `lapp_context`.
+ * - Add all IDs from the library to relocate to `lapp_context`
+ * - Mark the new target library to be considered for each ID.
+ * - Call this function.
+ *
+ * - Searching for (e.g.missing) linked IDs in a set or sub-set of libraries:
+ * - Add all potential library sources paths to `lapp_context`.
+ * - Add all IDs to search for to `lapp_context`.
+ * - Mark which libraries should be considered for each ID.
+ * - Call this function.
+ */
+void BKE_blendfile_library_relocate(struct BlendfileLinkAppendContext *lapp_context,
+ struct ReportList *reports,
+ struct Library *library,
+ const bool do_reload);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h
index 71a4d35767f..a9c8ad6422f 100644
--- a/source/blender/blenkernel/BKE_boids.h
+++ b/source/blender/blenkernel/BKE_boids.h
@@ -51,7 +51,13 @@ typedef struct BoidBrainData {
} BoidBrainData;
void boids_precalc_rules(struct ParticleSettings *part, float cfra);
+/**
+ * Determines the velocity the boid wants to have.
+ */
void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa);
+/**
+ * Tries to realize the wanted velocity taking all constraints into account.
+ */
void boid_body(BoidBrainData *bbd, struct ParticleData *pa);
void boid_default_settings(struct BoidSettings *boids);
struct BoidRule *boid_new_rule(int type);
diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h
index 3ec5409ca7f..bae151f6a72 100644
--- a/source/blender/blenkernel/BKE_bpath.h
+++ b/source/blender/blenkernel/BKE_bpath.h
@@ -16,10 +16,14 @@
/** \file
* \ingroup bke
- * \attention Based on ghash, difference is ghash is not a fixed size,
- * so for BPath we don't need to malloc
+ *
+ * \warning All paths manipulated by this API are assumed to be either constant char buffers of
+ * `FILE_MAX` size, or allocated char buffers not bigger than `FILE_MAX`.
*/
+/* TODO: Make this module handle a bit more safely string length, instead of assuming buffers are
+ * FILE_MAX length etc. */
+
#pragma once
#ifdef __cplusplus
@@ -31,66 +35,181 @@ struct ListBase;
struct Main;
struct ReportList;
-/* Function that does something with an ID's file path. Should return 1 if the
- * path has changed, and in that case, should write the result to pathOut. */
-typedef bool (*BPathVisitor)(void *userdata, char *path_dst, const char *path_src);
-/* Executes 'visit' for each path associated with 'id'. */
-void BKE_bpath_traverse_id(struct Main *bmain,
- struct ID *id,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-void BKE_bpath_traverse_id_list(struct Main *bmain,
- struct ListBase *lb,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-void BKE_bpath_traverse_main(struct Main *bmain,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data);
-bool BKE_bpath_relocate_visitor(void *oldbasepath, char *path_dst, const char *path_src);
-
-/* Functions for temp backup/restore of paths, path count must NOT change */
-void *BKE_bpath_list_backup(struct Main *bmain, const int flag);
-void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle);
-void BKE_bpath_list_free(void *ls_handle);
-
-enum {
- /* convert paths to absolute */
- BKE_BPATH_TRAVERSE_ABS = (1 << 0),
- /* skip library paths */
- BKE_BPATH_TRAVERSE_SKIP_LIBRARY = (1 << 1),
- /* skip packed data */
- BKE_BPATH_TRAVERSE_SKIP_PACKED = (1 << 2),
- /* skip paths where a single dir is used with an array of files, eg.
- * sequence strip images and pointcache. in this case only use the first
- * file, this is needed for directory manipulation functions which might
- * otherwise modify the same directory multiple times */
- BKE_BPATH_TRAVERSE_SKIP_MULTIFILE = (1 << 3),
- /* reload data (when the path is edited) */
- BKE_BPATH_TRAVERSE_RELOAD_EDITED = (1 << 4),
-};
-
-/* high level funcs */
-
-/* creates a text file with missing files if there are any */
+/** \name Core `foreach_path` API.
+ * \{ */
+
+typedef enum eBPathForeachFlag {
+ /** Flags controlling the behavior of the generic BPath API. */
+
+ /** Ensures the `absolute_base_path` member of #BPathForeachPathData is initialized properly with
+ * the path of the current .blend file. This can be used by the callbacks to convert relative
+ * paths to absolute ones. */
+ BKE_BPATH_FOREACH_PATH_ABSOLUTE = (1 << 0),
+ /** Skip paths of linked IDs. */
+ BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1),
+ /** Skip paths when their matching data is packed. */
+ BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2),
+ /* Skip weak reference paths. Those paths are typically 'nice to have' extra information, but are
+ * not used as actual source of data by the current .blend file.
+ *
+ * NOTE: Currently this only concerns the weak reference to a library file stored in
+ * `ID::library_weak_reference`. */
+ BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES = (1 << 5),
+
+ /** Flags not affecting the generic BPath API. Those may be used by specific IDTypeInfo
+ * `foreach_path` implementations and/or callbacks to implement specific behaviors. */
+
+ /** Skip paths where a single dir is used with an array of files, eg. sequence strip images or
+ * point-caches. In this case only use the first file path is processed.
+ *
+ * This is needed for directory manipulation callbacks which might otherwise modify the same
+ * directory multiple times. */
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE = (1 << 8),
+ /** Reload data (when the path is edited).
+ * \note Only used by Image IDType currently. */
+ BKE_BPATH_FOREACH_PATH_RELOAD_EDITED = (1 << 9),
+} eBPathForeachFlag;
+
+struct BPathForeachPathData;
+
+/** Callback used to iterate over an ID's file paths.
+ *
+ * \note `path`s parameters should be considered as having a maximal `FILE_MAX` string length.
+ *
+ * \return `true` if the path has been changed, and in that case, result should be written into
+ * `r_path_dst`. */
+typedef bool (*BPathForeachPathFunctionCallback)(struct BPathForeachPathData *bpath_data,
+ char *r_path_dst,
+ const char *path_src);
+
+/** Storage for common data needed across the BPath 'foreach_path' code. */
+typedef struct BPathForeachPathData {
+ struct Main *bmain;
+
+ BPathForeachPathFunctionCallback callback_function;
+ eBPathForeachFlag flag;
+
+ void *user_data;
+
+ /* 'Private' data, caller don't need to set those. */
+
+ /** The root to use as base for relative paths. Only set if `BKE_BPATH_FOREACH_PATH_ABSOLUTE`
+ * flag is set, NULL otherwise. */
+ const char *absolute_base_path;
+} BPathForeachPathData;
+
+/** Run `bpath_data.callback_function` on all paths contained in `id`. */
+void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, struct ID *id);
+
+/** Run `bpath_data.callback_function` on all paths of all IDs in `bmain`. */
+void BKE_bpath_foreach_path_main(BPathForeachPathData *bpath_data);
+
+/** \} */
+
+/** \name Helpers to handle common cases from `IDTypeInfo`'s `foreach_path` functions.
+ * \{ */
+
+/* TODO: Investigate using macros around those calls to check a bit better about actual
+ * strings/buffers length (e,g, with static asserts). */
+
+/**
+ * Run the callback on a path, replacing the content of the string as needed.
+ *
+ * \param path: A fixed, FILE_MAX-sized char buffer.
+ *
+ * \return true is \a path was modified, false otherwise.
+ */
+bool BKE_bpath_foreach_path_fixed_process(struct BPathForeachPathData *bpath_data, char *path);
+
+/**
+ * Run the callback on a (directory + file) path, replacing the content of the two strings as
+ * needed.
+ *
+ * \param path_dir: A fixed, FILE_MAXDIR-sized char buffer.
+ * \param path_file: A fixed, FILE_MAXFILE-sized char buffer.
+ *
+ * \return true is \a path_dir and/or \a path_file were modified, false otherwise.
+ */
+bool BKE_bpath_foreach_path_dirfile_fixed_process(struct BPathForeachPathData *bpath_data,
+ char *path_dir,
+ char *path_file);
+
+/**
+ * Run the callback on a path, replacing the content of the string as needed.
+ *
+ * \param path: A pointer to a MEM-allocated string. If modified, it will be freed and replaced by
+ * a new allocated string.
+ * \note path is expected to be FILE_MAX size or smaller.
+ *
+ * \return true is \a path was modified and re-allocated, false otherwise.
+ */
+bool BKE_bpath_foreach_path_allocated_process(struct BPathForeachPathData *bpath_data,
+ char **path);
+
+/** \} */
+
+/** \name High level features.
+ * \{ */
+
+/** Check for missing files. */
void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports);
+
+/** Recursively search into given search directory, for all file paths of all IDs in given \a
+ * bmain, and replace existing paths as needed.
+ *
+ * \note The search will happen into the whole search directory tree recursively (with a limit of
+ * MAX_DIR_RECURSE), if several files are found matching a searched filename, the biggest one will
+ * be used. This is so that things like thumbnails don't get selected instead of the actual image
+ * e.g.
+ *
+ * \param searchpath: The root directory in which the new filepaths should be searched for.
+ * \param find_all: If `true`, also search for files which current path is still valid, if `false`
+ * skip those still valid paths.
+ * */
void BKE_bpath_missing_files_find(struct Main *bmain,
const char *searchpath,
struct ReportList *reports,
const bool find_all);
+
+/** Rebase all relative file paths in given \a bmain from \a basedir_src to \a basedir_dst. */
void BKE_bpath_relative_rebase(struct Main *bmain,
const char *basedir_src,
const char *basedir_dst,
struct ReportList *reports);
+
+/** Make all absolute file paths in given \a bmain relative to given \a basedir. */
void BKE_bpath_relative_convert(struct Main *bmain,
const char *basedir,
struct ReportList *reports);
+
+/** Make all relative file paths in given \a bmain absolute, using given \a basedir as root. */
void BKE_bpath_absolute_convert(struct Main *bmain,
const char *basedir,
struct ReportList *reports);
+/** Temp backup of paths from all IDs in given \a bmain.
+ *
+ * \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free.
+ */
+void *BKE_bpath_list_backup(struct Main *bmain, const eBPathForeachFlag flag);
+
+/** Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain.
+ *
+ * \note This function assumes that the data in given Main did not change (no
+ * addition/deletion/re-ordering of IDs, or their file paths) since the call to
+ * #BKE_bpath_list_backup that generated the given \a path_list_handle. */
+void BKE_bpath_list_restore(struct Main *bmain,
+ const eBPathForeachFlag flag,
+ void *path_list_handle);
+
+/** Free the temp backup of paths in \a path_list_handle.
+ *
+ * \note This function assumes that the path list has already been restored with a call to
+ * #BKE_bpath_list_restore, and is therefore empty. */
+void BKE_bpath_list_free(void *path_list_handle);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 452a08bc9c8..a0f3733588a 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -39,49 +39,93 @@ struct UnifiedPaintSettings;
// enum eCurveMappingPreset;
-/* globals for brush execution */
+/* Globals for brush execution. */
+
void BKE_brush_system_init(void);
void BKE_brush_system_exit(void);
-/* datablock functions */
+/* Data-block functions. */
+
+/**
+ * \note Resulting brush will have two users: one as a fake user,
+ * another is assumed to be used by the caller.
+ */
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode);
+/**
+ * Add a new gp-brush.
+ */
struct Brush *BKE_brush_add_gpencil(struct Main *bmain,
struct ToolSettings *ts,
const char *name,
eObjectMode mode);
+/**
+ * Delete a Brush.
+ */
bool BKE_brush_delete(struct Main *bmain, struct Brush *brush);
+/**
+ * Add grease pencil settings.
+ */
void BKE_brush_init_gpencil_settings(struct Brush *brush);
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode);
void BKE_brush_sculpt_reset(struct Brush *brush);
+/**
+ * Create a set of grease pencil Drawing presets.
+ */
void BKE_brush_gpencil_paint_presets(struct Main *bmain,
struct ToolSettings *ts,
const bool reset);
+/**
+ * Create a set of grease pencil Vertex Paint presets.
+ */
void BKE_brush_gpencil_vertex_presets(struct Main *bmain,
struct ToolSettings *ts,
const bool reset);
+/**
+ * Create a set of grease pencil Sculpt Paint presets.
+ */
void BKE_brush_gpencil_sculpt_presets(struct Main *bmain,
struct ToolSettings *ts,
const bool reset);
+/**
+ * Create a set of grease pencil Weight Paint presets.
+ */
void BKE_brush_gpencil_weight_presets(struct Main *bmain,
struct ToolSettings *ts,
const bool reset);
void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, const short type);
-/* jitter */
void BKE_brush_jitter_pos(const struct Scene *scene,
struct Brush *brush,
const float pos[2],
float jitterpos[2]);
void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool mask);
-/* brush curve */
+/* Brush curve. */
+
+/**
+ * Library Operations
+ */
void BKE_brush_curve_preset(struct Brush *b, enum eCurveMappingPreset preset);
-float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len);
+/**
+ * Uses the brush curve control to find a strength value between 0 and 1.
+ */
+float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, const float len);
+/**
+ * Uses the brush curve control to find a strength value.
+ */
float BKE_brush_curve_strength(const struct Brush *br, float p, const float len);
-/* sampling */
+/* Sampling. */
+
+/**
+ * Generic texture sampler for 3D painting systems.
+ * point has to be either in region space mouse coordinates,
+ * or 3d world coordinates for 3D mapping.
+ *
+ * RGBA outputs straight alpha.
+ */
float BKE_brush_sample_tex_3d(const struct Scene *scene,
const struct Brush *br,
const float point[3],
@@ -94,15 +138,18 @@ float BKE_brush_sample_masktex(const struct Scene *scene,
const int thread,
struct ImagePool *pool);
-/* texture */
+/* Texture. */
+
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary);
-/* radial control */
+/**
+ * Radial control.
+ */
struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br,
bool secondary,
bool display_gradient);
-/* unified strength size and color */
+/* Unified strength size and color. */
const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush);
const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush);
@@ -127,12 +174,16 @@ bool BKE_brush_use_size_pressure(const struct Brush *brush);
bool BKE_brush_sculpt_has_secondary_color(const struct Brush *brush);
-/* scale unprojected radius to reflect a change in the brush's 2D size */
+/**
+ * Scale unprojected radius to reflect a change in the brush's 2D size.
+ */
void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
int new_brush_size,
int old_brush_size);
-/* scale brush size to reflect a change in the brush's unprojected radius */
+/**
+ * Scale brush size to reflect a change in the brush's unprojected radius.
+ */
void BKE_brush_scale_size(int *r_brush_size,
float new_unprojected_radius,
float old_unprojected_radius);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index bb95985ef4c..45c3a8ec159 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -48,7 +48,7 @@ struct BVHCache;
typedef struct BVHTreeFromEditMesh {
struct BVHTree *tree;
- /** Default callbacks to bvh nearest and ray-cast. */
+ /** Default callbacks to BVH nearest and ray-cast. */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
@@ -65,7 +65,7 @@ typedef struct BVHTreeFromEditMesh {
typedef struct BVHTreeFromMesh {
struct BVHTree *tree;
- /** Default callbacks to bvh nearest and ray-cast. */
+ /** Default callbacks to BVH nearest and ray-cast. */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
@@ -105,7 +105,7 @@ typedef enum BVHCacheType {
} BVHCacheType;
/**
- * Builds a bvh tree where nodes are the relevant elements of the given mesh.
+ * Builds a BVH tree where nodes are the relevant elements of the given mesh.
* Configures #BVHTreeFromMesh.
*
* The tree is build in mesh space coordinates, this means special care must be made on queries
@@ -113,11 +113,14 @@ typedef enum BVHCacheType {
* Reason for this is that bvh_from_mesh_* can use a cache in some cases and so it
* becomes possible to reuse a #BVHTree.
*
- * free_bvhtree_from_mesh should be called when the tree is no longer needed.
+ * #free_bvhtree_from_mesh should be called when the tree is no longer needed.
*/
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the vertices of the given `em`.
+ */
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *mask,
@@ -129,11 +132,18 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given vertices (NOTE: does not copy given `vert`!).
+ * \param vert_allocated: if true, vert freeing will be done when freeing data.
+ * \param verts_mask: if not null, true elements give which vert to add to BVH-tree.
+ * \param verts_num_active: if >= 0, number of active verts to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
const int verts_num,
const bool vert_allocated,
- const BLI_bitmap *mask,
+ const BLI_bitmap *verts_mask,
int verts_num_active,
float epsilon,
int tree_type,
@@ -145,6 +155,9 @@ BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the edges of the given `em`.
+ */
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *edges_mask,
@@ -156,6 +169,14 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given edges.
+ * \param vert, vert_allocated: if true, elem freeing will be done when freeing data.
+ * \param edge, edge_allocated: if true, elem freeing will be done when freeing data.
+ * \param edges_mask: if not null, true elements give which vert to add to BVH-tree.
+ * \param edges_num_active: if >= 0, number of active edges to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
@@ -171,13 +192,22 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the given tessellated faces
+ * (NOTE: does not copy given mfaces!).
+ * \param vert_allocated: if true, vert freeing will be done when freeing data.
+ * \param face_allocated: if true, face freeing will be done when freeing data.
+ * \param faces_mask: if not null, true elements give which faces to add to BVH-tree.
+ * \param faces_num_active: if >= 0, number of active faces to add to BVH-tree
+ * (else will be computed from mask).
+ */
BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
const struct MFace *face,
const int numFaces,
const bool face_allocated,
- const BLI_bitmap *mask,
+ const BLI_bitmap *faces_mask,
int faces_num_active,
float epsilon,
int tree_type,
@@ -189,6 +219,9 @@ BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
+/**
+ * Builds a BVH-tree where nodes are the `looptri` faces of the given `bm`.
+ */
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const BLI_bitmap *mask,
@@ -200,6 +233,11 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds a BVH-tree where nodes are the looptri faces of the given mesh.
+ *
+ * \note for edit-mesh this is currently a duplicate of #bvhtree_from_mesh_faces_ex
+ */
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
@@ -217,11 +255,20 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
+/**
+ * Builds or queries a BVH-cache for the cache BVH-tree of the request type.
+ *
+ * \note This function only fills a cache, and therefore the mesh argument can
+ * be considered logically const. Concurrent access is protected by a mutex.
+ */
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const struct Mesh *mesh,
const BVHCacheType bvh_cache_type,
const int tree_type);
+/**
+ * Builds or queries a BVH-cache for the cache BVH-tree of the request type.
+ */
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
@@ -230,9 +277,12 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
ThreadMutex *mesh_eval_mutex);
/**
- * Frees data allocated by a call to bvhtree_from_mesh_*.
+ * Frees data allocated by a call to `bvhtree_from_editmesh_*`.
*/
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data);
+/**
+ * Frees data allocated by a call to `bvhtree_from_mesh_*`.
+ */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
/**
@@ -272,6 +322,9 @@ void free_bvhtree_from_pointcloud(struct BVHTreeFromPointCloud *data);
bool bvhcache_has_tree(const struct BVHCache *bvh_cache, const BVHTree *tree);
struct BVHCache *bvhcache_init(void);
+/**
+ * Frees a BVH-cache.
+ */
void bvhcache_free(struct BVHCache *bvh_cache);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index 836597f95da..ac621bfdcb9 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -61,6 +61,12 @@ void BKE_cachefile_reader_open(struct CacheFile *cache_file,
const char *object_path);
void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader);
+/**
+ * Determine whether the #CacheFile should use a render engine procedural. If so, data is not read
+ * from the file and bounding boxes are used to represent the objects in the Scene.
+ * Render engines will receive the bounding box as a placeholder but can instead
+ * load the data directly if they support it.
+ */
bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file,
struct Scene *scene,
const int dag_eval_mode);
diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
index 7c518f33c89..c125b081b49 100644
--- a/source/blender/blenkernel/BKE_callbacks.h
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -133,6 +133,9 @@ void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt);
void BKE_callback_global_init(void);
+/**
+ * Call on application exit.
+ */
void BKE_callback_global_finalize(void);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index b42fcbe7808..45bfef82302 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -37,22 +37,26 @@ struct Scene;
struct View3D;
struct rctf;
-/* Camera Datablock */
+/* Camera Data-block */
void *BKE_camera_add(struct Main *bmain, const char *name);
/* Camera Usage */
+/**
+ * Get the camera's DOF value, takes the DOF object into account.
+ */
float BKE_camera_object_dof_distance(struct Object *ob);
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey);
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y);
-/* Camera Parameters:
+/**
+ * Camera Parameters:
*
* Intermediate struct for storing camera parameters from various sources,
- * to unify computation of viewplane, window matrix, ... */
-
+ * to unify computation of view-plane, window matrix, ... etc.
+ */
typedef struct CameraParams {
/* lens */
bool is_ortho;
@@ -84,7 +88,7 @@ typedef struct CameraParams {
float winmat[4][4];
} CameraParams;
-/* values for CameraParams.zoom, need to be taken into account for some operations */
+/* Values for CameraParams.zoom, need to be taken into account for some operations. */
#define CAMERA_PARAM_ZOOM_INIT_CAMOB 1.0f
#define CAMERA_PARAM_ZOOM_INIT_PERSP 2.0f
@@ -97,6 +101,9 @@ void BKE_camera_params_from_view3d(CameraParams *params,
void BKE_camera_params_compute_viewplane(
CameraParams *params, int winx, int winy, float aspx, float aspy);
+/**
+ * View-plane is assumed to be already computed.
+ */
void BKE_camera_params_compute_matrix(CameraParams *params);
/* Camera View Frame */
@@ -114,6 +121,11 @@ void BKE_camera_view_frame(const struct Scene *scene,
const struct Camera *camera,
float r_vec[4][3]);
+/**
+ * \param r_scale: only valid/useful for orthographic cameras.
+ *
+ * \note Don't move the camera, just yield the fit location.
+ */
bool BKE_camera_view_frame_fit_to_scene(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *camera_ob,
@@ -128,9 +140,15 @@ bool BKE_camera_view_frame_fit_to_coords(const struct Depsgraph *depsgraph,
/* Camera multi-view API */
+/**
+ * Returns the camera to be used for render.
+ */
struct Object *BKE_camera_multiview_render(const struct Scene *scene,
struct Object *camera,
const char *viewname);
+/**
+ * The view matrix is used by the viewport drawing, it is basically the inverted model matrix.
+ */
void BKE_camera_multiview_view_matrix(const struct RenderData *rd,
const struct Object *camera,
const bool is_left,
@@ -158,6 +176,7 @@ bool BKE_camera_multiview_spherical_stereo(const struct RenderData *rd,
const struct Object *camera);
/* Camera background image API */
+
struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam);
void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic);
void BKE_camera_background_image_clear(struct Camera *cam);
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index dbf285feb92..ee73b926886 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -235,7 +235,9 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph,
/* cloth.c */
/* Needed for modifier.c */
+/** Frees all. */
void cloth_free_modifier_extern(struct ClothModifierData *clmd);
+/** Frees all. */
void cloth_free_modifier(struct ClothModifierData *clmd);
void clothModifier_do(struct ClothModifierData *clmd,
struct Depsgraph *depsgraph,
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 2c7143be60e..46c1fe0d33d 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -54,20 +54,51 @@ typedef struct CollectionParent {
/* Collections */
+/**
+ * Add a collection to a collection ListBase and synchronize all render layers
+ * The ListBase is NULL when the collection is to be added to the master collection
+ */
struct Collection *BKE_collection_add(struct Main *bmain,
struct Collection *parent,
const char *name);
+/**
+ * Add \a collection_dst to all scene collections that reference object \a ob_src is in.
+ * Used to replace an instance object with a collection (library override operator).
+ *
+ * Logic is very similar to #BKE_collection_object_add_from().
+ */
void BKE_collection_add_from_object(struct Main *bmain,
struct Scene *scene,
const struct Object *ob_src,
struct Collection *collection_dst);
+/**
+ * Add \a collection_dst to all scene collections that reference collection \a collection_src is
+ * in.
+ *
+ * Logic is very similar to #BKE_collection_object_add_from().
+ */
void BKE_collection_add_from_collection(struct Main *bmain,
struct Scene *scene,
struct Collection *collection_src,
struct Collection *collection_dst);
+/**
+ * Free (or release) any data used by this collection (does not free the collection itself).
+ */
void BKE_collection_free_data(struct Collection *collection);
+/**
+ * Remove a collection, optionally removing its child objects or moving
+ * them to parent collections.
+ */
bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy);
+/**
+ * Make a deep copy (aka duplicate) of the given collection and all of its children, recursively.
+ *
+ * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a
+ * #LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is
+ * responsible to reconstruct collection dependencies information's
+ * (i.e. call #BKE_main_collection_sync).
+ */
struct Collection *BKE_collection_duplicate(struct Main *bmain,
struct Collection *parent,
struct Collection *collection,
@@ -91,28 +122,60 @@ struct Collection *BKE_collection_object_find(struct Main *bmain,
struct Object *ob);
bool BKE_collection_is_empty(const struct Collection *collection);
+/**
+ * Add object to collection
+ */
bool BKE_collection_object_add(struct Main *bmain,
struct Collection *collection,
struct Object *ob);
+/**
+ * Add \a ob_dst to all scene collections that reference object \a ob_src is in.
+ * Used for copying objects.
+ *
+ * Logic is very similar to #BKE_collection_add_from_object()
+ */
void BKE_collection_object_add_from(struct Main *bmain,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst);
+/**
+ * Remove object from collection.
+ */
bool BKE_collection_object_remove(struct Main *bmain,
struct Collection *collection,
struct Object *object,
const bool free_us);
+/**
+ * Move object from a collection into another
+ *
+ * If source collection is NULL move it from all the existing collections.
+ */
void BKE_collection_object_move(struct Main *bmain,
struct Scene *scene,
struct Collection *collection_dst,
struct Collection *collection_src,
struct Object *ob);
+/**
+ * Remove object from all collections of scene
+ */
bool BKE_scene_collections_object_remove(struct Main *bmain,
struct Scene *scene,
struct Object *object,
const bool free_us);
void BKE_collections_object_remove_nulls(struct Main *bmain);
+/**
+ * Remove all NULL children from parent collections of changed \a collection.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ *
+ * \note caller must ensure #BKE_main_collection_sync_remap() is called afterwards!
+ *
+ * \param parent_collection: The collection owning the pointers that were remapped. May be \a NULL,
+ * in which case whole \a bmain database of collections is checked.
+ * \param child_collection: The collection that was remapped to another pointer. May be \a NULL,
+ * in which case whole \a bmain database of collections is checked.
+ */
void BKE_collections_child_remove_nulls(struct Main *bmain,
struct Collection *parent_collection,
struct Collection *child_collection);
@@ -136,9 +199,24 @@ struct Base *BKE_collection_or_layer_objects(const struct ViewLayer *view_layer,
/* Editing. */
+/**
+ * Return Scene Collection for a given index.
+ *
+ * The index is calculated from top to bottom counting the children before the siblings.
+ */
struct Collection *BKE_collection_from_index(struct Scene *scene, const int index);
+/**
+ * The automatic/fallback name of a new collection.
+ */
void BKE_collection_new_name_get(struct Collection *collection_parent, char *rname);
+/**
+ * The name to show in the interface.
+ */
const char *BKE_collection_ui_name_get(struct Collection *collection);
+/**
+ * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
+ * Return true if any object was selected.
+ */
bool BKE_collection_objects_select(struct ViewLayer *view_layer,
struct Collection *collection,
bool deselect);
@@ -162,13 +240,36 @@ bool BKE_collection_move(struct Main *bmain,
bool relative_after,
struct Collection *collection);
+/**
+ * Find potential cycles in collections.
+ *
+ * \param new_ancestor: the potential new owner of given \a collection,
+ * or the collection to check if the later is NULL.
+ * \param collection: the collection we want to add to \a new_ancestor,
+ * may be NULL if we just want to ensure \a new_ancestor does not already have cycles.
+ * \return true if a cycle is found.
+ */
bool BKE_collection_cycle_find(struct Collection *new_ancestor, struct Collection *collection);
+/**
+ * Find and fix potential cycles in collections.
+ *
+ * \param collection: The collection to check for existing cycles.
+ * \return true if cycles are found and fixed.
+ */
bool BKE_collection_cycles_fix(struct Main *bmain, struct Collection *collection);
bool BKE_collection_has_collection(const struct Collection *parent,
const struct Collection *collection);
+/**
+ * Rebuild parent relationships from child ones, for all children of given \a collection.
+ *
+ * \note Given collection is assumed to already have valid parents.
+ */
void BKE_collection_parent_relations_rebuild(struct Collection *collection);
+/**
+ * Rebuild parent relationships from child ones, for all collections in given \a bmain.
+ */
void BKE_main_collections_parent_relations_rebuild(struct Main *bmain);
/* .blend file I/O */
@@ -224,6 +325,10 @@ typedef void (*BKE_scene_collections_Cb)(struct Collection *ob, void *data);
/* Iteration over collections in scene. */
+/**
+ * Only use this in non-performance critical situations
+ * (it iterates over all scene collections twice)
+ */
void BKE_scene_collections_iterator_begin(struct BLI_Iterator *iter, void *data_in);
void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter);
void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter);
@@ -232,6 +337,13 @@ void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in);
void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter);
void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
+/**
+ * Generate a new #GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
+ * all collections of given `scene`.
+ *
+ * \note This will include objects without a base currently
+ * (because they would belong to excluded collections only e.g.).
+ */
struct GSet *BKE_scene_objects_as_gset(struct Scene *scene, struct GSet *objects_gset);
#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance) \
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index 2c21b7355d6..71929d1797c 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -116,8 +116,11 @@ void bvhtree_update_from_mvert(struct BVHTree *bvhtree,
/////////////////////////////////////////////////
-/* move Collision modifier object inter-frame with step = [0,1]
- * defined in collisions.c */
+/**
+ * Move Collision modifier object inter-frame with step = [0,1]
+ *
+ * \param step: is limited from 0 (frame start position) to 1 (frame end position).
+ */
void collision_move_object(struct CollisionModifierData *collmd,
const float step,
const float prevstep,
@@ -135,6 +138,11 @@ typedef struct CollisionRelation {
struct Object *ob;
} CollisionRelation;
+/**
+ * Create list of collision relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of colliders during evaluation.
+ */
struct ListBase *BKE_collision_relations_create(struct Depsgraph *depsgraph,
struct Collection *collection,
unsigned int modifier_type);
@@ -142,6 +150,10 @@ void BKE_collision_relations_free(struct ListBase *relations);
/* Collision object lists for physics simulation evaluation. */
+/**
+ * Create effective list of colliders from relations built beforehand.
+ * Self will be excluded.
+ */
struct Object **BKE_collision_objects_create(struct Depsgraph *depsgraph,
struct Object *self,
struct Collection *collection,
@@ -155,6 +167,10 @@ typedef struct ColliderCache {
struct CollisionModifierData *collmd;
} ColliderCache;
+/**
+ * Create effective list of colliders from relations built beforehand.
+ * Self will be excluded.
+ */
struct ListBase *BKE_collider_cache_create(struct Depsgraph *depsgraph,
struct Object *self,
struct Collection *collection);
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 109947cece4..17fb48cdd27 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -59,40 +59,85 @@ enum {
CURVEMAP_SLOPE_POS_NEG = 2,
};
+/**
+ * Reset the view for current curve.
+ */
void BKE_curvemapping_reset_view(struct CurveMapping *cumap);
void BKE_curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int preset, int slope);
+/**
+ * Removes with flag set.
+ */
void BKE_curvemap_remove(struct CurveMap *cuma, const short flag);
+/**
+ * Remove specified point.
+ */
bool BKE_curvemap_remove_point(struct CurveMap *cuma, struct CurveMapPoint *cmp);
struct CurveMapPoint *BKE_curvemap_insert(struct CurveMap *cuma, float x, float y);
+/**
+ * \param type: #eBezTriple_Handle
+ */
void BKE_curvemap_handle_set(struct CurveMap *cuma, int type);
+/**
+ * \note only does current curvemap!.
+ */
void BKE_curvemapping_changed(struct CurveMapping *cumap, const bool rem_doubles);
void BKE_curvemapping_changed_all(struct CurveMapping *cumap);
-/* call before _all_ evaluation functions */
+/**
+ * Call before _all_ evaluation functions.
+ */
void BKE_curvemapping_init(struct CurveMapping *cumap);
-/* keep these (const CurveMap) - to help with thread safety */
-/* single curve, no table check */
+/**
+ * Keep these `const CurveMap` - to help with thread safety.
+ * \note Single curve, no table check.
+ * \note Table should be verified.
+ */
float BKE_curvemap_evaluateF(const struct CurveMapping *cumap,
const struct CurveMap *cuma,
float value);
-/* single curve, with table check */
+/**
+ * Single curve, with table check.
+ * Works with curve 'cur'.
+ */
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value);
+/**
+ * Vector case.
+ */
void BKE_curvemapping_evaluate3F(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
+/**
+ * RGB case, no black/white points, no pre-multiply.
+ */
void BKE_curvemapping_evaluateRGBF(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
+/**
+ * Byte version of #BKE_curvemapping_evaluateRGBF.
+ */
void BKE_curvemapping_evaluate_premulRGB(const struct CurveMapping *cumap,
unsigned char vecout_byte[3],
const unsigned char vecin_byte[3]);
+/**
+ * Same as #BKE_curvemapping_evaluate_premulRGBF
+ * but black/bwmul are passed as args for the compositor
+ * where they can change per pixel.
+ *
+ * Use in conjunction with #BKE_curvemapping_set_black_white_ex
+ *
+ * \param black: Use instead of cumap->black
+ * \param bwmul: Use instead of cumap->bwmul
+ */
void BKE_curvemapping_evaluate_premulRGBF_ex(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3],
const float black[3],
const float bwmul[3]);
+/**
+ * RGB with black/white points and pre-multiply. tables are checked.
+ */
void BKE_curvemapping_evaluate_premulRGBF(const struct CurveMapping *cumap,
float vecout[3],
const float vecin[3]);
@@ -100,12 +145,18 @@ bool BKE_curvemapping_RGBA_does_something(const struct CurveMapping *cumap);
void BKE_curvemapping_table_F(const struct CurveMapping *cumap, float **array, int *size);
void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array, int *size);
-/* non-const, these modify the curve */
-void BKE_curvemapping_premultiply(struct CurveMapping *cumap, int restore);
+/**
+ * Call when you do images etc, needs restore too. also verifies tables.
+ * non-const (these modify the curve).
+ */
+void BKE_curvemapping_premultiply(struct CurveMapping *cumap, bool restore);
void BKE_curvemapping_blend_write(struct BlendWriter *writer, const struct CurveMapping *cumap);
void BKE_curvemapping_curves_blend_write(struct BlendWriter *writer,
const struct CurveMapping *cumap);
+/**
+ * \note `cumap` itself has been read already.
+ */
void BKE_curvemapping_blend_read(struct BlendDataReader *reader, struct CurveMapping *cumap);
void BKE_histogram_update_sample_line(struct Histogram *hist,
@@ -123,16 +174,20 @@ void BKE_color_managed_display_settings_init(struct ColorManagedDisplaySettings
void BKE_color_managed_display_settings_copy(struct ColorManagedDisplaySettings *new_settings,
const struct ColorManagedDisplaySettings *settings);
-/* Initialize view settings to be best suitable for render type of viewing.
+/**
+ * Initialize view settings to be best suitable for render type of viewing.
* This will use default view transform from the OCIO configuration if none
- * is specified. */
+ * is specified.
+ */
void BKE_color_managed_view_settings_init_render(
struct ColorManagedViewSettings *settings,
const struct ColorManagedDisplaySettings *display_settings,
const char *view_transform);
-/* Initialize view settings which are best suitable for viewing non-render
- * images. For example,s movie clips while tracking. */
+/**
+ * Initialize view settings which are best suitable for viewing non-render images.
+ * For example,s movie clips while tracking.
+ */
void BKE_color_managed_view_settings_init_default(
struct ColorManagedViewSettings *settings,
const struct ColorManagedDisplaySettings *display_settings);
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 784b395dfa5..1f59efbb0f3 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -45,7 +45,7 @@ extern "C" {
typedef struct bConstraintOb {
/** to get evaluated armature. */
struct Depsgraph *depsgraph;
- /** for system time, part of deglobalization, code nicer later with local time (ton) */
+ /** for system time, part of de-globalization, code nicer later with local time (ton) */
struct Scene *scene;
/** if pchan, then armature that it comes from, otherwise constraint owner */
struct Object *ob;
@@ -61,7 +61,7 @@ typedef struct bConstraintOb {
/** type of owner. */
short type;
- /** rotation order for constraint owner (as defined in eEulerRotationOrders in BLI_math.h) */
+ /** rotation order for constraint owner (as defined in #eEulerRotationOrders in BLI_math.h) */
short rotOrder;
} bConstraintOb;
@@ -76,7 +76,7 @@ typedef void (*ConstraintIDFunc)(struct bConstraint *con,
/* ....... */
/**
- * Constraint Type-Info (shorthand in code = cti):
+ * Constraint Type-Info (shorthand in code = `cti`):
* This struct provides function pointers for runtime, so that functions can be
* written more generally (with fewer/no special exceptions for various constraints).
*
@@ -138,49 +138,107 @@ typedef struct bConstraintTypeInfo {
} bConstraintTypeInfo;
/* Function Prototypes for bConstraintTypeInfo's */
+
+/**
+ * This function should always be used to get the appropriate type-info, as it
+ * has checks which prevent segfaults in some weird cases.
+ */
const bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con);
+/**
+ * This function should be used for getting the appropriate type-info when only
+ * a constraint type is known.
+ */
const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
/* ---------------------------------------------------------------------------- */
/* Constraint function prototypes */
+
+/**
+ * Find the first available, non-duplicate name for a given constraint.
+ */
void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
+/**
+ * Allocate and duplicate a single constraint, outside of any object/pose context.
+ */
struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src,
const int flag,
const bool do_extern);
+/**
+ * Add a copy of the given constraint for the given bone.
+ */
struct bConstraint *BKE_constraint_copy_for_pose(struct Object *ob,
struct bPoseChannel *pchan,
struct bConstraint *src);
+/**
+ * Add a copy of the given constraint for the given object.
+ */
struct bConstraint *BKE_constraint_copy_for_object(struct Object *ob, struct bConstraint *src);
void BKE_constraints_free(struct ListBase *list);
+/**
+ * Free all constraints from a constraint-stack.
+ */
void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user);
void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern);
+/**
+ * Duplicate all of the constraints in a constraint stack.
+ */
void BKE_constraints_copy_ex(struct ListBase *dst,
const struct ListBase *src,
const int flag,
bool do_extern);
+/**
+ * Run the given callback on all ID-blocks in list of constraints.
+ */
void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata);
void BKE_constraint_free_data(struct bConstraint *con);
+/**
+ * Free data of a specific constraint if it has any info.
+ * Be sure to run #BIK_clear_data() when freeing an IK constraint,
+ * unless #DAG_relations_tag_update is called.
+ */
void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user);
bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *ct);
/* Constraint API function prototypes */
+
+/**
+ * Finds the 'active' constraint in a constraint stack.
+ */
struct bConstraint *BKE_constraints_active_get(struct ListBase *list);
+/**
+ * Set the given constraint as the active one (clearing all the others).
+ */
void BKE_constraints_active_set(ListBase *list, struct bConstraint *con);
struct bConstraint *BKE_constraints_find_name(struct ListBase *list, const char *name);
+/**
+ * Finds the constraint that owns the given target within the object.
+ */
struct bConstraint *BKE_constraint_find_from_target(struct Object *ob,
struct bConstraintTarget *tgt,
struct bPoseChannel **r_pchan);
+/**
+ * Check whether given constraint is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param con: May be NULL, in which case we consider it as a non-local constraint case.
+ */
bool BKE_constraint_is_nonlocal_in_liboverride(const struct Object *ob,
const struct bConstraint *con);
+/**
+ * Add new constraint for the given object.
+ */
struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type);
+/**
+ * Add new constraint for the given bone.
+ */
struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob,
struct bPoseChannel *pchan,
const char *name,
@@ -190,8 +248,14 @@ bool BKE_constraint_remove_ex(ListBase *list,
struct Object *ob,
struct bConstraint *con,
bool clear_dep);
+/**
+ * Remove the specified constraint from the given constraint stack.
+ */
bool BKE_constraint_remove(ListBase *list, struct bConstraint *con);
+/**
+ * Apply the specified constraint in the given constraint stack.
+ */
bool BKE_constraint_apply_for_object(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -217,17 +281,38 @@ bool BKE_constraint_apply_and_remove_for_pose(struct Depsgraph *depsgraph,
void BKE_constraint_panel_expand(struct bConstraint *con);
/* Constraints + Proxies function prototypes */
+
+/**
+ * Rescue all constraints tagged as being #CONSTRAINT_PROXY_LOCAL
+ * (i.e. added to bone that's proxy-synced in this file).
+ */
void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *src);
+/**
+ * Returns if the owner of the constraint is proxy-protected.
+ */
bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan);
/* Constraint Evaluation function prototypes */
+
+/**
+ * This function MEM_calloc's a #bConstraintOb struct,
+ * that will need to be freed after evaluation.
+ */
struct bConstraintOb *BKE_constraints_make_evalob(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
void *subdata,
short datatype);
+/**
+ * Cleanup after constraint evaluation.
+ */
void BKE_constraints_clear_evalob(struct bConstraintOb *cob);
+/**
+ * This function is responsible for the correct transformations/conversions
+ * of a matrix from one space to another for constraint evaluation.
+ * For now, this is only implemented for objects and pose-channels.
+ */
void BKE_constraint_mat_convertspace(struct Object *ob,
struct bPoseChannel *pchan,
struct bConstraintOb *cob,
@@ -236,6 +321,14 @@ void BKE_constraint_mat_convertspace(struct Object *ob,
short to,
const bool keep_scale);
+/**
+ * This function is a relic from the prior implementations of the constraints system, when all
+ * constraints either had one or no targets. It used to be called during the main constraint
+ * solving loop, but is now only used for the remaining cases for a few constraints.
+ *
+ * None of the actual calculations of the matrices should be done here! Also, this function is
+ * not to be used by any new constraints, particularly any that have multiple targets.
+ */
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
struct Scene *scene,
struct bConstraint *con,
@@ -244,12 +337,22 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
void *ownerdata,
float mat[4][4],
float ctime);
+/**
+ * Get the list of targets required for solving a constraint.
+ */
void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
struct bConstraint *con,
struct bConstraintOb *ob,
struct ListBase *targets,
float ctime);
void BKE_constraint_custom_object_space_get(float r_mat[4][4], struct bConstraint *con);
+/**
+ * This function is called whenever constraints need to be evaluated. Currently, all
+ * constraints that can be evaluated are every time this gets run.
+ *
+ * #BKE_constraints_make_evalob and #BKE_constraints_clear_evalob should be called before and
+ * after running this function, to sort out cob.
+ */
void BKE_constraints_solve(struct Depsgraph *depsgraph,
struct ListBase *conlist,
struct bConstraintOb *cob,
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index b0705ff411f..ac864c7f82c 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -247,6 +247,12 @@ PointerRNA CTX_data_pointer_get_type_silent(const bContext *C,
const char *member,
StructRNA *type);
ListBase CTX_data_collection_get(const bContext *C, const char *member);
+/**
+ * \param C: Context.
+ * \param use_store: Use 'C->wm.store'.
+ * \param use_rna: Use Include the properties from 'RNA_Context'.
+ * \param use_all: Don't skip values (currently only "scene").
+ */
ListBase CTX_data_dir_get_ex(const bContext *C,
const bool use_store,
const bool use_rna,
@@ -297,6 +303,13 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas
struct Main *CTX_data_main(const bContext *C);
struct Scene *CTX_data_scene(const bContext *C);
+/**
+ * This is tricky. Sometimes the user overrides the render_layer
+ * but not the scene_collection. In this case what to do?
+ *
+ * If the scene_collection is linked to the #ViewLayer we use it.
+ * Otherwise we fallback to the active one of the #ViewLayer.
+ */
struct LayerCollection *CTX_data_layer_collection(const bContext *C);
struct Collection *CTX_data_collection(const bContext *C);
struct ViewLayer *CTX_data_view_layer(const bContext *C);
@@ -367,28 +380,34 @@ struct AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid);
bool CTX_wm_interface_locked(const bContext *C);
-/* Gets pointer to the dependency graph.
+/**
+ * Gets pointer to the dependency graph.
* If it doesn't exist yet, it will be allocated.
*
* The result dependency graph is NOT guaranteed to be up-to-date neither from relation nor from
* evaluated data points of view.
*
- * NOTE: Can not be used if access to a fully evaluated datablock is needed. */
+ * \note Can not be used if access to a fully evaluated data-block is needed.
+ */
struct Depsgraph *CTX_data_depsgraph_pointer(const bContext *C);
-/* Get dependency graph which is expected to be fully evaluated.
+/**
+ * Get dependency graph which is expected to be fully evaluated.
*
* In the release builds it is the same as CTX_data_depsgraph_pointer(). In the debug builds extra
* sanity checks are done. Additionally, this provides more semantic meaning to what is exactly
- * expected to happen. */
+ * expected to happen.
+ */
struct Depsgraph *CTX_data_expect_evaluated_depsgraph(const bContext *C);
-/* Gets fully updated and evaluated dependency graph.
+/**
+ * Gets fully updated and evaluated dependency graph.
*
* All the relations and evaluated objects are guaranteed to be up to date.
*
- * NOTE: Will be expensive if there are relations or objects tagged for update.
- * NOTE: If there are pending updates depsgraph hooks will be invoked. */
+ * \note Will be expensive if there are relations or objects tagged for update.
+ * \note If there are pending updates depsgraph hooks will be invoked.
+ */
struct Depsgraph *CTX_data_ensure_evaluated_depsgraph(const bContext *C);
/* Will Return NULL if depsgraph is not allocated yet.
diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h
index b95be70379f..f5266ed7a10 100644
--- a/source/blender/blenkernel/BKE_crazyspace.h
+++ b/source/blender/blenkernel/BKE_crazyspace.h
@@ -33,6 +33,10 @@ struct Object;
struct Scene;
/* crazyspace.c */
+
+/**
+ * Disable subdivision-surface temporal, get mapped coordinates, and enable it.
+ */
float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph,
struct Object *obedit))[3];
void BKE_crazyspace_set_quats_editmesh(struct BMEditMesh *em,
@@ -44,6 +48,10 @@ void BKE_crazyspace_set_quats_mesh(struct Mesh *me,
float (*origcos)[3],
float (*mappedcos)[3],
float (*quats)[4]);
+/**
+ * Returns an array of deform matrices for crazy-space correction,
+ * and the number of modifiers left.
+ */
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
struct Scene *,
struct Object *,
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index e98a9b2b1fd..329046ad494 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -55,6 +55,9 @@ uint32_t BKE_cryptomatte_asset_hash(struct CryptomatteSession *session,
const char *layer_name,
const struct Object *object);
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
+/**
+ * Find an ID in the given main that matches the given encoded float.
+ */
bool BKE_cryptomatte_find_name(const struct CryptomatteSession *session,
const float encoded_hash,
char *r_name,
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index 9e205d01765..08536ecccbd 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -37,7 +37,8 @@ struct ID;
namespace blender::bke::cryptomatte {
-/* Format to a cryptomatte meta data key.
+/**
+ * Format to a cryptomatte meta data key.
*
* Cryptomatte stores meta data. The keys are formatted containing a hash that
* is generated from its layer name.
@@ -48,7 +49,8 @@ namespace blender::bke::cryptomatte {
std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name,
const StringRefNull key_name);
-/* Extract the cryptomatte layer name from the given `render_pass_name`.
+/**
+ * Extract the cryptomatte layer name from the given `render_pass_name`.
*
* Cryptomatte passes are formatted with a trailing number for storing multiple samples that belong
* to the same cryptomatte layer. This function would remove the trailing numbers to determine the
@@ -59,7 +61,7 @@ std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name,
* A render_pass_name could be 'View Layer.CryptoMaterial02'. The cryptomatte layer would be 'View
* Layer.CryptoMaterial'.
*
- * NOTE: The return type is a sub-string of `render_pass_name` and therefore cannot outlive the
+ * \note The return type is a sub-string of `render_pass_name` and therefore cannot outlive the
* `render_pass_name` internal data.
*/
StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name);
@@ -72,6 +74,18 @@ struct CryptomatteHash {
static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
std::string hex_encoded() const;
+ /**
+ Convert a cryptomatte hash to a float.
+ *
+ * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
+ * cryptomatte specification. See Floating point conversion section in
+ * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
+ *
+ * The conversion uses as many 32 bit floating point values as possible to minimize hash
+ * collisions. Unfortunately not all 32 bits can be used as NaN and Inf can be problematic.
+ *
+ * Note that this conversion assumes to be running on a L-endian system.
+ */
float float_encoded() const;
};
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 5e474c0c5ac..713ee8cac01 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -75,8 +75,8 @@ typedef struct CVKeyIndex {
#define SEGMENTSV(nu) (((nu)->flagv & CU_NURB_CYCLIC) ? (nu)->pntsv : (nu)->pntsv - 1)
#define CU_DO_RADIUS(cu, nu) \
- ((((cu)->flag & (CU_PATH_RADIUS | CU_3D)) || (cu)->bevobj || (cu)->ext1 != 0.0f || \
- (cu)->ext2 != 0.0f) ? \
+ ((((cu)->flag & (CU_PATH_RADIUS | CU_3D)) || (cu)->bevobj || (cu)->extrude != 0.0f || \
+ (cu)->bevel_radius != 0.0f) ? \
1 : \
0)
@@ -86,6 +86,9 @@ typedef struct CVKeyIndex {
#define CU_DO_2DFILL(cu) (CU_IS_2D(cu) && (((cu)->flag & (CU_FRONT | CU_BACK)) != 0))
/* ** Curve ** */
+/**
+ * Frees edit-curve entirely.
+ */
void BKE_curve_editfont_free(struct Curve *cu);
void BKE_curve_init(struct Curve *cu, const short curve_type);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
@@ -98,6 +101,8 @@ struct BoundBox *BKE_curve_boundbox_get(struct Object *ob);
void BKE_curve_texspace_calc(struct Curve *cu);
void BKE_curve_texspace_ensure(struct Curve *cu);
+/* Basic vertex data functions. */
+
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]);
@@ -119,14 +124,26 @@ void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsig
void BKE_curve_smooth_flag_set(struct Curve *cu, const bool use_smooth);
+/**
+ * \return edit-nurbs or normal nurbs list.
+ */
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
const ListBase *BKE_curve_nurbs_get_for_read(const struct Curve *cu);
int BKE_curve_nurb_vert_index_get(const struct Nurb *nu, const void *vert);
void BKE_curve_nurb_active_set(struct Curve *cu, const struct Nurb *nu);
struct Nurb *BKE_curve_nurb_active_get(struct Curve *cu);
+/**
+ * Get active vert for curve.
+ */
void *BKE_curve_vert_active_get(struct Curve *cu);
+/**
+ * Set active nurb and active vert for curve.
+ */
void BKE_curve_nurb_vert_active_set(struct Curve *cu, const struct Nurb *nu, const void *vert);
+/**
+ * Get points to the active nurb and active vert for curve.
+ */
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert);
void BKE_curve_nurb_vert_active_validate(struct Curve *cu);
@@ -152,6 +169,9 @@ void BKE_curve_nurbs_key_vert_tilts_apply(struct ListBase *lb, const float *key)
void BKE_curve_editNurb_keyIndex_delCV(struct GHash *keyindex, const void *cv);
void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex);
void BKE_curve_editNurb_free(struct Curve *cu);
+/**
+ * Get list of nurbs from edit-nurbs structure.
+ */
struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
const struct ListBase *BKE_curve_editNurbs_get_for_read(const struct Curve *cu);
@@ -159,8 +179,14 @@ void BKE_curve_bevelList_free(struct ListBase *bev);
void BKE_curve_bevelList_make(struct Object *ob, const struct ListBase *nurbs, bool for_render);
ListBase BKE_curve_bevel_make(const struct Curve *curve);
+/**
+ * Forward differencing method for bezier curve.
+ */
void BKE_curve_forward_diff_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride);
+/**
+ * Forward differencing method for first derivative of cubic bezier curve.
+ */
void BKE_curve_forward_diff_tangent_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride);
@@ -168,6 +194,10 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu,
const struct TextBox *tb,
struct rctf *r_rect);
+/**
+ * This function is almost the same as #BKE_fcurve_correct_bezpart,
+ * but doesn't allow as large a tangent.
+ */
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]);
/* ** Nurbs ** */
@@ -179,6 +209,15 @@ int BKE_nurbList_verts_count_without_handles(const struct ListBase *nurb);
void BKE_nurbList_free(struct ListBase *lb);
void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2);
+/**
+ * \param code:
+ * - 1 (#HD_AUTO): set auto-handle.
+ * - 2 (#HD_VECT): set vector-handle.
+ * - 3 (#HD_ALIGN) it toggle, vector-handles become #HD_FREE.
+ *
+ * - 5: Set align, like 3 but no toggle.
+ * - 6: Clear align (setting #HD_FREE), like 3 but no toggle.
+ */
void BKE_nurbList_handles_set(struct ListBase *editnurb, const char code);
void BKE_nurbList_handles_recalculate(struct ListBase *editnurb,
const bool calc_length,
@@ -186,18 +225,36 @@ void BKE_nurbList_handles_recalculate(struct ListBase *editnurb,
void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag);
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set);
+/**
+ * Set \a flag for every point that already has \a from_flag set.
+ */
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag);
void BKE_nurb_free(struct Nurb *nu);
struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
+/**
+ * Copy the nurb but allow for different number of points (to be copied after this).
+ */
struct Nurb *BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv);
void BKE_nurb_project_2d(struct Nurb *nu);
+/**
+ * if use_radius is truth, minmax will take points' radius into account,
+ * which will make bound-box closer to beveled curve.
+ */
void BKE_nurb_minmax(const struct Nurb *nu, bool use_radius, float min[3], float max[3]);
float BKE_nurb_calc_length(const struct Nurb *nu, int resolution);
+/**
+ * \param coord_array: has to be `(3 * 4 * resolu * resolv)` in size, and zero-ed.
+ */
void BKE_nurb_makeFaces(
const struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv);
+/**
+ * \param coord_array: Has to be `(3 * 4 * pntsu * resolu)` in size and zero-ed
+ * \param tilt_array: set when non-NULL
+ * \param radius_array: set when non-NULL
+ */
void BKE_nurb_makeCurve(const struct Nurb *nu,
float *coord_array,
float *tilt_array,
@@ -206,10 +263,19 @@ void BKE_nurb_makeCurve(const struct Nurb *nu,
int resolu,
int stride);
+/**
+ * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
+ */
unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
const unsigned int resolu,
const bool is_cyclic,
const bool use_cyclic_duplicate_endpoint);
+/**
+ * Calculate an array for the entire curve (cyclic or non-cyclic).
+ * \note Call for each axis.
+ *
+ * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
+ */
void BKE_curve_calc_coords_axis(const struct BezTriple *bezt_array,
const unsigned int bezt_array_len,
const unsigned int resolu,
@@ -232,11 +298,17 @@ bool BKE_nurb_order_clamp_u(struct Nurb *nu);
bool BKE_nurb_order_clamp_v(struct Nurb *nu);
void BKE_nurb_direction_switch(struct Nurb *nu);
+/**
+ * \note caller must ensure active vertex remains valid.
+ */
bool BKE_nurb_type_convert(struct Nurb *nu,
const short type,
const bool use_handles,
const char **r_err_msg);
+/**
+ * Be sure to call #BKE_nurb_knot_calc_u / #BKE_nurb_knot_calc_v after this.
+ */
void BKE_nurb_points_add(struct Nurb *nu, int number);
void BKE_nurb_bezierPoints_add(struct Nurb *nu, int number);
@@ -254,17 +326,31 @@ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_p
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, struct BPoint *bp, float r_normal[3]);
void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, struct BPoint *bp, float r_plane[3]);
+/**
+ * Recalculate the handles of a nurb bezier-triple. Acts based on handle selection with `SELECT`
+ * flag. To use a different flag, use #BKE_nurb_handle_calc_ex().
+ */
void BKE_nurb_handle_calc(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
const bool is_fcurve,
const char smoothing);
+/**
+ * Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag.
+ *
+ * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
+ * Usually #SELECT, but may want to use a different one at times
+ * (if caller does not operate on selection).
+ */
void BKE_nurb_handle_calc_ex(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
const eBezTriple_Flag__Alias handle_sel_flag,
const bool is_fcurve,
const char smoothing);
+/**
+ * Similar to #BKE_nurb_handle_calc but for curves and figures out the previous and next for us.
+ */
void BKE_nurb_handle_calc_simple(struct Nurb *nu, struct BezTriple *bezt);
void BKE_nurb_handle_calc_simple_auto(struct Nurb *nu, struct BezTriple *bezt);
@@ -272,6 +358,18 @@ void BKE_nurb_handle_smooth_fcurve(struct BezTriple *bezt, int total, bool cycli
void BKE_nurb_handles_calc(struct Nurb *nu);
void BKE_nurb_handles_autocalc(struct Nurb *nu, uint8_t flag);
+/**
+ * Update selected handle types to ensure valid state, e.g. deduce "Auto" types to concrete ones.
+ * Thereby \a sel_flag defines what qualifies as selected.
+ * Use when something has changed handle positions.
+ *
+ * The caller needs to recalculate handles.
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on * selection).
+ * \param use_handle: Check selection state of individual handles, otherwise always update both
+ * handles if the key is selected.
+ */
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const bool use_handle,
@@ -337,6 +435,12 @@ void BKE_curve_deform_coords_with_editmesh(const struct Object *ob_curve,
const short defaxis,
struct BMEditMesh *em_target);
+/**
+ * \param orco: Input vec and orco = local coord in curve space
+ * orco is original not-animated or deformed reference point.
+ *
+ * The result written to `vec` and `r_mat`.
+ */
void BKE_curve_deform_co(const struct Object *ob_curve,
const struct Object *ob_target,
const float orco[3],
diff --git a/source/blender/blenkernel/BKE_curve_to_mesh.hh b/source/blender/blenkernel/BKE_curve_to_mesh.hh
index fb077425336..cf5c8b87ede 100644
--- a/source/blender/blenkernel/BKE_curve_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_curve_to_mesh.hh
@@ -25,7 +25,21 @@ struct CurveEval;
namespace blender::bke {
+/**
+ * Extrude all splines in the profile curve along the path of every spline in the curve input.
+ * Transfer curve attributes to the mesh.
+ *
+ * \note Normal calculation is by far the slowest part of calculations relating to the result mesh.
+ * Although it would be a sensible decision to use the better topology information available while
+ * generating the mesh to also generate the normals, that work may wasted if the output mesh is
+ * changed anyway in a way that affects the normals. So currently this code uses the safer /
+ * simpler solution of deferring normal calculation to the rest of Blender.
+ */
Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, bool fill_caps);
+/**
+ * Create a loose-edge mesh based on the evaluated path of the curve's splines.
+ * Transfer curve attributes to the mesh.
+ */
Mesh *curve_to_wire_mesh(const CurveEval &curve);
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_curveprofile.h b/source/blender/blenkernel/BKE_curveprofile.h
index 5a948f0d844..ee8bf99a216 100644
--- a/source/blender/blenkernel/BKE_curveprofile.h
+++ b/source/blender/blenkernel/BKE_curveprofile.h
@@ -34,8 +34,15 @@ struct BlendWriter;
struct CurveProfile;
struct CurveProfilePoint;
+/**
+ * Sets the default settings and clip range for the profile widget.
+ * Does not generate either table.
+ */
void BKE_curveprofile_set_defaults(struct CurveProfile *profile);
+/**
+ * Returns a pointer to a newly allocated curve profile, using the given preset.
+ */
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset);
void BKE_curveprofile_free_data(struct CurveProfile *profile);
@@ -46,32 +53,90 @@ void BKE_curveprofile_copy_data(struct CurveProfile *target, const struct CurveP
struct CurveProfile *BKE_curveprofile_copy(const struct CurveProfile *profile);
+/**
+ * Move a point's handle, accounting for the alignment of handles with the #HD_ALIGN type.
+ *
+ * \param handle_1: Whether to move the 1st or 2nd control point.
+ * \param delta: The *relative* change in the handle's position.
+ * \note Requires #BKE_curveprofile_update call after.
+ * \return Whether the handle moved from its start position.
+ */
bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
const bool handle_1,
const bool snap,
const float delta[2]);
+/**
+ * Moves a control point, accounting for clipping and snapping, and moving free handles.
+ *
+ * \param snap: Whether to snap the point to the grid
+ * \param delta: The *relative* change of the point's location.
+ * \return Whether the point moved from its start position.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
bool BKE_curveprofile_move_point(struct CurveProfile *profile,
struct CurveProfilePoint *point,
const bool snap,
const float delta[2]);
+/**
+ * Removes a specific point from the path of control points.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
bool BKE_curveprofile_remove_point(struct CurveProfile *profile, struct CurveProfilePoint *point);
+/**
+ * Removes every point in the widget with the supplied flag set, except for the first and last.
+ *
+ * \param flag: #CurveProfilePoint.flag.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, const short flag);
+/**
+ * Adds a new point at the specified location. The choice for which points to place the new vertex
+ * between is made by checking which control point line segment is closest to the new point and
+ * placing the new vertex in between that segment's points.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
struct CurveProfilePoint *BKE_curveprofile_insert(struct CurveProfile *profile, float x, float y);
+/**
+ * Sets the handle type of the selected control points.
+ * \param type_1, type_2: Handle type for the first handle. HD_VECT, HD_AUTO, HD_FREE, or HD_ALIGN.
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_selected_handle_set(struct CurveProfile *profile, int type_1, int type_2);
+/**
+ * Flips the profile across the diagonal so that its orientation is reversed.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_reverse(struct CurveProfile *profile);
+/**
+ * Reset the view to the clipping rectangle.
+ */
void BKE_curveprofile_reset_view(struct CurveProfile *profile);
+/**
+ * Resets the profile to the current preset.
+ *
+ * \note Requires #BKE_curveprofile_update call after.
+ */
void BKE_curveprofile_reset(struct CurveProfile *profile);
int BKE_curveprofile_table_size(const struct CurveProfile *profile);
+/**
+ * Refreshes the higher resolution table sampled from the input points. A call to this or
+ * #BKE_curveprofile_update is needed before evaluation functions that use the table.
+ * Also sets the number of segments used for the display preview of the locations
+ * of the sampled points.
+ */
void BKE_curveprofile_init(struct CurveProfile *profile, short segments_len);
/* Called for a complete update of the widget after modifications */
@@ -80,15 +145,31 @@ enum {
PROF_UPDATE_REMOVE_DOUBLES = (1 << 0),
PROF_UPDATE_CLIP = (1 << 1),
};
+/**
+ * Should be called after the widget is changed. Does profile and remove double checks and more
+ * importantly, recreates the display / evaluation and segments tables.
+ * \param update_flags: Bit-field with fields defined in header file.
+ * Controls removing doubles and clipping.
+ */
void BKE_curveprofile_update(struct CurveProfile *profile, const int update_flags);
-/* Length portion is the fraction of the total path length where we want the location */
+/**
+ * Does a single evaluation along the profile's path.
+ * Travels down (length_portion * path) length and returns the position at that point.
+ * Where length portion is the fraction of the total path length where we want the location.
+ *
+ * \param length_portion: The portion (0 to 1) of the path's full length to sample at.
+ * \note Requires #BKE_curveprofile_init or #BKE_curveprofile_update call before to fill table.
+ */
void BKE_curveprofile_evaluate_length_portion(const struct CurveProfile *profile,
float length_portion,
float *x_out,
float *y_out);
void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct CurveProfile *profile);
+/**
+ * Expects that the curve profile itself has been read already.
+ */
void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 0732f1e5190..68d29235469 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -86,8 +86,14 @@ typedef void (*cd_interp)(
typedef void (*cd_copy)(const void *source, void *dest, int count);
typedef bool (*cd_validate)(void *item, const uint totitems, const bool do_fixes);
+/**
+ * Update mask_dst with layers defined in mask_src (equivalent to a bit-wise OR).
+ */
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src);
+/**
+ * Return True if all layers set in \a mask_required are also set in \a mask_ref
+ */
bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
const CustomData_MeshMasks *mask_required);
@@ -99,39 +105,50 @@ bool CustomData_layer_has_math(const struct CustomData *data, int layer_n);
bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n);
/**
- * Checks if any of the customdata layers has math.
+ * Checks if any of the custom-data layers has math.
*/
bool CustomData_has_math(const struct CustomData *data);
bool CustomData_has_interp(const struct CustomData *data);
+/**
+ * A non bmesh version would have to check `layer->data`.
+ */
bool CustomData_bmesh_has_free(const struct CustomData *data);
/**
- * Checks if any of the customdata layers is referenced.
+ * Checks if any of the custom-data layers is referenced.
*/
bool CustomData_has_referenced(const struct CustomData *data);
-/* Copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
+/**
+ * Copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
* another, while not overwriting anything else (e.g. flags). probably only
- * implemented for mloopuv/mloopcol, for now. */
+ * implemented for mloopuv/mloopcol, for now.
+ */
void CustomData_data_copy_value(int type, const void *source, void *dest);
-/* Same as above, but doing advanced mixing.
- * Only available for a few types of data (like colors...). */
+/**
+ * Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
+ * another, while not overwriting anything else (e.g. flags).
+ */
void CustomData_data_mix_value(
int type, const void *source, void *dest, const int mixmode, const float mixfactor);
-/* compares if data1 is equal to data2. type is a valid CustomData type
- * enum (e.g. CD_MLOOPUV). the layer type's equal function is used to compare
- * the data, if it exists, otherwise memcmp is used. */
+/**
+ * Compares if data1 is equal to data2. type is a valid CustomData type
+ * enum (e.g. #CD_MLOOPUV). the layer type's equal function is used to compare
+ * the data, if it exists, otherwise #memcmp is used.
+ */
bool CustomData_data_equals(int type, const void *data1, const void *data2);
void CustomData_data_initminmax(int type, void *min, void *max);
void CustomData_data_dominmax(int type, const void *data, void *min, void *max);
void CustomData_data_multiply(int type, void *data, float fac);
void CustomData_data_add(int type, void *data1, const void *data2);
-/* initializes a CustomData object with the same layer setup as source.
- * mask is a bitfield where (mask & (1 << (layer type))) indicates
- * if a layer should be copied or not. alloctype must be one of the above. */
+/**
+ * Initializes a CustomData object with the same layer setup as source.
+ * mask is a bitfield where `(mask & (1 << (layer type)))` indicates
+ * if a layer should be copied or not. alloctype must be one of the above.
+ */
void CustomData_copy(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
@@ -141,25 +158,30 @@ void CustomData_copy(const struct CustomData *source,
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
-/* same as the above, except that this will preserve existing layers, and only
- * add the layers that were not there yet */
+/**
+ * Same as the above, except that this will preserve existing layers, and only
+ * add the layers that were not there yet.
+ */
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
eCDAllocType alloctype,
int totelem);
-/* Reallocate custom data to a new element count.
+/**
+ * Reallocate custom data to a new element count.
* Only affects on data layers which are owned by the CustomData itself,
* referenced data is kept unchanged,
*
- * NOTE: Take care of referenced layers by yourself!
+ * \note Take care of referenced layers by yourself!
*/
void CustomData_realloc(struct CustomData *data, int totelem);
-/* bmesh version of CustomData_merge; merges the layouts of source and dest,
- * then goes through the mesh and makes sure all the customdata blocks are
- * consistent with the new layout. */
+/**
+ * BMesh version of CustomData_merge; merges the layouts of source and `dest`,
+ * then goes through the mesh and makes sure all the custom-data blocks are
+ * consistent with the new layout.
+ */
bool CustomData_bmesh_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
@@ -167,7 +189,9 @@ bool CustomData_bmesh_merge(const struct CustomData *source,
struct BMesh *bm,
const char htype);
-/** NULL's all members and resets the typemap. */
+/**
+ * NULL's all members and resets the #CustomData.typemap.
+ */
void CustomData_reset(struct CustomData *data);
/**
@@ -175,19 +199,26 @@ void CustomData_reset(struct CustomData *data);
*/
void CustomData_free(struct CustomData *data, int totelem);
-/* same as above, but only frees layers which matches the given mask. */
+/**
+ * Same as above, but only frees layers which matches the given mask.
+ */
void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask);
-/* frees all layers with CD_FLAG_TEMPORARY */
+/**
+ * Frees all layers with #CD_FLAG_TEMPORARY.
+ */
void CustomData_free_temporary(struct CustomData *data, int totelem);
-/* adds a data layer of the given type to the CustomData object, optionally
+/**
+ * Adds a data layer of the given type to the #CustomData object, optionally
* backed by an external data array. the different allocation types are
* defined above. returns the data of the layer.
*/
void *CustomData_add_layer(
struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem);
-/* Same as above but accepts a name. */
+/**
+ * Same as above but accepts a name.
+ */
void *CustomData_add_layer_named(struct CustomData *data,
int type,
eCDAllocType alloctype,
@@ -201,32 +232,42 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
int totelem,
const struct AnonymousAttributeID *anonymous_id);
-/* frees the active or first data layer with the give type.
+/**
+ * Frees the active or first data layer with the give type.
* returns 1 on success, 0 if no layer with the given type is found
*
- * in editmode, use EDBM_data_layer_free instead of this function
+ * In edit-mode, use #EDBM_data_layer_free instead of this function.
*/
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index);
-/* frees the layer index with the give type.
- * returns 1 on success, 0 if no layer with the given type is found
+/**
+ * Frees the layer index with the give type.
+ * returns 1 on success, 0 if no layer with the given type is found.
*
- * in editmode, use EDBM_data_layer_free instead of this function
+ * In edit-mode, use #EDBM_data_layer_free instead of this function.
*/
bool CustomData_free_layer_active(struct CustomData *data, int type, int totelem);
-/* same as above, but free all layers with type */
+/**
+ * Same as above, but free all layers with type.
+ */
void CustomData_free_layers(struct CustomData *data, int type, int totelem);
-/* returns 1 if a layer with the specified type exists */
+/**
+ * Returns true if a layer with the specified type exists.
+ */
bool CustomData_has_layer(const struct CustomData *data, int type);
-/* returns the number of layers with this type */
+/**
+ * Returns the number of layers with this type.
+ */
int CustomData_number_of_layers(const struct CustomData *data, int type);
int CustomData_number_of_layers_typemask(const struct CustomData *data, CustomDataMask mask);
-/* duplicate data of a layer with flag NOFREE, and remove that flag.
- * returns the layer data */
+/**
+ * Duplicate data of a layer with flag NOFREE, and remove that flag.
+ * \return the layer data.
+ */
void *CustomData_duplicate_referenced_layer(struct CustomData *data,
const int type,
const int totelem);
@@ -245,19 +286,21 @@ void *CustomData_duplicate_referenced_layer_anonymous(
const int totelem);
bool CustomData_is_referenced_layer(struct CustomData *data, int type);
-/* Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers. */
+/**
+ * Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers.
+ */
void CustomData_duplicate_referenced_layers(CustomData *data, int totelem);
-/* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
- * zero for the layer type, so only layer types specified by the mask
- * will be copied
+/**
+ * Set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is
+ * zero for the layer type, so only layer types specified by the mask will be copied
*/
void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask);
-/* copies data from one CustomData object to another
+/**
+ * Copies data from one CustomData object to another
* objects need not be compatible, each source layer is copied to the
- * first dest layer of correct type (if there is none, the layer is skipped)
- * return 1 on success, 0 on failure
+ * first dest layer of correct type (if there is none, the layer is skipped).
*/
void CustomData_copy_data(const struct CustomData *source,
struct CustomData *dest,
@@ -287,7 +330,9 @@ void CustomData_bmesh_copy_data_exclude_by_type(const struct CustomData *source,
void **dest_block,
const CustomDataMask mask_exclude);
-/* Copies data of a single layer of a given type. */
+/**
+ * Copies data of a single layer of a given type.
+ */
void CustomData_copy_layer_type_data(const struct CustomData *source,
struct CustomData *destination,
int type,
@@ -295,22 +340,22 @@ void CustomData_copy_layer_type_data(const struct CustomData *source,
int destination_index,
int count);
-/* frees data in a CustomData object
- * return 1 on success, 0 on failure
+/**
+ * Frees data in a #CustomData object.
*/
void CustomData_free_elem(struct CustomData *data, int index, int count);
-/* interpolates data from one CustomData object to another
- * objects need not be compatible, each source layer is interpolated to the
- * first dest layer of correct type (if there is none, the layer is skipped)
- * if weights == NULL or sub_weights == NULL, they default to all 1's
+/**
+ * Interpolate given custom data source items into a single destination one.
*
- * src_indices gives the source elements to interpolate from
- * weights gives the weight for each source element
- * sub_weights is an array of matrices of weights for sub-elements (matrices
- * should be source->subElems * source->subElems in size)
- * count gives the number of source elements to interpolate from
- * dest_index gives the dest element to write the interpolated value to
+ * \param src_indices: Indices of every source items to interpolate into the destination one.
+ * \param weights: The weight to apply to each source value individually. If NULL, they will be
+ * averaged.
+ * \param sub_weights: The weights of sub-items, only used to affect each corners of a
+ * tessellated face data (should always be and array of four values).
+ * \param count: The number of source items to interpolate.
+ * \param dest_index: Index of the destination item, in which to put the result of the
+ * interpolation.
*/
void CustomData_interp(const struct CustomData *source,
struct CustomData *dest,
@@ -319,6 +364,10 @@ void CustomData_interp(const struct CustomData *source,
const float *sub_weights,
int count,
int dest_index);
+/**
+ * \note src_blocks_ofs & dst_block_ofs
+ * must be pointers to the data, offset by layer->offset already.
+ */
void CustomData_bmesh_interp_n(struct CustomData *data,
const void **src_blocks,
const float *weights,
@@ -333,30 +382,45 @@ void CustomData_bmesh_interp(struct CustomData *data,
int count,
void *dst_block);
-/* swaps the data in the element corners, to new corners with indices as
- * specified in corner_indices. for edges this is an array of length 2, for
- * faces an array of length 4 */
+/**
+ * Swap data inside each item, for all layers.
+ * This only applies to item types that may store several sub-item data
+ * (e.g. corner data [UVs, VCol, ...] of tessellated faces).
+ *
+ * \param corner_indices: A mapping 'new_index -> old_index' of sub-item data.
+ */
void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices);
+/**
+ * Swap two items of given custom data, in all available layers.
+ */
void CustomData_swap(struct CustomData *data, const int index_a, const int index_b);
-/* gets a pointer to the data element at index from the first layer of type
- * returns NULL if there is no layer of type
+/**
+ * Gets a pointer to the data element at index from the first layer of type.
+ * \return NULL if there is no layer of type.
*/
void *CustomData_get(const struct CustomData *data, int index, int type);
void *CustomData_get_n(const struct CustomData *data, int type, int index, int n);
+
+/* BMesh Custom Data Functions.
+ * Should replace edit-mesh ones with these as well, due to more efficient memory alloc. */
+
void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type);
void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n);
-/* gets the layer at physical index n, with no type checking.
+/**
+ * Gets from the layer at physical index `n`,
+ * \note doesn't check type.
*/
void *CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n);
bool CustomData_set_layer_name(const struct CustomData *data, int type, int n, const char *name);
const char *CustomData_get_layer_name(const struct CustomData *data, int type, int n);
-/* gets a pointer to the active or first layer of type
- * returns NULL if there is no layer of type
+/**
+ * Gets a pointer to the active or first layer of type.
+ * \return NULL if there is no layer of type.
*/
void *CustomData_get_layer(const struct CustomData *data, int type);
void *CustomData_get_layer_n(const struct CustomData *data, int type, int n);
@@ -377,9 +441,9 @@ int CustomData_get_render_layer(const struct CustomData *data, int type);
int CustomData_get_clone_layer(const struct CustomData *data, int type);
int CustomData_get_stencil_layer(const struct CustomData *data, int type);
-/* copies the data from source to the data element at index in the first
- * layer of type
- * no effect if there is no layer of type
+/**
+ * Copies the data from source to the data element at index in the first layer of type
+ * no effect if there is no layer of type.
*/
void CustomData_set(const struct CustomData *data, int index, int type, const void *source);
@@ -390,42 +454,63 @@ void CustomData_bmesh_set(const struct CustomData *data,
void CustomData_bmesh_set_n(
struct CustomData *data, void *block, int type, int n, const void *source);
-/* sets the data of the block at physical layer n. no real type checking
- * is performed.
+/**
+ * Sets the data of the block at physical layer n.
+ * no real type checking is performed.
*/
void CustomData_bmesh_set_layer_n(struct CustomData *data, void *block, int n, const void *source);
-/* set the pointer of to the first layer of type. the old data is not freed.
- * returns the value of ptr if the layer is found, NULL otherwise
+/**
+ * Set the pointer of to the first layer of type. the old data is not freed.
+ * returns the value of `ptr` if the layer is found, NULL otherwise.
*/
void *CustomData_set_layer(const struct CustomData *data, int type, void *ptr);
void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr);
-/* sets the nth layer of type as active */
+/**
+ * Sets the nth layer of type as active.
+ */
void CustomData_set_layer_active(struct CustomData *data, int type, int n);
void CustomData_set_layer_render(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone(struct CustomData *data, int type, int n);
void CustomData_set_layer_stencil(struct CustomData *data, int type, int n);
-/* same as above but works with an index from CustomData_get_layer_index */
+/**
+ * For using with an index from #CustomData_get_active_layer_index and
+ * #CustomData_get_render_layer_index.
+ */
void CustomData_set_layer_active_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_render_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_stencil_index(struct CustomData *data, int type, int n);
-/* adds flag to the layer flags */
+/**
+ * Adds flag to the layer flags.
+ */
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_bmesh_set_default(struct CustomData *data, void **block);
void CustomData_bmesh_free_block(struct CustomData *data, void **block);
+/**
+ * Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
+ */
void CustomData_bmesh_free_block_data(struct CustomData *data, void *block);
+/**
+ * A selective version of #CustomData_bmesh_free_block_data.
+ */
void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
void *block,
const CustomDataMask mask_exclude);
-/* copy custom data to/from layers as in mesh/derivedmesh, to editmesh
- * blocks of data. the CustomData's must not be compatible */
+/**
+ * Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
+ * blocks of data. the CustomData's must not be compatible.
+ *
+ * \param use_default_init: initializes data which can't be copied,
+ * typically you'll want to use this if the BM_xxx create function
+ * is called with BM_CREATE_SKIP_CD flag
+ */
void CustomData_to_bmesh_block(const struct CustomData *source,
struct CustomData *dest,
int src_index,
@@ -436,17 +521,34 @@ void CustomData_from_bmesh_block(const struct CustomData *source,
void *src_block,
int dest_index);
-/* query info over types */
+/**
+ * Query info over types.
+ */
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num);
int CustomData_sizeof(int type);
-/* get the name of a layer type */
+/**
+ * Get the name of a layer type.
+ */
const char *CustomData_layertype_name(int type);
+/**
+ * Can only ever be one of these.
+ */
bool CustomData_layertype_is_singleton(int type);
+/**
+ * Has dynamically allocated members.
+ * This is useful to know if operations such as #memcmp are
+ * valid when comparing data from two layers.
+ */
bool CustomData_layertype_is_dynamic(int type);
+/**
+ * \return Maximum number of layers of given \a type, -1 means 'no limit'.
+ */
int CustomData_layertype_layers_max(const int type);
-/* make sure the name of layer at index is unique */
+/**
+ * Make sure the name of layer at index is unique.
+ */
void CustomData_set_layer_unique_name(struct CustomData *data, int index);
void CustomData_validate_layer_name(const struct CustomData *data,
@@ -454,23 +556,45 @@ void CustomData_validate_layer_name(const struct CustomData *data,
const char *name,
char *outname);
-/* for file reading compatibility, returns false if the layer was freed,
- * only after this test passes, layer->data should be assigned */
+/**
+ * For file reading compatibility, returns false if the layer was freed,
+ * only after this test passes, `layer->data` should be assigned.
+ */
bool CustomData_verify_versions(struct CustomData *data, int index);
-/* BMesh specific custom-data stuff. */
+/* BMesh specific custom-data stuff.
+ *
+ * Needed to convert to/from different face representation (for versioning). */
+
void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int totloop);
void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int total);
void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *ldata);
+/**
+ * Update active indices for active/render/clone/stencil custom data layers
+ * based on indices from fdata layers
+ * used by do_versions in `readfile.c` when creating pdata and ldata for pre-bmesh
+ * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files.
+ */
void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata,
struct CustomData *ldata);
void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, const char htype);
#ifndef NDEBUG
+/**
+ * Debug check, used to assert when we expect layers to be in/out of sync.
+ *
+ * \param fallback: Use when there are no layers to handle,
+ * since callers may expect success or failure.
+ */
bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback);
#endif
-/* Layer data validation. */
+/**
+ * Validate and fix data of \a layer,
+ * if possible (needs relevant callback in layer's type to be defined).
+ *
+ * \return True if some errors were found.
+ */
bool CustomData_layer_validate(struct CustomDataLayer *layer,
const uint totitems,
const bool do_fixes);
@@ -587,16 +711,41 @@ typedef struct CustomDataTransferLayerMap {
cd_datatransfer_interp interp;
} CustomDataTransferLayerMap;
-/* Those functions assume src_n and dst_n layers of given type exist in resp. src and dst. */
+/**
+ * Those functions assume src_n and dst_n layers of given type exist in resp. src and dst.
+ */
void CustomData_data_transfer(const struct MeshPairRemap *me_remap,
const CustomDataTransferLayerMap *laymap);
/* .blend file I/O */
+
+/**
+ * Prepare given custom data for file writing.
+ *
+ * \param data: the custom-data to tweak for .blend file writing (modified in place).
+ * \param r_write_layers: contains a reduced set of layers to be written to file,
+ * use it with #writestruct_at_address()
+ * (caller must free it if != \a write_layers_buff).
+ *
+ * \param write_layers_buff: An optional buffer for r_write_layers (to avoid allocating it).
+ * \param write_layers_size: The size of pre-allocated \a write_layer_buff.
+ *
+ * \warning After this funcion has ran, given custom data is no more valid from Blender POV
+ * (its `totlayer` is invalid). This function shall always be called with localized data
+ * (as it is in write_meshes()).
+ *
+ * \note `data->typemap` is not updated here, since it is always rebuilt on file read anyway.
+ * This means written `typemap` does not match written layers (as returned by \a r_write_layers).
+ * Trivial to fix is ever needed.
+ */
void CustomData_blend_write_prepare(struct CustomData *data,
struct CustomDataLayer **r_write_layers,
struct CustomDataLayer *write_layers_buff,
size_t write_layers_size);
+/**
+ * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
+ */
void CustomData_blend_write(struct BlendWriter *writer,
struct CustomData *data,
CustomDataLayer *layers,
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index a2544e43c3d..a4218ec564b 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -65,6 +65,10 @@ enum {
void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
struct CustomData_MeshMasks *r_data_masks);
+/**
+ * Check what can do each layer type
+ * (if it is actually handled by transfer-data, if it supports advanced mixing.
+ */
bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
bool *r_advanced_mixing,
bool *r_threshold);
@@ -122,6 +126,12 @@ enum {
#endif
};
+/**
+ * Transfer data *layout* of selected types from source to destination object.
+ * By default, it only creates new data layers if needed on \a ob_dst.
+ * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those
+ * from \a ob_src, to get (as much as possible) exact copy of source data layout.
+ */
void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index f4221d57428..9870d43b5c2 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -44,20 +44,36 @@ const struct ListBase *BKE_object_defgroup_list(const struct Object *ob);
struct ListBase *BKE_object_defgroup_list_mutable(struct Object *ob);
int BKE_object_defgroup_count(const struct Object *ob);
+/**
+ * \note For historical reasons, the index starts at 1 rather than 0.
+ */
int BKE_object_defgroup_active_index_get(const struct Object *ob);
+/**
+ * \note For historical reasons, the index starts at 1 rather than 0.
+ */
void BKE_object_defgroup_active_index_set(struct Object *ob, const int new_index);
const struct ListBase *BKE_id_defgroup_list_get(const struct ID *id);
struct ListBase *BKE_id_defgroup_list_get_mutable(struct ID *id);
int BKE_id_defgroup_name_index(const struct ID *id, const char *name);
+bool BKE_id_defgroup_name_find(const struct ID *id,
+ const char *name,
+ int *r_index,
+ struct bDeformGroup **r_group);
struct bDeformGroup *BKE_object_defgroup_new(struct Object *ob, const char *name);
void BKE_defgroup_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
struct bDeformGroup *BKE_defgroup_duplicate(const struct bDeformGroup *ingroup);
struct bDeformGroup *BKE_object_defgroup_find_name(const struct Object *ob, const char *name);
+/**
+ * \note caller must free.
+ */
int *BKE_object_defgroup_flip_map(const struct Object *ob,
int *flip_map_len,
const bool use_default);
+/**
+ * \note caller must free.
+ */
int *BKE_object_defgroup_flip_map_single(const struct Object *ob,
int *flip_map_len,
const bool use_default,
@@ -67,11 +83,33 @@ int BKE_object_defgroup_name_index(const struct Object *ob, const char *name);
void BKE_object_defgroup_unique_name(struct bDeformGroup *dg, struct Object *ob);
struct MDeformWeight *BKE_defvert_find_index(const struct MDeformVert *dv, const int defgroup);
+/**
+ * Ensures that `dv` has a deform weight entry for the specified defweight group.
+ *
+ * \note this function is mirrored in editmesh_tools.c, for use for edit-vertices.
+ */
struct MDeformWeight *BKE_defvert_ensure_index(struct MDeformVert *dv, const int defgroup);
+/**
+ * Adds the given vertex to the specified vertex group, with given weight.
+ *
+ * \warning this does NOT check for existing, assume caller already knows its not there.
+ */
void BKE_defvert_add_index_notest(struct MDeformVert *dv, int defgroup, const float weight);
+/**
+ * Removes the given vertex from the vertex group.
+ *
+ * \warning This function frees the given #MDeformWeight, do not use it afterward!
+ */
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw);
void BKE_defvert_clear(struct MDeformVert *dvert);
+/**
+ * \return The first group index shared by both deform verts
+ * or -1 if none are found.
+ */
int BKE_defvert_find_shared(const struct MDeformVert *dvert_a, const struct MDeformVert *dvert_b);
+/**
+ * \return true if has no weights.
+ */
bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot);
void BKE_defvert_array_free_elems(struct MDeformVert *dvert, int totvert);
@@ -79,14 +117,32 @@ void BKE_defvert_array_free(struct MDeformVert *dvert, int totvert);
void BKE_defvert_array_copy(struct MDeformVert *dst, const struct MDeformVert *src, int totvert);
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup);
+/**
+ * Take care with this the rationale is:
+ * - if the object has no vertex group. act like vertex group isn't set and return 1.0.
+ * - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0.
+ *
+ * This is a bit confusing, just saves some checks from the caller.
+ */
float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert,
const int index,
const int defgroup);
+/**
+ * \return The total weight in all groups marked in the selection mask.
+ */
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel);
+/**
+ * \return The representative weight of a multi-paint group, used for
+ * viewport colors and actual painting.
+ *
+ * Result equal to sum of weights with auto normalize, and average otherwise.
+ * Value is not clamped, since painting relies on multiplication being always
+ * commutative with the collective weight function.
+ */
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel,
@@ -96,9 +152,19 @@ float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
/* This much unlocked weight is considered equivalent to none. */
#define VERTEX_WEIGHT_LOCK_EPSILON 1e-6f
+/**
+ * Computes the display weight for the lock relative weight paint mode.
+ *
+ * \return weight divided by 1-locked_weight with division by zero check
+ */
float BKE_defvert_calc_lock_relative_weight(float weight,
float locked_weight,
float unlocked_weight);
+/**
+ * Computes the display weight for the lock relative weight paint mode, using weight data.
+ *
+ * \return weight divided by unlocked, or 1-locked_weight with division by zero check.
+ */
float BKE_defvert_lock_relative_weight(float weight,
const struct MDeformVert *dv,
int defbase_tot,
@@ -106,41 +172,75 @@ float BKE_defvert_lock_relative_weight(float weight,
const bool *defbase_unlocked);
void BKE_defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src);
+/**
+ * Overwrite weights filtered by vgroup_subset.
+ * - do nothing if neither are set.
+ * - add destination weight if needed
+ */
void BKE_defvert_copy_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
const int vgroup_tot);
+/**
+ * Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
+ * - do nothing if neither are set.
+ * - add destination weight if needed
+ */
void BKE_defvert_mirror_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
const int vgroup_tot,
const int *flip_map,
const int flip_map_len);
+/**
+ * Copy an index from one #MDeformVert to another.
+ * - do nothing if neither are set.
+ * - add destination weight if needed.
+ */
void BKE_defvert_copy_index(struct MDeformVert *dvert_dst,
const int defgroup_dst,
const struct MDeformVert *dvert_src,
const int defgroup_src);
+/**
+ * Only sync over matching weights, don't add or remove groups
+ * warning, loop within loop.
+ */
void BKE_defvert_sync(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool use_ensure);
+/**
+ * be sure all flip_map values are valid
+ */
void BKE_defvert_sync_mapped(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const int *flip_map,
const int flip_map_len,
const bool use_ensure);
+/**
+ * be sure all flip_map values are valid
+ */
void BKE_defvert_remap(struct MDeformVert *dvert, const int *map, const int map_len);
void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len);
void BKE_defvert_flip_merged(struct MDeformVert *dvert,
const int *flip_map,
const int flip_map_len);
void BKE_defvert_normalize(struct MDeformVert *dvert);
+/**
+ * Same as #BKE_defvert_normalize but takes a bool array.
+ */
void BKE_defvert_normalize_subset(struct MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot);
+/**
+ * Same as BKE_defvert_normalize() if the locked vgroup is not a member of the subset
+ */
void BKE_defvert_normalize_lock_single(struct MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
const uint def_nr_lock);
+/**
+ * Same as BKE_defvert_normalize() if no locked vgroup is a member of the subset
+ */
void BKE_defvert_normalize_lock_map(struct MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
@@ -149,11 +249,16 @@ void BKE_defvert_normalize_lock_map(struct MDeformVert *dvert,
/* Utilities to 'extract' a given vgroup into a simple float array,
* for verts, but also edges/polys/loops. */
+
void BKE_defvert_extract_vgroup_to_vertweights(struct MDeformVert *dvert,
const int defgroup,
const int num_verts,
float *r_weights,
const bool invert_vgroup);
+/**
+ * The following three make basic interpolation,
+ * using temp vert_weights array to avoid looking up same weight several times.
+ */
void BKE_defvert_extract_vgroup_to_edgeweights(struct MDeformVert *dvert,
const int defgroup,
const int num_verts,
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index 8fb596a8096..db1217465d7 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -98,6 +98,12 @@ void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
bool BKE_displist_surfindex_get(
const struct DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
+/**
+ * \param normal_proj: Optional normal that's used to project the scan-fill verts into 2D coords.
+ * Pass this along if known since it saves time calculating the normal.
+ * This is also used to initialize #DispList.nors (one normal per display list).
+ * \param flip_normal: Flip the normal (same as passing \a normal_proj negated).
+ */
void BKE_displist_fill(const struct ListBase *dispbase,
struct ListBase *to,
const float normal_proj[3],
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index 989b68f4ccb..5eff84b8c9e 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -36,6 +36,9 @@ struct ID;
/* ---------------------------------------------------- */
/* Dupli-Geometry */
+/**
+ * \return a #ListBase of #DupliObject.
+ */
struct ListBase *object_duplilist(struct Depsgraph *depsgraph,
struct Scene *sce,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 31f48be2c27..4b34a9490c4 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -64,41 +64,79 @@ typedef struct PaintWavePoint {
short state;
} PaintWavePoint;
+/**
+ * Modifier call. Processes dynamic paint modifier step.
+ */
struct Mesh *dynamicPaint_Modifier_do(struct DynamicPaintModifierData *pmd,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct Mesh *me);
+/**
+ * Free whole dynamic-paint modifier.
+ */
void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd);
void dynamicPaint_Modifier_free_runtime(struct DynamicPaintRuntime *runtime);
void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd,
struct DynamicPaintModifierData *tpmd,
int flag);
+/**
+ * Initialize modifier data.
+ */
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene);
+/**
+ * Creates a new surface and adds it to the list
+ * If scene is null, frame range of 1-250 is used
+ * A pointer to this surface is returned.
+ */
struct DynamicPaintSurface *dynamicPaint_createNewSurface(
struct DynamicPaintCanvasSettings *canvas, struct Scene *scene);
+/**
+ * Clears surface data back to zero.
+ */
void dynamicPaint_clearSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
+/**
+ * Completely (re)initializes surface (only for point cache types).
+ */
bool dynamicPaint_resetSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
void dynamicPaint_freeSurface(const struct DynamicPaintModifierData *pmd,
struct DynamicPaintSurface *surface);
+/**
+ * Free canvas data.
+ */
void dynamicPaint_freeCanvas(struct DynamicPaintModifierData *pmd);
+/* Free brush data */
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd);
void dynamicPaint_freeSurfaceData(struct DynamicPaintSurface *surface);
+/**
+ * Update cache frame range.
+ */
void dynamicPaint_cacheUpdateFrames(struct DynamicPaintSurface *surface);
bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface,
struct Object *ob,
int output);
+/**
+ * Change surface data to defaults on new type.
+ */
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface);
void dynamicPaintSurface_setUniqueName(struct DynamicPaintSurface *surface, const char *basename);
+/**
+ * Get currently active surface (in user interface).
+ */
struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings *canvas);
-/* image sequence baking */
+/**
+ * Image sequence baking.
+ */
int dynamicPaint_createUVSurface(struct Scene *scene,
struct DynamicPaintSurface *surface,
float *progress,
short *do_update);
+/**
+ * Calculate a single frame and included sub-frames for surface.
+ */
int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface,
struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 2c24b1a5487..32cc5961e4a 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -102,12 +102,29 @@ void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpda
void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
struct BMPartialUpdate *bmpinfo);
+/**
+ * Performing the face normal calculation at the same time as tessellation
+ * gives a reasonable performance boost (approx ~20% faster).
+ */
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em);
+/**
+ * \note The caller is responsible for ensuring triangulation data,
+ * typically by calling #BKE_editmesh_looptri_calc.
+ */
BMEditMesh *BKE_editmesh_create(BMesh *bm);
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
+/**
+ * \brief Return the #BMEditMesh for a given object
+ *
+ * \note this function assumes this is a mesh object,
+ * don't add NULL data check here. caller must do that
+ */
BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
void BKE_editmesh_free_derived_caches(BMEditMesh *em);
+/**
+ * \note Does not free the #BMEditMesh struct itself.
+ */
void BKE_editmesh_free_data(BMEditMesh *em);
float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph,
@@ -124,6 +141,9 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
bool *r_is_alloc))[3];
void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me);
+/**
+ * If auto-smooth not already set, set it.
+ */
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me);
struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em);
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index 69d1b4819f8..fc274b4ffd1 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -78,7 +78,9 @@ struct BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *tree,
BMBVHTree_FaceFilter filter_cb,
void *filter_userdata);
-/* find a vert closest to co in a sphere of radius dist_max */
+/**
+ * Find a vert closest to co in a sphere of radius dist_max.
+ */
struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree,
const float co[3],
const float dist_max);
@@ -86,10 +88,16 @@ struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *tree,
const float co[3],
const float dist_max);
+/**
+ * Overlap indices reference the looptri's.
+ */
struct BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a,
const BMBVHTree *bmtree_b,
unsigned int *r_overlap_tot);
+/**
+ * Overlap indices reference the looptri's.
+ */
struct BVHTreeOverlap *BKE_bmbvh_overlap_self(const BMBVHTree *bmtree,
unsigned int *r_overlap_tot);
diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h
index 0e3f063ae44..b76db11348e 100644
--- a/source/blender/blenkernel/BKE_editmesh_tangent.h
+++ b/source/blender/blenkernel/BKE_editmesh_tangent.h
@@ -24,6 +24,13 @@
extern "C" {
#endif
+/**
+ * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
+ *
+ * \note This function is not so normal, its using #BMesh.ldata as input,
+ * but output's to #Mesh.ldata.
+ * This is done because #CD_TANGENT is cache data used only for drawing.
+ */
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index 3a964ddb1aa..f33ca2f03d1 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -113,16 +113,27 @@ struct PartDeflect *BKE_partdeflect_new(int type);
struct PartDeflect *BKE_partdeflect_copy(const struct PartDeflect *pd_src);
void BKE_partdeflect_free(struct PartDeflect *pd);
+/**
+ * Create list of effector relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of effectors during evaluation.
+ */
struct ListBase *BKE_effector_relations_create(struct Depsgraph *depsgraph,
struct ViewLayer *view_layer,
struct Collection *collection);
void BKE_effector_relations_free(struct ListBase *lb);
+/**
+ * Create effective list of effectors from relations built beforehand.
+ */
struct ListBase *BKE_effectors_create(struct Depsgraph *depsgraph,
struct Object *ob_src,
struct ParticleSystem *psys_src,
struct EffectorWeights *weights,
bool use_rotation);
+/**
+ * Generic force/speed system, now used for particles, soft-bodies & dynamic-paint.
+ */
void BKE_effectors_apply(struct ListBase *effectors,
struct ListBase *colliders,
struct EffectorWeights *weights,
@@ -146,15 +157,15 @@ float effector_falloff(struct EffectorCache *eff,
struct EffectorData *efd,
struct EffectedPoint *point,
struct EffectorWeights *weights);
-int closest_point_on_surface(struct SurfaceModifierData *surmd,
- const float co[3],
- float surface_co[3],
- float surface_nor[3],
- float surface_vel[3]);
-int get_effector_data(struct EffectorCache *eff,
- struct EffectorData *efd,
- struct EffectedPoint *point,
- int real_velocity);
+bool closest_point_on_surface(struct SurfaceModifierData *surmd,
+ const float co[3],
+ float surface_co[3],
+ float surface_nor[3],
+ float surface_vel[3]);
+bool get_effector_data(struct EffectorCache *eff,
+ struct EffectorData *efd,
+ struct EffectedPoint *point,
+ int real_velocity);
/* required for particle_system.c */
#if 0
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index f494c2e30cc..1537d14ab01 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -133,20 +133,56 @@ typedef enum eFMI_Requirement_Flags {
} eFMI_Requirement_Flags;
/* Function Prototypes for FModifierTypeInfo's */
+
+/**
+ * This function should always be used to get the appropriate type-info,
+ * as it has checks which prevent segfaults in some weird cases.
+ */
const FModifierTypeInfo *fmodifier_get_typeinfo(const struct FModifier *fcm);
+/**
+ * This function should be used for getting the appropriate type-info when only
+ * a F-Curve modifier type is known.
+ */
const FModifierTypeInfo *get_fmodifier_typeinfo(const int type);
/* ---------------------- */
+/**
+ * Add a new F-Curve Modifier to the given F-Curve of a certain type.
+ */
struct FModifier *add_fmodifier(ListBase *modifiers, int type, struct FCurve *owner_fcu);
+/**
+ * Make a copy of the specified F-Modifier.
+ */
struct FModifier *copy_fmodifier(const struct FModifier *src);
+/**
+ * Duplicate all of the F-Modifiers in the Modifier stacks.
+ */
void copy_fmodifiers(ListBase *dst, const ListBase *src);
+/**
+ * Remove and free the given F-Modifier from the given stack.
+ */
bool remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+/**
+ * Remove all of a given F-Curve's modifiers.
+ */
void free_fmodifiers(ListBase *modifiers);
+/**
+ * Find the active F-Modifier.
+ */
struct FModifier *find_active_fmodifier(ListBase *modifiers);
+/**
+ * Set the active F-Modifier.
+ */
void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm);
+/**
+ * Do we have any modifiers which match certain criteria.
+ *
+ * \param mtype: Type of modifier (if 0, doesn't matter).
+ * \param acttype: Type of action to perform (if -1, doesn't matter).
+ */
bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype);
typedef struct FModifiersStackStorage {
@@ -156,17 +192,38 @@ typedef struct FModifiersStackStorage {
} FModifiersStackStorage;
uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers);
+/**
+ * Evaluate time modifications imposed by some F-Curve Modifiers.
+ *
+ * - This step acts as an optimization to prevent the F-Curve stack being evaluated
+ * several times by modifiers requesting the time be modified, as the final result
+ * would have required using the modified time
+ * - Modifiers only ever receive the unmodified time, as subsequent modifiers should be
+ * working on the 'global' result of the modified curve, not some localized segment,
+ * so \a evaltime gets set to whatever the last time-modifying modifier likes.
+ * - We start from the end of the stack, as only the last one matters for now.
+ *
+ * \param fcu: Can be NULL.
+ */
float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
struct FCurve *fcu,
float cvalue,
float evaltime);
+/**
+ * Evaluates the given set of F-Curve Modifiers using the given data
+ * Should only be called after evaluate_time_fmodifiers() has been called.
+ */
void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
struct FCurve *fcu,
float *cvalue,
float evaltime);
+/**
+ * Bake modifiers for given F-Curve to curve sample data, in the frame range defined
+ * by start and end (inclusive).
+ */
void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array,
@@ -182,30 +239,64 @@ int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array,
/* -------- Data Management -------- */
struct FCurve *BKE_fcurve_create(void);
+/**
+ * Frees the F-Curve itself too, so make sure #BLI_remlink is called before calling this.
+ */
void BKE_fcurve_free(struct FCurve *fcu);
+/**
+ * Duplicate a F-Curve.
+ */
struct FCurve *BKE_fcurve_copy(const struct FCurve *fcu);
-
+/**
+ * Frees a list of F-Curves.
+ */
void BKE_fcurves_free(ListBase *list);
+/**
+ * Duplicate a list of F-Curves.
+ */
void BKE_fcurves_copy(ListBase *dst, ListBase *src);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_fcurve_foreach_id(struct FCurve *fcu, struct LibraryForeachIDData *data);
-/* find matching F-Curve in the given list of F-Curves */
+/**
+ * Find the F-Curve affecting the given RNA-access path + index,
+ * in the list of F-Curves provided.
+ */
struct FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index);
+/**
+ * Quick way to loop over all f-curves of a given 'path'.
+ */
struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path[]);
-/* high level function to get an fcurve from C without having the rna */
+/**
+ * High level function to get an f-curve from C without having the RNA.
+ */
struct FCurve *id_data_find_fcurve(
ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, bool *r_driven);
-/* Get list of LinkData's containing pointers to the F-Curves which control the types of data
- * indicated
- * e.g. numMatches = BKE_fcurves_filter(matches, &act->curves, "pose.bones[", "MyFancyBone");
+/**
+ * Get list of LinkData's containing pointers to the F-curves
+ * which control the types of data indicated.
+ * e.g. `numMatches = BKE_fcurves_filter(matches, &act->curves, "pose.bones[", "MyFancyBone");`
+ *
+ * Lists:
+ * \param dst: list of LinkData's matching the criteria returned.
+ * List must be freed after use, and is assumed to be empty when passed.
+ * \param src: list of F-Curves to search through
+ * Filters:
+ * \param dataPrefix: i.e. `pose.bones[` or `nodes[`.
+ * \param dataName: name of entity within "" immediately following the prefix.
*/
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
-/* Find an f-curve based on an rna property. */
+/**
+ * Find an f-curve based on an rna property.
+ */
struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
struct PropertyRNA *prop,
int rnaindex,
@@ -213,8 +304,10 @@ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
struct bAction **r_action,
bool *r_driven,
bool *r_special);
-/* Same as above, but takes a context data,
- * temp hack needed for complex paths like texture ones. */
+/**
+ * Same as above, but takes a context data,
+ * temp hack needed for complex paths like texture ones.
+ */
struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -224,7 +317,8 @@ struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
bool *r_driven,
bool *r_special);
-/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
+/**
+ * Binary search algorithm for finding where to 'insert' #BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
*/
int BKE_fcurve_bezt_binarysearch_index(const struct BezTriple array[],
@@ -233,23 +327,35 @@ int BKE_fcurve_bezt_binarysearch_index(const struct BezTriple array[],
bool *r_replace);
/* fcurve_cache.c */
-/* Cached f-curve look-ups, use when this needs to be done many times. */
+
+/**
+ * Cached f-curve look-ups, use when this needs to be done many times.
+ */
struct FCurvePathCache;
struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list);
void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache);
struct FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
const char rna_path[],
const int array_index);
+/**
+ * Fill in an array of F-Curve, leave NULL when not found.
+ *
+ * \return The number of F-Curves found.
+ */
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
struct FCurve **fcurve_result,
int fcurve_result_len);
-/* get the time extents for F-Curve */
+/**
+ * Calculate the extents of F-Curve's keyframes.
+ */
bool BKE_fcurve_calc_range(
struct FCurve *fcu, float *min, float *max, const bool do_sel_only, const bool do_min_length);
-/* get the bounding-box extents for F-Curve */
+/**
+ * Calculate the extents of F-Curve's data.
+ */
bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
float *xmin,
float *xmax,
@@ -258,6 +364,14 @@ bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
const bool do_sel_only,
const bool include_handles);
+/**
+ * Return an array of keyed frames, rounded to `interval`.
+ *
+ * \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc.
+ *
+ * \note An interval of zero could be supported (this implies no rounding at all),
+ * however this risks very small differences in float values being treated as separate keyframes.
+ */
float *BKE_fcurves_calc_keyed_frames_ex(struct FCurve **fcurve_array,
const int fcurve_array_len,
const float interval,
@@ -266,23 +380,42 @@ float *BKE_fcurves_calc_keyed_frames(struct FCurve **fcurve_array,
const int fcurve_array_len,
int *r_frames_len);
+/**
+ * Set the index that stores the FCurve's active keyframe, assuming that \a active_bezt
+ * is already part of `fcu->bezt`. If NULL, set active keyframe index to "none."
+ */
void BKE_fcurve_active_keyframe_set(struct FCurve *fcu, const struct BezTriple *active_bezt);
+/**
+ * Get the active keyframe index, with sanity checks for point bounds.
+ */
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu);
-/* Move the indexed keyframe to the given value, and move the handles with it to ensure the slope
- * remains the same. */
+/**
+ * Move the indexed keyframe to the given value,
+ * and move the handles with it to ensure the slope remains the same.
+ */
void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, float new_value);
/* .............. */
-/* Are keyframes on F-Curve of any use (to final result, and to show in editors)? */
+/**
+ * Are keyframes on F-Curve of any use (to final result, and to show in editors)?
+ * Usability of keyframes refers to whether they should be displayed,
+ * and also whether they will have any influence on the final result.
+ */
bool BKE_fcurve_are_keyframes_usable(struct FCurve *fcu);
-/* Can keyframes be added to F-Curve? */
+/**
+ * Can keyframes be added to F-Curve?
+ * Keyframes can only be added if they are already visible.
+ */
bool BKE_fcurve_is_keyframable(struct FCurve *fcu);
bool BKE_fcurve_is_protected(struct FCurve *fcu);
-/* The curve is an infinite cycle via Cycles modifier */
+/**
+ * Checks if the F-Curve has a Cycles modifier with simple settings
+ * that warrant transition smoothing.
+ */
bool BKE_fcurve_is_cyclic(struct FCurve *fcu);
/* Type of infinite cycle for a curve. */
@@ -294,9 +427,19 @@ typedef enum eFCU_Cycle_Type {
FCU_CYCLE_OFFSET,
} eFCU_Cycle_Type;
+/**
+ * Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior.
+ */
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu);
-/* Recompute handles to neatly subdivide the prev-next range at bezt. */
+/**
+ * Recompute bezier handles of all three given BezTriples, so that `bezt` can be inserted between
+ * `prev` and `next` without changing the resulting curve shape.
+ *
+ * \param r_pdelta: return Y difference between `bezt` and the original curve value at its X
+ * position.
+ * \return Whether the split was successful.
+ */
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
@@ -304,12 +447,50 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
/* -------- Curve Sanity -------- */
+/**
+ * This function recalculates the handles of an F-Curve. Acts based on selection with `SELECT`
+ * flag. To use a different flag, use #calchandles_fcurve_ex().
+ *
+ * If the BezTriples have been rearranged, sort them first before using this.
+ */
void calchandles_fcurve(struct FCurve *fcu);
+/**
+ * Variant of #calchandles_fcurve() that allows calculating based on a different select flag.
+ *
+ * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
+ * Usually `SELECT`, but may want to use a different one at times
+ * (if caller does not operate on selection).
+ */
void calchandles_fcurve_ex(struct FCurve *fcu, eBezTriple_Flag handle_sel_flag);
+/**
+ * Update handles, making sure the handle-types are valid (e.g. correctly deduced from an "Auto"
+ * type), and recalculating their position vectors.
+ * Use when something has changed handle positions.
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on selection).
+ * \param use_handle: Check selection state of individual handles, otherwise always update both
+ * handles if the key is selected.
+ */
void testhandles_fcurve(struct FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle);
+/**
+ * This function sorts BezTriples so that they are arranged in chronological order,
+ * as tools working on F-Curves expect that the BezTriples are in order.
+ */
void sort_time_fcurve(struct FCurve *fcu);
+/**
+ * This function tests if any BezTriples are out of order, thus requiring a sort.
+ */
bool test_time_fcurve(struct FCurve *fcu);
+/**
+ * The length of each handle is not allowed to be more
+ * than the horizontal distance between (v1-v4).
+ * This is to prevent curve loops.
+ *
+ * This function is very similar to BKE_curve_correct_bezpart(), but allows a steeper tangent for
+ * more snappy animations. This is not desired for other areas in which curves are used, though.
+ */
void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2]);
/* -------- Evaluation -------- */
@@ -321,8 +502,14 @@ float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna,
struct FCurve *fcu,
struct ChannelDriver *driver_orig,
const struct AnimationEvalContext *anim_eval_context);
+/**
+ * Checks if the curve has valid keys, drivers or modifiers that produce an actual curve.
+ */
bool BKE_fcurve_is_empty(struct FCurve *fcu);
-/* evaluate fcurve and store value */
+/**
+ * Calculate the value of the given F-Curve at the given frame,
+ * and store it's value in #FCurve.curval.
+ */
float calculate_fcurve(struct PathResolvedRNA *anim_rna,
struct FCurve *fcu,
const struct AnimationEvalContext *anim_eval_context);
@@ -331,26 +518,34 @@ float calculate_fcurve(struct PathResolvedRNA *anim_rna,
/* -------- Defines -------- */
-/* Basic signature for F-Curve sample-creation function
- * - fcu: the F-Curve being operated on
- * - data: pointer to some specific data that may be used by one of the callbacks
+/**
+ * Basic signature for F-Curve sample-creation function.
+ *
+ * \param fcu: the F-Curve being operated on.
+ * \param data: pointer to some specific data that may be used by one of the callbacks.
*/
typedef float (*FcuSampleFunc)(struct FCurve *fcu, void *data, float evaltime);
/* ----- Sampling Callbacks ------ */
-/* Basic sampling callback which acts as a wrapper for evaluate_fcurve() */
+/**
+ * Basic sampling callback which acts as a wrapper for #evaluate_fcurve()
+ * 'data' arg here is unneeded here.
+ */
float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime);
/* -------- Main Methods -------- */
-/* Main API function for creating a set of sampled curve data, given some callback function
+/**
+ * Main API function for creating a set of sampled curve data, given some callback function
* used to retrieve the values to store.
*/
void fcurve_store_samples(
struct FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb);
-/* Convert baked/sampled fcurves into bezt/regular fcurves. */
+/**
+ * Convert baked/sampled f-curves into bezt/regular f-curves.
+ */
void fcurve_samples_to_keyframes(struct FCurve *fcu, const int start, const int end);
/* ************* F-Curve .blend file API ******************** */
diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h
index 5b4da4a78a4..18676dfcb38 100644
--- a/source/blender/blenkernel/BKE_fcurve_driver.h
+++ b/source/blender/blenkernel/BKE_fcurve_driver.h
@@ -66,34 +66,85 @@ struct PropertyRNA;
/* ---------------------- */
+/**
+ * This frees the driver itself.
+ */
void fcurve_free_driver(struct FCurve *fcu);
+/**
+ * This makes a copy of the given driver.
+ */
struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
+/**
+ * Copy driver variables from src_vars list to dst_vars list.
+ */
void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars);
+/**
+ * Compute channel values for a rotational Transform Channel driver variable.
+ */
void BKE_driver_target_matrix_to_rot_channels(
float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]);
+/**
+ * Perform actual freeing driver variable and remove it from the given list.
+ */
void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
+/**
+ * Free the driver variable and do extra updates.
+ */
void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
+/**
+ * Change the type of driver variable.
+ */
void driver_change_variable_type(struct DriverVar *dvar, int type);
+/**
+ * Validate driver variable name (after being renamed).
+ *
+ */
void driver_variable_name_validate(struct DriverVar *dvar);
+/**
+ * Add a new driver variable.
+ */
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
+/**
+ * Evaluate a Driver Variable to get a value that contributes to the final.
+ */
float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
+/**
+ * Same as 'dtar_get_prop_val'. but get the RNA property.
+ */
bool driver_get_variable_property(struct ChannelDriver *driver,
struct DriverTarget *dtar,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
int *r_index);
+/**
+ * Check if the expression in the driver conforms to the simple subset.
+ */
bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
+/**
+ * Check if the expression in the driver may depend on the current frame.
+ */
bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver);
+/**
+ * Reset cached compiled expression data.
+ */
void BKE_driver_invalidate_expression(struct ChannelDriver *driver,
bool expr_changed,
bool varname_changed);
+/**
+ * Evaluate an Channel-Driver to get a 'time' value to use
+ * instead of `anim_eval_context->eval_time`.
+ *
+ * - `anim_eval_context->eval_time` is the frame at which F-Curve is being evaluated.
+ * - Has to return a float value.
+ * - \a driver_orig is where we cache Python expressions, in case of COW
+ */
float evaluate_driver(struct PathResolvedRNA *anim_rna,
struct ChannelDriver *driver,
struct ChannelDriver *driver_orig,
diff --git a/source/blender/blenkernel/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h
index 33ff6943514..7bafcf00ce8 100644
--- a/source/blender/blenkernel/BKE_fluid.h
+++ b/source/blender/blenkernel/BKE_fluid.h
@@ -64,6 +64,10 @@ void BKE_fluid_cache_free_all(struct FluidDomainSettings *fds, struct Object *ob
void BKE_fluid_cache_free(struct FluidDomainSettings *fds, struct Object *ob, int cache_map);
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name);
+/**
+ * Get fluid velocity and density at given coordinates.
+ * \returns fluid density or -1.0f if outside domain.
+ */
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
int BKE_fluid_get_data_flags(struct FluidDomainSettings *fds);
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index 5e29665d728..ee3517f5b43 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -47,6 +47,10 @@ void BKE_freestyle_config_copy(struct FreestyleConfig *new_config,
struct FreestyleModuleConfig *BKE_freestyle_module_add(struct FreestyleConfig *config);
bool BKE_freestyle_module_delete(struct FreestyleConfig *config,
struct FreestyleModuleConfig *module_conf);
+/**
+ * Reinsert \a module_conf offset by \a direction from current position.
+ * \return if position of \a module_conf changed.
+ */
bool BKE_freestyle_module_move(struct FreestyleConfig *config,
struct FreestyleModuleConfig *module_conf,
int direction);
diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h
index 17cdb9d6a42..2d6218f1036 100644
--- a/source/blender/blenkernel/BKE_geometry_set.h
+++ b/source/blender/blenkernel/BKE_geometry_set.h
@@ -39,6 +39,8 @@ typedef enum GeometryComponentType {
GEO_COMPONENT_TYPE_CURVE = 4,
} GeometryComponentType;
+#define GEO_COMPONENT_TYPE_ENUM_SIZE 5
+
void BKE_geometry_set_free(struct GeometrySet *geometry_set);
bool BKE_object_has_geometry_set_instances(const struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 35e66908d54..79f29e0954e 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -62,7 +62,9 @@ class ComponentAttributeProviders;
class GeometryComponent;
/**
- * This is the base class for specialized geometry component types.
+ * This is the base class for specialized geometry component types. A geometry component handles
+ * a user count to allow avoiding duplication when it is wrapped with #UserCounter. It also handles
+ * the attribute API, which generalizes storing and modifying generic information on a geometry.
*/
class GeometryComponent {
private:
@@ -150,6 +152,10 @@ class GeometryComponent {
const AttributeInit &initializer);
blender::Set<blender::bke::AttributeIDRef> attribute_ids() const;
+ /**
+ * \return False if the callback explicitly returned false at any point, otherwise true,
+ * meaning the callback made it all the way through.
+ */
bool attribute_foreach(const AttributeForeachCallback callback) const;
virtual bool is_empty() const;
@@ -252,19 +258,33 @@ template<typename T>
inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryComponent, T>;
/**
- * A geometry set contains zero or more geometry components. There is at most one component of each
- * type. Individual components might be shared between multiple geometries. Shared components are
- * copied automatically when write access is requested.
+ * A geometry set is a container for multiple kinds of geometry. It does not own geometry directly
+ * itself, instead geometry is owned by multiple #GeometryComponents, and the geometry set
+ * increases the user count of each component, so they avoid losing the data. This means
+ * individual components might be shared between multiple geometries and other code. Shared
+ * components are copied automatically when write access is requested.
+ *
+ * The components usually do not store data directly, but keep a reference to a data
+ * structure defined elsewhere. There is at most one component of each type:
+ * - #MeshComponent
+ * - #CurveComponent
+ * - #PointCloudComponent
+ * - #InstancesComponent
+ * - #VolumeComponent
*
* Copying a geometry set is a relatively cheap operation, because it does not copy the referenced
- * geometry components.
+ * geometry components, so #GeometrySet can often be passed or moved by value.
*/
struct GeometrySet {
private:
using GeometryComponentPtr = blender::UserCounter<class GeometryComponent>;
- blender::Map<GeometryComponentType, GeometryComponentPtr> components_;
+ /* Indexed by #GeometryComponentType. */
+ std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;
public:
+ /**
+ * The methods are defaulted here so that they are not instantiated in every translation unit.
+ */
GeometrySet();
GeometrySet(const GeometrySet &other);
GeometrySet(GeometrySet &&other);
@@ -272,6 +292,10 @@ struct GeometrySet {
GeometrySet &operator=(const GeometrySet &other);
GeometrySet &operator=(GeometrySet &&other);
+ /**
+ * This method can only be used when the geometry set is mutable. It returns a mutable geometry
+ * component of the given type.
+ */
GeometryComponent &get_component_for_write(GeometryComponentType component_type);
template<typename Component> Component &get_component_for_write()
{
@@ -279,6 +303,9 @@ struct GeometrySet {
return static_cast<Component &>(this->get_component_for_write(Component::static_type));
}
+ /**
+ * Get the component of the given type. Might return null if the component does not exist yet.
+ */
const GeometryComponent *get_component_for_read(GeometryComponentType component_type) const;
template<typename Component> const Component *get_component_for_read() const
{
@@ -300,19 +327,33 @@ struct GeometrySet {
return this->remove(Component::static_type);
}
+ /**
+ * Remove all geometry components with types that are not in the provided list.
+ */
void keep_only(const blender::Span<GeometryComponentType> component_types);
void add(const GeometryComponent &component);
+ /**
+ * Get all geometry components in this geometry set for read-only access.
+ */
blender::Vector<const GeometryComponent *> get_components_for_read() const;
void compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const;
friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set);
+ /**
+ * Remove all geometry components from the geometry set.
+ */
void clear();
bool owns_direct_data() const;
+ /**
+ * Make sure that the geometry can be cached. This does not ensure ownership of object/collection
+ * instances. This is necessary because sometimes components only have read-only or editing
+ * access to their data, which might be freed later if this geometry set outlasts the data.
+ */
void ensure_owns_direct_data();
using AttributeForeachCallback =
@@ -335,46 +376,119 @@ struct GeometrySet {
using ForeachSubGeometryCallback = blender::FunctionRef<void(GeometrySet &geometry_set)>;
+ /**
+ * Modify every (recursive) instance separately. This is often more efficient than realizing all
+ * instances just to change the same thing on all of them.
+ */
void modify_geometry_sets(ForeachSubGeometryCallback callback);
/* Utility methods for creation. */
+ /**
+ * Create a new geometry set that only contains the given mesh.
+ */
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Create a new geometry set that only contains the given point cloud.
+ */
static GeometrySet create_with_pointcloud(
PointCloud *pointcloud, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Create a new geometry set that only contains the given curve.
+ */
static GeometrySet create_with_curve(
CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/* Utility methods for access. */
+ /**
+ * Returns true when the geometry set has a mesh component that has a mesh.
+ */
bool has_mesh() const;
+ /**
+ * Returns true when the geometry set has a point cloud component that has a point cloud.
+ */
bool has_pointcloud() const;
+ /**
+ * Returns true when the geometry set has an instances component that has at least one instance.
+ */
bool has_instances() const;
+ /**
+ * Returns true when the geometry set has a volume component that has a volume.
+ */
bool has_volume() const;
+ /**
+ * Returns true when the geometry set has a curve component that has a curve.
+ */
bool has_curve() const;
+ /**
+ * Returns true when the geometry set has any data that is not an instance.
+ */
bool has_realized_data() const;
+ /**
+ * Return true if the geometry set has any component that isn't empty.
+ */
bool is_empty() const;
+ /**
+ * Returns a read-only mesh or null.
+ */
const Mesh *get_mesh_for_read() const;
+ /**
+ * Returns a read-only point cloud of null.
+ */
const PointCloud *get_pointcloud_for_read() const;
+ /**
+ * Returns a read-only volume or null.
+ */
const Volume *get_volume_for_read() const;
+ /**
+ * Returns a read-only curve or null.
+ */
const CurveEval *get_curve_for_read() const;
+ /**
+ * Returns a mutable mesh or null. No ownership is transferred.
+ */
Mesh *get_mesh_for_write();
+ /**
+ * Returns a mutable point cloud or null. No ownership is transferred.
+ */
PointCloud *get_pointcloud_for_write();
+ /**
+ * Returns a mutable volume or null. No ownership is transferred.
+ */
Volume *get_volume_for_write();
+ /**
+ * Returns a mutable curve or null. No ownership is transferred.
+ */
CurveEval *get_curve_for_write();
/* Utility methods for replacement. */
+ /**
+ * Clear the existing mesh and replace it with the given one.
+ */
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing point cloud and replace with the given one.
+ */
void replace_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing volume and replace with the given one.
+ */
void replace_volume(Volume *volume,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing curve and replace it with the given one.
+ */
void replace_curve(CurveEval *curve,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
private:
- /* Utility to retrieve a mutable component without creating it. */
+ /**
+ * Retrieve the pointer to a component without creating it if it does not exist,
+ * unlike #get_component_for_write.
+ */
GeometryComponent *get_component_ptr(GeometryComponentType type);
template<typename Component> Component *get_component_ptr()
{
@@ -383,7 +497,13 @@ struct GeometrySet {
}
};
-/** A geometry component that can store a mesh. */
+/**
+ * A geometry component that can store a mesh, storing the #Mesh data structure.
+ *
+ * Attributes are stored in the mesh itself, on any of the four attribute domains. Generic
+ * attributes are stored in contiguous arrays, but often built-in attributes are stored in an
+ * array of structs fashion for historical reasons, requiring more complex attribute access.
+ */
class MeshComponent : public GeometryComponent {
private:
Mesh *mesh_ = nullptr;
@@ -396,10 +516,25 @@ class MeshComponent : public GeometryComponent {
void clear();
bool has_mesh() const;
+ /**
+ * Clear the component and replace it with the new mesh.
+ */
void replace(Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the mesh and clear the component. The caller takes over responsibility for freeing the
+ * mesh (if the component was responsible before).
+ */
Mesh *release();
+ /**
+ * Get the mesh from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned mesh should not be modified. No ownership is transferred.
+ */
const Mesh *get_for_read() const;
+ /**
+ * Get the mesh from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred.
+ */
Mesh *get_for_write();
int attribute_domain_size(const AttributeDomain domain) const final;
@@ -420,7 +555,16 @@ class MeshComponent : public GeometryComponent {
const AttributeDomain to_domain) const final;
};
-/** A geometry component that stores a point cloud. */
+/**
+ * A geometry component that stores a point cloud, corresponding to the #PointCloud data structure.
+ * While a point cloud is technically a subset of a mesh in some respects, it is useful because of
+ * its simplicity, partly on a conceptual level for the user, but also in the code, though partly
+ * for historical reasons. Point clouds can also be rendered in special ways, based on the built-in
+ * `radius` attribute.
+ *
+ * Attributes on point clouds are all stored in contiguous arrays in its #CustomData,
+ * which makes them efficient to process, relative to some legacy built-in mesh attributes.
+ */
class PointCloudComponent : public GeometryComponent {
private:
PointCloud *pointcloud_ = nullptr;
@@ -433,11 +577,28 @@ class PointCloudComponent : public GeometryComponent {
void clear();
bool has_pointcloud() const;
+ /**
+ * Clear the component and replace it with the new point cloud.
+ */
void replace(PointCloud *pointcloud,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the point cloud and clear the component. The caller takes over responsibility for
+ * freeing the point cloud (if the component was responsible before).
+ */
PointCloud *release();
+ /**
+ * Get the point cloud from this component. This method can be used by multiple threads at the
+ * same time. Therefore, the returned point cloud should not be modified. No ownership is
+ * transferred.
+ */
const PointCloud *get_for_read() const;
+ /**
+ * Get the point cloud from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
+ * transferred.
+ */
PointCloud *get_for_write();
int attribute_domain_size(const AttributeDomain domain) const final;
@@ -453,7 +614,13 @@ class PointCloudComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
-/** A geometry component that stores curve data, in other words, a group of splines. */
+/**
+ * A geometry component that stores curve data, in other words, a group of splines.
+ * Curves are stored differently than other geometry components, because the data structure used
+ * here does not correspond exactly to the #Curve DNA data structure. A #CurveEval is stored here
+ * instead, though the component does give access to a #Curve for interfacing with render engines
+ * and other areas of Blender that expect to use a data-block with an #ID.
+ */
class CurveComponent : public GeometryComponent {
private:
CurveEval *curve_ = nullptr;
@@ -475,6 +642,9 @@ class CurveComponent : public GeometryComponent {
void clear();
bool has_curve() const;
+ /**
+ * Clear the component and replace it with the new curve.
+ */
void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
CurveEval *release();
@@ -488,6 +658,10 @@ class CurveComponent : public GeometryComponent {
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
+ /**
+ * Create empty curve data used for rendering the spline's wire edges.
+ * \note See comment on #curve_for_render_ for further explanation.
+ */
const Curve *get_curve_for_render() const;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
@@ -501,6 +675,10 @@ class CurveComponent : public GeometryComponent {
const AttributeDomain to_domain) const final;
};
+/**
+ * Holds a reference to conceptually unique geometry or a pointer to object/collection data
+ * that is is instanced with a transform in #InstancesComponent.
+ */
class InstanceReference {
public:
enum class Type {
@@ -623,7 +801,19 @@ class InstanceReference {
}
};
-/** A geometry component that stores instances. */
+/**
+ * A geometry component that stores instances. The instance data can be any type described by
+ * #InstanceReference. Geometry instances can even contain instances themselves, for nested
+ * instancing. Each instance has an index into an array of unique instance data, and a transform.
+ * The component can also store generic attributes for each instance.
+ *
+ * The component works differently from other geometry components in that it stores
+ * data about instancing directly, rather than owning a pointer to a separate data structure.
+ *
+ * This component is not responsible for handling the interface to a render engine, or other
+ * areas that work with all visible geometry, that is handled by the dependency graph iterator
+ * (see `DEG_depsgraph_query.h`).
+ */
class InstancesComponent : public GeometryComponent {
private:
/**
@@ -636,18 +826,11 @@ class InstancesComponent : public GeometryComponent {
blender::Vector<int> instance_reference_handles_;
/** Transformation of the instances. */
blender::Vector<blender::float4x4> instance_transforms_;
- /**
- * IDs of the instances. They are used for consistency over multiple frames for things like
- * motion blur. Proper stable ID data that actually helps when rendering can only be generated
- * in some situations, so this vector is allowed to be empty, in which case the index of each
- * instance will be used for the final ID.
- */
- blender::Vector<int> instance_ids_;
- /* These almost unique ids are generated based on `ids_`, which might not contain unique ids at
- * all. They are *almost* unique, because under certain very unlikely circumstances, they are not
- * unique. Code using these ids should not crash when they are not unique but can generally
- * expect them to be unique. */
+ /* These almost unique ids are generated based on the `id` attribute, which might not contain
+ * unique ids at all. They are *almost* unique, because under certain very unlikely
+ * circumstances, they are not unique. Code using these ids should not crash when they are not
+ * unique but can generally expect them to be unique. */
mutable std::mutex almost_unique_ids_mutex_;
mutable blender::Array<int> almost_unique_ids_;
@@ -661,26 +844,47 @@ class InstancesComponent : public GeometryComponent {
void clear();
void reserve(int min_capacity);
+ /**
+ * Resize the transform, handles, and attributes to the specified capacity.
+ *
+ * \note This function should be used carefully, only when it's guaranteed
+ * that the data will be filled.
+ */
void resize(int capacity);
+ /**
+ * Returns a handle for the given reference.
+ * If the reference exists already, the handle of the existing reference is returned.
+ * Otherwise a new handle is added.
+ */
int add_reference(const InstanceReference &reference);
+ /**
+ * Add a reference to the instance reference with an index specified by the #instance_handle
+ * argument. For adding many instances, using #resize and accessing the transform array directly
+ * is preferred.
+ */
void add_instance(int instance_handle, const blender::float4x4 &transform);
blender::Span<InstanceReference> references() const;
void remove_unused_references();
+ /**
+ * If references have a collection or object type, convert them into geometry instances
+ * recursively. After that, the geometry sets can be edited. There may still be instances of
+ * other types of they can't be converted to geometry sets.
+ */
void ensure_geometry_instances();
+ /**
+ * With write access to the instances component, the data in the instanced geometry sets can be
+ * changed. This is a function on the component rather than each reference to ensure `const`
+ * correctness for that reason.
+ */
GeometrySet &geometry_set_from_reference(const int reference_index);
blender::Span<int> instance_reference_handles() const;
blender::MutableSpan<int> instance_reference_handles();
blender::MutableSpan<blender::float4x4> instance_transforms();
blender::Span<blender::float4x4> instance_transforms() const;
- blender::MutableSpan<int> instance_ids();
- blender::Span<int> instance_ids() const;
-
- blender::MutableSpan<int> instance_ids_ensure();
- void instance_ids_clear();
int instances_amount() const;
int references_amount() const;
@@ -706,7 +910,11 @@ class InstancesComponent : public GeometryComponent {
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
-/** A geometry component that stores volume grids. */
+/**
+ * A geometry component that stores volume grids, corresponding to the #Volume data structure.
+ * This component does not implement an attribute API, partly because storage of sparse volume
+ * information in grids is much more complicated than it is for other types
+ */
class VolumeComponent : public GeometryComponent {
private:
Volume *volume_ = nullptr;
@@ -719,10 +927,26 @@ class VolumeComponent : public GeometryComponent {
void clear();
bool has_volume() const;
+ /**
+ * Clear the component and replace it with the new volume.
+ */
void replace(Volume *volume, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Return the volume and clear the component. The caller takes over responsibility for freeing
+ * the volume (if the component was responsible before).
+ */
Volume *release();
+ /**
+ * Get the volume from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned volume should not be modified. No ownership is transferred.
+ */
const Volume *get_for_read() const;
+ /**
+ * Get the volume from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned volume can be modified. No ownership is
+ * transferred.
+ */
Volume *get_for_write();
bool owns_direct_data() const override;
@@ -755,13 +979,26 @@ class GeometryComponentFieldContext : public fn::FieldContext {
}
};
-class AttributeFieldInput : public fn::FieldInput {
+class GeometryFieldInput : public fn::FieldInput {
+ public:
+ using fn::FieldInput::FieldInput;
+
+ GVArray get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const override;
+
+ virtual GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const = 0;
+};
+
+class AttributeFieldInput : public GeometryFieldInput {
private:
std::string name_;
public:
AttributeFieldInput(std::string name, const CPPType &type)
- : fn::FieldInput(type, name), name_(std::move(name))
+ : GeometryFieldInput(type, name), name_(std::move(name))
{
category_ = Category::NamedAttribute;
}
@@ -778,9 +1015,9 @@ class AttributeFieldInput : public fn::FieldInput {
return name_;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const override;
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -788,16 +1025,16 @@ class AttributeFieldInput : public fn::FieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-class IDAttributeFieldInput : public fn::FieldInput {
+class IDAttributeFieldInput : public GeometryFieldInput {
public:
- IDAttributeFieldInput() : fn::FieldInput(CPPType::get<int>())
+ IDAttributeFieldInput() : GeometryFieldInput(CPPType::get<int>())
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const override;
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -805,7 +1042,7 @@ class IDAttributeFieldInput : public fn::FieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-class AnonymousAttributeFieldInput : public fn::FieldInput {
+class AnonymousAttributeFieldInput : public GeometryFieldInput {
private:
/**
* A strong reference is required to make sure that the referenced attribute is not removed
@@ -818,7 +1055,7 @@ class AnonymousAttributeFieldInput : public fn::FieldInput {
AnonymousAttributeFieldInput(StrongAnonymousAttributeID anonymous_id,
const CPPType &type,
std::string producer_name)
- : fn::FieldInput(type, anonymous_id.debug_name()),
+ : GeometryFieldInput(type, anonymous_id.debug_name()),
anonymous_id_(std::move(anonymous_id)),
producer_name_(producer_name)
{
@@ -834,9 +1071,9 @@ class AnonymousAttributeFieldInput : public fn::FieldInput {
return fn::Field<T>{field_input};
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const override;
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const override;
std::string socket_inspection_name() const override;
diff --git a/source/blender/blenkernel/BKE_geometry_set_instances.hh b/source/blender/blenkernel/BKE_geometry_set_instances.hh
index e5b28e4fbab..98120b07f2d 100644
--- a/source/blender/blenkernel/BKE_geometry_set_instances.hh
+++ b/source/blender/blenkernel/BKE_geometry_set_instances.hh
@@ -20,6 +20,9 @@
namespace blender::bke {
+/**
+ * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
+ */
GeometrySet object_get_evaluated_geometry_set(const Object &object);
/**
@@ -41,11 +44,19 @@ struct GeometryInstanceGroup {
Vector<float4x4> transforms;
};
+/**
+ * Return flattened vector of the geometry component's recursive instances. I.e. all collection
+ * instances and object instances will be expanded into the instances of their geometry components.
+ * Even the instances in those geometry components' will be included.
+ *
+ * \note For convenience (to avoid duplication in the caller), the returned vector also contains
+ * the argument geometry set.
+ *
+ * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
+ */
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups);
-GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set);
-
/**
* Add information about all the attributes on every component of the type. The resulting info
* will contain the highest complexity data type and the highest priority domain among every
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index d6cabbc1236..ecf2e1f32a0 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -37,35 +37,61 @@ struct Main;
typedef struct Global {
- /** Active pointers. */
+ /**
+ * Data for the current active blend file.
+ *
+ * Note that `CTX_data_main(C)` should be used where possible.
+ * Otherwise access via #G_MAIN.
+ */
struct Main *main;
- /** Strings: last saved */
- char ima[1024], lib[1024]; /* 1024 = FILE_MAX */
-
- /** When set: `G_MAIN->name` contains valid relative base path. */
- bool relbase_valid;
- bool save_over;
+ /** Last saved location for images. */
+ char ima[1024]; /* 1024 = FILE_MAX */
+ /** Last used location for library link/append. */
+ char lib[1024];
- /** Strings of recent opened files. */
+ /**
+ * Strings of recently opened files to show in the file menu.
+ * A list of #RecentFile read from #BLENDER_HISTORY_FILE.
+ */
struct ListBase recent_files;
- /** Has escape been pressed or Ctrl+C pressed in background mode, used for render quit. */
+ /**
+ * Set when Escape been pressed or `Ctrl-C` pressed in background mode.
+ * Used for render quit and some other background tasks such as baking.
+ */
bool is_break;
+ /**
+ * Blender is running without any Windows or OpenGLES context.
+ * Typically set by the `--background` command-line argument.
+ *
+ * Also enabled when build defines `WITH_PYTHON_MODULE` or `WITH_HEADLESS` are set
+ * (which use background mode by definition).
+ */
bool background;
+
+ /**
+ * Skip reading the startup file and user preferences.
+ * Also disable saving the preferences on exit (see #G_FLAG_USERPREF_NO_SAVE_ON_EXIT),
+ * see via the command line argument: `--factory-startup`.
+ */
bool factory_startup;
+ /**
+ * Set when the user is interactively moving (transforming) content.
+ * see: #G_TRANSFORM_OBJ and related flags.
+ */
short moving;
- /** To indicate render is busy, prevent render-window events etc. */
+ /** To indicate render is busy, prevent render-window events, animation playback etc. */
bool is_rendering;
/**
* Debug value, can be set from the UI and python, used for testing nonstandard features.
* DO NOT abuse it with generic checks like `if (G.debug_value > 0)`. Do not use it as bitflags.
* Only precise specific values should be checked for, to avoid unpredictable side-effects.
- * Please document here the value(s) you are using (or a range of values reserved to some area).
+ * Please document here the value(s) you are using (or a range of values reserved to some area):
* * -16384 and below: Reserved for python (add-ons) usage.
* * -1: Disable faster motion paths computation (since 08/2018).
* * 1 - 30: EEVEE debug/stats values (01/2018).
@@ -82,24 +108,50 @@ typedef struct Global {
*/
short debug_value;
- /** Saved to the blend file as #FileGlobal.globalf,
- * however this is now only used for runtime options. */
+ /**
+ * Saved to the blend file as #FileGlobal.globalf
+ *
+ * \note Currently this is only used for runtime options, adding flags to #G_FLAG_ALL_READFILE
+ * will cause them to be written and read to files.
+ */
int f;
struct {
- /** Logging vars (different loggers may use). */
+ /**
+ * Logging vars (different loggers may use).
+ * Set via `--log-level` command line argument.
+ */
int level;
- /** FILE handle or use stderr (we own this so close when done). */
+ /**
+ * FILE handle or use `stderr` (we own this so close when done).
+ * Set via `--log-file` command line argument.
+ */
void *file;
} log;
- /** debug flag, #G_DEBUG, #G_DEBUG_PYTHON & friends, set python or command line args */
+ /**
+ * Debug flag, #G_DEBUG, #G_DEBUG_PYTHON & friends, set via:
+ * - Command line arguments: `--debug`, `--debug-memory` ... etc.
+ * - Python API: `bpy.app.debug`, `bpy.app.debug_memory` ... etc.
+ */
int debug;
- /** This variable is written to / read from #FileGlobal.fileflags */
+ /**
+ * Control behavior of file reading/writing.
+ *
+ * This variable is written to / read from #FileGlobal.fileflags.
+ * See: #G_FILE_COMPRESS and related flags.
+ */
int fileflags;
- /** Message to use when auto execution fails. */
+ /**
+ * Message to show when loading a `.blend` file attempts to execute
+ * a Python script or driver-expression when doing so is disallowed.
+ *
+ * Set when `(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL) == 0`,
+ * so users can be alerted to the reason why the file may not be behaving as expected.
+ * Typically Python drivers.
+ */
char autoexec_fail[200];
} Global;
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index b58317f4815..a483d482bd5 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -86,65 +86,185 @@ struct bGPdata;
/* ------------ Grease-Pencil API ------------------ */
+/* clean vertex groups weights */
void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke_editcurve(struct bGPDstroke *gps);
+/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
+/* Free strokes belonging to a gp-frame */
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
+/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
+/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
void BKE_gpencil_free_layers(struct ListBase *list);
+/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all);
+/**
+ * Delete grease pencil evaluated data
+ * \param gpd_eval: Grease pencil data-block
+ */
void BKE_gpencil_eval_delete(struct bGPdata *gpd_eval);
void BKE_gpencil_free_layer_masks(struct bGPDlayer *gpl);
+/**
+ * Tag data-block for depsgraph update.
+ * Wrapper to avoid include Depsgraph tag functions in other modules.
+ * \param gpd: Grease pencil data-block.
+ */
void BKE_gpencil_tag(struct bGPdata *gpd);
void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
+/**
+ * Ensure selection status of stroke is in sync with its points.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
void BKE_gpencil_curve_sync_selection(struct bGPdata *gpd, struct bGPDstroke *gps);
+/* Assign unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_set(struct bGPdata *gpd, struct bGPDstroke *gps);
+/* Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps);
+/**
+ * Add a new gp-frame to the given layer.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
+/**
+ * Add a copy of the active gp-frame to the given layer.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
+/**
+ * Add a new gp-layer and make it the active layer.
+ * \param gpd: Grease pencil data-block
+ * \param name: Name of the layer
+ * \param setactive: Set as active
+ * \param add_to_header: Used to force the layer added at header
+ * \return Pointer to new layer
+ */
struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd,
const char *name,
const bool setactive,
const bool add_to_header);
+/**
+ * Add a new grease pencil data-block.
+ * \param bmain: Main pointer
+ * \param name: Name of the datablock
+ * \return Pointer to new data-block
+ */
struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]);
+/**
+ * Make a copy of a given gpencil frame.
+ * \param gpf_src: Source grease pencil frame
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src,
const bool dup_strokes);
+/**
+ * Make a copy of a given gpencil layer.
+ * \param gpl_src: Source grease pencil layer
+ * \return Pointer to new layer
+ */
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src,
const bool dup_frames,
const bool dup_strokes);
+/**
+ * Make a copy of a given gpencil layer settings.
+ */
void BKE_gpencil_layer_copy_settings(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst);
+/**
+ * Make a copy of strokes between gpencil frames.
+ * \param gpf_src: Source grease pencil frame
+ * \param gpf_dst: Destination grease pencil frame
+ */
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
+/* Create a hash with the list of selected frame number. */
void BKE_gpencil_frame_selected_hash(struct bGPdata *gpd, struct GHash *r_list);
+/* Make a copy of a given gpencil stroke editcurve */
struct bGPDcurve *BKE_gpencil_stroke_curve_duplicate(struct bGPDcurve *gpc_src);
+/**
+ * Make a copy of a given grease-pencil stroke.
+ * \param gps_src: Source grease pencil strokes.
+ * \param dup_points: Duplicate points data.
+ * \param dup_curve: Duplicate curve data.
+ * \return Pointer to new stroke.
+ */
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src,
const bool dup_points,
const bool dup_curve);
+/**
+ * Make a copy of a given gpencil data-block.
+ *
+ * XXX: Should this be deprecated?
+ */
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain,
const struct bGPdata *gpd,
bool internal_copy);
+/**
+ * Delete the last stroke of the given frame.
+ * \param gpl: Grease pencil layer
+ * \param gpf: Grease pencil frame
+ */
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
/* materials */
+/**
+ * Reassign strokes using a material.
+ * \param gpd: Grease pencil data-block
+ * \param totcol: Total materials
+ * \param index: Index of the material
+ */
void BKE_gpencil_material_index_reassign(struct bGPdata *gpd, int totcol, int index);
+/**
+ * Remove strokes using a material.
+ * \param gpd: Grease pencil data-block
+ * \param index: Index of the material
+ * \return True if removed
+ */
bool BKE_gpencil_material_index_used(struct bGPdata *gpd, int index);
+/**
+ * Remap material
+ * \param gpd: Grease pencil data-block
+ * \param remap: Remap index
+ * \param remap_len: Remap length
+ */
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len);
+/**
+ * Load a table with material conversion index for merged materials.
+ * \param ob: Grease pencil object.
+ * \param hue_threshold: Threshold for Hue.
+ * \param sat_threshold: Threshold for Saturation.
+ * \param val_threshold: Threshold for Value.
+ * \param r_mat_table: return material table.
+ * \return True if done.
+ */
bool BKE_gpencil_merge_materials_table_get(struct Object *ob,
const float hue_threshold,
const float sat_threshold,
const float val_threshold,
struct GHash *r_mat_table);
+/**
+ * Merge similar materials
+ * \param ob: Grease pencil object
+ * \param hue_threshold: Threshold for Hue
+ * \param sat_threshold: Threshold for Saturation
+ * \param val_threshold: Threshold for Value
+ * \param r_removed: Number of materials removed
+ * \return True if done
+ */
bool BKE_gpencil_merge_materials(struct Object *ob,
const float hue_threshold,
const float sat_threshold,
@@ -152,12 +272,42 @@ bool BKE_gpencil_merge_materials(struct Object *ob,
int *r_removed);
/* statistics functions */
+/**
+ * Calc grease pencil statistics functions.
+ * \param gpd: Grease pencil data-block
+ */
void BKE_gpencil_stats_update(struct bGPdata *gpd);
+/**
+ * Create a new stroke, with pre-allocated data buffers.
+ * \param mat_idx: Index of the material
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness);
+/**
+ * Create a new stroke and add to frame.
+ * \param gpf: Grease pencil frame
+ * \param mat_idx: Material index
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \param insert_at_head: Add to the head of the strokes list
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_add(
struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head);
+/**
+ * Add a stroke and copy the temporary drawing color value
+ * from one of the existing stroke.
+ * \param gpf: Grease pencil frame
+ * \param existing: Stroke with the style to copy
+ * \param mat_idx: Material index
+ * \param totpoints: Total points
+ * \param thickness: Stroke thickness
+ * \return Pointer to new stroke
+ */
struct bGPDstroke *BKE_gpencil_stroke_add_existing_style(struct bGPDframe *gpf,
struct bGPDstroke *existing,
int mat_idx,
@@ -170,6 +320,11 @@ struct bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points);
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
#define GPENCIL_STRENGTH_MIN 0.003f
+/**
+ * Check if the given layer is able to be edited or not.
+ * \param gpl: Grease pencil layer
+ * \return True if layer is editable
+ */
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl);
/* How gpencil_layer_getframe() should behave when there
@@ -185,28 +340,121 @@ typedef enum eGP_GetFrame_Mode {
GP_GETFRAME_ADD_COPY = 2,
} eGP_GetFrame_Mode;
+/**
+ * Get the appropriate gp-frame from a given layer
+ * - this sets the layer's actframe var (if allowed to)
+ * - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
+ *
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \param addnew: Add option
+ * \return Pointer to new frame
+ */
struct bGPDframe *BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl,
int cframe,
eGP_GetFrame_Mode addnew);
+/**
+ * Look up the gp-frame on the requested frame number, but don't add a new one.
+ * \param gpl: Grease pencil layer
+ * \param cframe: Frame number
+ * \return Pointer to frame
+ */
struct bGPDframe *BKE_gpencil_layer_frame_find(struct bGPDlayer *gpl, int cframe);
+/**
+ * Delete the given frame from a layer.
+ * \param gpl: Grease pencil layer
+ * \param gpf: Grease pencil frame
+ * \return True if delete was done
+ */
bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+/**
+ * Get layer by name
+ * \param gpd: Grease pencil data-block
+ * \param name: Layer name
+ * \return Pointer to layer
+ */
struct bGPDlayer *BKE_gpencil_layer_named_get(struct bGPdata *gpd, const char *name);
+/**
+ * Get the active grease pencil layer for editing.
+ * \param gpd: Grease pencil data-block
+ * \return Pointer to layer
+ */
struct bGPDlayer *BKE_gpencil_layer_active_get(struct bGPdata *gpd);
+/**
+ * Set active grease pencil layer.
+ * \param gpd: Grease pencil data-block
+ * \param active: Grease pencil layer to set as active
+ */
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active);
+/**
+ * Delete grease pencil layer.
+ * \param gpd: Grease pencil data-block
+ * \param gpl: Grease pencil layer
+ */
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
+/**
+ * Set locked layers for autolock mode.
+ * \param gpd: Grease pencil data-block
+ * \param unlock: Unlock flag
+ */
void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, const bool unlock);
+/**
+ * Add grease pencil mask layer.
+ * \param gpl: Grease pencil layer
+ * \param name: Name of the mask
+ * \return Pointer to new mask layer
+ */
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_add(struct bGPDlayer *gpl, const char *name);
+/**
+ * Remove grease pencil mask layer.
+ * \param gpl: Grease pencil layer
+ * \param mask: Grease pencil mask layer
+ */
void BKE_gpencil_layer_mask_remove(struct bGPDlayer *gpl, struct bGPDlayer_Mask *mask);
+/**
+ * Remove any reference to mask layer.
+ * \param gpd: Grease pencil data-block
+ * \param name: Name of the mask layer
+ */
void BKE_gpencil_layer_mask_remove_ref(struct bGPdata *gpd, const char *name);
+/**
+ * Get mask layer by name.
+ * \param gpl: Grease pencil layer
+ * \param name: Mask name
+ * \return Pointer to mask layer
+ */
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name);
+/**
+ * Sort grease pencil mask layers.
+ * \param gpd: Grease pencil data-block
+ * \param gpl: Grease pencil layer
+ */
void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl);
+/**
+ * Sort all grease pencil mask layer.
+ * \param gpd: Grease pencil data-block
+ */
void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd);
+/**
+ * Make a copy of a given gpencil mask layers.
+ */
void BKE_gpencil_layer_mask_copy(const struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst);
+/**
+ * Clean any invalid mask layer.
+ */
void BKE_gpencil_layer_mask_cleanup(struct bGPdata *gpd, struct bGPDlayer *gpl);
+/**
+ * Clean any invalid mask layer for all layers.
+ */
void BKE_gpencil_layer_mask_cleanup_all_layers(struct bGPdata *gpd);
+/**
+ * Sort grease pencil frames.
+ * \param gpl: Grease pencil layer
+ * \param r_has_duplicate_frames: Duplicated frames flag
+ */
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames);
struct bGPDlayer *BKE_gpencil_layer_get_by_name(struct bGPdata *gpd,
@@ -214,14 +462,43 @@ struct bGPDlayer *BKE_gpencil_layer_get_by_name(struct bGPdata *gpd,
int first_if_not_found);
/* Brush */
+/**
+ * Get grease pencil material from brush.
+ * \param brush: Brush
+ * \return Pointer to material
+ */
struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
+/**
+ * Set grease pencil brush material.
+ * \param brush: Brush
+ * \param material: Material
+ */
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
/* Object */
+/**
+ * Get active color, and add all default settings if we don't find anything.
+ * \param ob: Grease pencil object
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_active(struct Object *ob);
+/**
+ * Adds the pinned material to the object if necessary.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Pointer to material
+ */
struct Material *BKE_gpencil_object_material_ensure_from_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
+/**
+ * Assigns the material to object (if not already present) and returns its index (mat_nr).
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param material: Material
+ * \return Index of the material
+ */
int BKE_gpencil_object_material_ensure(struct Main *bmain,
struct Object *ob,
struct Material *material);
@@ -230,41 +507,140 @@ struct Material *BKE_gpencil_object_material_ensure_by_name(struct Main *bmain,
const char *name,
int *r_index);
+/**
+ * Creates a new grease-pencil material and assigns it to object.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \param name: Material name
+ * \param r_index: value is set to zero based index of the new material if \a r_index is not NULL.
+ * \return Material pointer.
+ */
struct Material *BKE_gpencil_object_material_new(struct Main *bmain,
struct Object *ob,
const char *name,
int *r_index);
+/**
+ * Get material index (0-based like mat_nr not actcol).
+ * \param ob: Grease pencil object
+ * \param ma: Material
+ * \return Index of the material
+ */
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma);
int BKE_gpencil_object_material_index_get_by_name(struct Object *ob, const char *name);
+/**
+ * Returns the material for a brush with respect to its pinned state.
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_from_brush_get(struct Object *ob,
struct Brush *brush);
+/**
+ * Returns the material index for a brush with respect to its pinned state.
+ * \param ob: Grease pencil object
+ * \param brush: Brush
+ * \return Material index.
+ */
int BKE_gpencil_object_material_get_index_from_brush(struct Object *ob, struct Brush *brush);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object
+ * \return Material pointer.
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(
struct Main *bmain, struct Object *ob, struct ToolSettings *ts);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * \param bmain: Main pointer
+ * \param ob: Grease pencil object.
+ * \param brush: Brush
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
+/**
+ * Guaranteed to return a material assigned to object. Returns never NULL.
+ * Only use this for materials unrelated to user input.
+ * \param ob: Grease pencil object
+ * \return Material pointer
+ */
struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Object *ob);
+/**
+ * Check if stroke has any point selected
+ * \param gps: Grease pencil stroke
+ * \return True if selected
+ */
bool BKE_gpencil_stroke_select_check(const struct bGPDstroke *gps);
/* vertex groups */
+/**
+ * Ensure stroke has vertex group.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps);
+/**
+ * Remove a vertex group.
+ * \param ob: Grease pencil object
+ * \param defgroup: deform group
+ */
void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+/**
+ * Make a copy of a given gpencil weights.
+ * \param gps_src: Source grease pencil stroke
+ * \param gps_dst: Destination grease pencil stroke
+ */
void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
/* Set active frame by layer. */
+/**
+ * Set current grease pencil active frame.
+ * \param depsgraph: Current depsgraph
+ * \param gpd: Grease pencil data-block.
+ */
void BKE_gpencil_frame_active_set(struct Depsgraph *depsgraph, struct bGPdata *gpd);
+/**
+ * Get range of selected frames in layer.
+ * Always the active frame is considered as selected, so if no more selected the range
+ * will be equal to the current active frame.
+ * \param gpl: Layer.
+ * \param r_initframe: Number of first selected frame.
+ * \param r_endframe: Number of last selected frame.
+ */
void BKE_gpencil_frame_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
+/**
+ * Get Falloff factor base on frame range
+ * \param gpf: Frame.
+ * \param actnum: Number of active frame in layer.
+ * \param f_init: Number of first selected frame.
+ * \param f_end: Number of last selected frame.
+ * \param cur_falloff: Curve with falloff factors.
+ */
float BKE_gpencil_multiframe_falloff_calc(
struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
+/**
+ * Create a default palette.
+ * \param bmain: Main pointer
+ * \param scene: Scene
+ */
void BKE_gpencil_palette_ensure(struct Main *bmain, struct Scene *scene);
+/**
+ * Create grease pencil strokes from image
+ * \param sima: Image
+ * \param gpd: Grease pencil data-block
+ * \param gpf: Grease pencil frame
+ * \param size: Size
+ * \param mask: Mask
+ * \return True if done
+ */
bool BKE_gpencil_from_image(struct SpaceImage *sima,
struct bGPdata *gpd,
struct bGPDframe *gpf,
@@ -272,7 +648,9 @@ bool BKE_gpencil_from_image(struct SpaceImage *sima,
const bool mask);
/* Iterators */
-/* frame & stroke are NULL if it is a layer callback. */
+/**
+ * Frame & stroke are NULL if it is a layer callback.
+ */
typedef void (*gpIterCb)(struct bGPDlayer *layer,
struct bGPDframe *frame,
struct bGPDstroke *stroke,
@@ -294,17 +672,45 @@ void BKE_gpencil_visible_stroke_advanced_iter(struct ViewLayer *view_layer,
extern void (*BKE_gpencil_batch_cache_dirty_tag_cb)(struct bGPdata *gpd);
extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd);
+/**
+ * Update original pointers in evaluated frame.
+ * \param gpf_orig: Original grease-pencil frame.
+ * \param gpf_eval: Evaluated grease pencil frame.
+ */
void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig,
const struct bGPDframe *gpf_eval);
+/**
+ * Update pointers of eval data to original data to keep references.
+ * \param ob_orig: Original grease pencil object
+ * \param ob_eval: Evaluated grease pencil object
+ */
void BKE_gpencil_update_orig_pointers(const struct Object *ob_orig, const struct Object *ob_eval);
+/**
+ * Get parent matrix, including layer parenting.
+ * \param depsgraph: Depsgraph
+ * \param obact: Grease pencil object
+ * \param gpl: Grease pencil layer
+ * \param diff_mat: Result parent matrix
+ */
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph,
struct Object *obact,
struct bGPDlayer *gpl,
float diff_mat[4][4]);
+/**
+ * Update parent matrix and local transforms.
+ * \param depsgraph: Depsgraph
+ * \param ob: Grease pencil object
+ */
void BKE_gpencil_update_layer_transforms(const struct Depsgraph *depsgraph, struct Object *ob);
+/**
+ * Find material by name prefix.
+ * \param ob: Object pointer
+ * \param name_prefix: Prefix name of the material
+ * \return Index
+ */
int BKE_gpencil_material_find_index_by_name_prefix(struct Object *ob, const char *name_prefix);
void BKE_gpencil_blend_read_data(struct BlendDataReader *reader, struct bGPdata *gpd);
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
index 9cbe67af9c1..044e2ff2336 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -35,6 +35,17 @@ struct bGPDlayer;
struct bGPDstroke;
struct bGPdata;
+/**
+ * Convert a curve object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_cu: Curve to convert.
+ * \param use_collections: Create layers using collection names.
+ * \param scale_thickness: Scale thickness factor.
+ * \param sample: Sample distance, zero to disable.
+ */
void BKE_gpencil_convert_curve(struct Main *bmain,
struct Scene *scene,
struct Object *ob_gp,
@@ -43,24 +54,42 @@ void BKE_gpencil_convert_curve(struct Main *bmain,
const float scale_thickness,
const float sample);
+/**
+ * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
+ */
struct bGPDcurve *BKE_gpencil_stroke_editcurve_generate(struct bGPDstroke *gps,
const float error_threshold,
const float corner_angle,
const float stroke_radius);
+/**
+ * Updates the edit-curve for a stroke. Frees the old curve if one exists and generates a new one.
+ */
void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDstroke *gps);
+/**
+ * Sync the selection from stroke to edit-curve.
+ */
void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPdata *gpd,
struct bGPDstroke *gps,
struct bGPDcurve *gpc);
+/**
+ * Sync the selection from edit-curve to stroke.
+ */
void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPdata *gpd,
struct bGPDstroke *gps,
struct bGPDcurve *gpc);
void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd);
void BKE_gpencil_strokes_selected_sync_selection_editcurve(struct bGPdata *gpd);
+/**
+ * Recalculate stroke points with the edit-curve of the stroke.
+ */
void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps,
const uint resolution,
const bool is_adaptive);
+/**
+ * Recalculate the handles of the edit curve of a grease pencil stroke.
+ */
void BKE_gpencil_editcurve_recalculate_handles(struct bGPDstroke *gps);
void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, const int cuts);
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 41b1bba10ba..4b9671c7881 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -38,38 +38,130 @@ struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
-/* Object boundbox. */
+/* Object bound-box. */
+
+/**
+ * Get min/max bounds of all strokes in grease pencil data-block.
+ * \param gpd: Grease pencil data-block
+ * \param r_min: Result minimum coordinates
+ * \param r_max: Result maximum coordinates
+ * \return True if it was possible to calculate
+ */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);
+/**
+ * Get min/max coordinate bounds for single stroke.
+ * \param gps: Grease pencil stroke
+ * \param use_select: Include only selected points
+ * \param r_min: Result minimum coordinates
+ * \param r_max: Result maximum coordinates
+ * \return True if it was possible to calculate
+ */
bool BKE_gpencil_stroke_minmax(const struct bGPDstroke *gps,
const bool use_select,
float r_min[3],
float r_max[3]);
+/**
+ * Get grease pencil object bounding box.
+ * \param ob: Grease pencil object
+ * \return Bounding box
+ */
struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob);
+/**
+ * Compute center of bounding box.
+ * \param gpd: Grease pencil data-block
+ * \param r_centroid: Location of the center
+ */
void BKE_gpencil_centroid_3d(struct bGPdata *gpd, float r_centroid[3]);
+/**
+ * Compute stroke bounding box.
+ * \param gps: Grease pencil Stroke
+ */
void BKE_gpencil_stroke_boundingbox_calc(struct bGPDstroke *gps);
-/* stroke geometry utilities */
+/* Stroke geometry utilities. */
+
+/**
+ * Calculate stroke normals.
+ * \param gps: Grease pencil stroke
+ * \param r_normal: Return Normal vector normalized
+ */
void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
+/**
+ * Reduce a series of points to a simplified version,
+ * but maintains the general shape of the series.
+ *
+ * Ramer - Douglas - Peucker algorithm
+ * by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ * \param epsilon: Epsilon value to define precision of the algorithm
+ */
void BKE_gpencil_stroke_simplify_adaptive(struct bGPdata *gpd,
struct bGPDstroke *gps,
float epsilon);
+/**
+ * Simplify alternate vertex of stroke except extremes.
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_simplify_fixed(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Subdivide a stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Stroke
+ * \param level: Level of subdivision
+ * \param type: Type of subdivision
+ */
void BKE_gpencil_stroke_subdivide(struct bGPdata *gpd,
struct bGPDstroke *gps,
int level,
int type);
+/**
+ * Trim stroke to the first intersection or loop.
+ * \param gps: Stroke data
+ */
bool BKE_gpencil_stroke_trim(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Reduce a series of points when the distance is below a threshold.
+ * Special case for first and last points (both are kept) for other points,
+ * the merge point always is at first point.
+ *
+ * \param gpd: Grease pencil data-block.
+ * \param gpf: Grease Pencil frame.
+ * \param gps: Grease Pencil stroke.
+ * \param threshold: Distance between points.
+ * \param use_unselected: Set to true to analyze all stroke and not only selected points.
+ */
void BKE_gpencil_stroke_merge_distance(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
const float threshold,
const bool use_unselected);
+/**
+ * Get points of stroke always flat to view not affected
+ * by camera view or view position.
+ * \param points: Array of grease pencil points (3D)
+ * \param totpoints: Total of points
+ * \param points2d: Result array of 2D points
+ * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
+ */
void BKE_gpencil_stroke_2d_flat(const struct bGPDspoint *points,
int totpoints,
float (*points2d)[2],
int *r_direction);
+/**
+ * Get points of stroke always flat to view not affected by camera view or view position
+ * using another stroke as reference.
+ * \param ref_points: Array of reference points (3D)
+ * \param ref_totpoints: Total reference points
+ * \param points: Array of points to flat (3D)
+ * \param totpoints: Total points
+ * \param points2d: Result array of 2D points
+ * \param scale: Scale factor
+ * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
+ */
void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points,
int ref_totpoints,
const struct bGPDspoint *points,
@@ -77,10 +169,28 @@ void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points,
float (*points2d)[2],
const float scale,
int *r_direction);
+/**
+ * Triangulate stroke to generate data for filling areas.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_fill_triangulate(struct bGPDstroke *gps);
+/**
+ * Recalc all internal geometry data for the stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps);
+/**
+ * Update Stroke UV data.
+ * \param gps: Grease pencil stroke
+ */
void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps);
+/**
+ * Apply grease pencil Transforms.
+ * \param gpd: Grease pencil data-block
+ * \param mat: Transformation matrix
+ */
void BKE_gpencil_transform(struct bGPdata *gpd, const float mat[4][4]);
typedef struct GPencilPointCoordinates {
@@ -90,27 +200,93 @@ typedef struct GPencilPointCoordinates {
float pressure;
} GPencilPointCoordinates;
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
int BKE_gpencil_stroke_point_count(const struct bGPdata *gpd);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_get(struct bGPdata *gpd, GPencilPointCoordinates *elem_data);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_apply(struct bGPdata *gpd, const GPencilPointCoordinates *elem_data);
+/**
+ * \note Used for "move only origins" in object_data_transform.c.
+ */
void BKE_gpencil_point_coords_apply_with_mat4(struct bGPdata *gpd,
const GPencilPointCoordinates *elem_data,
const float mat[4][4]);
+/**
+ * Resample a stroke
+ * \param gpd: Grease pencil data-block
+ * \param gps: Stroke to sample
+ * \param dist: Distance of one segment
+ */
bool BKE_gpencil_stroke_sample(struct bGPdata *gpd,
struct bGPDstroke *gps,
const float dist,
const bool select);
-bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps, int i, float inf);
+/**
+ * Apply smooth position to stroke point.
+ * \param gps: Stroke to smooth
+ * \param i: Point index
+ * \param inf: Amount of smoothing to apply
+ * \param smooth_caps: Apply smooth to stroke extremes
+ */
+bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps,
+ int i,
+ float inf,
+ const bool smooth_caps);
+/**
+ * Apply smooth strength to stroke point.
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Apply smooth for thickness to stroke point (use pressure).
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Apply smooth for UV rotation to stroke point (use pressure).
+ * \param gps: Stroke to smooth
+ * \param point_index: Point index
+ * \param influence: Amount of smoothing to apply
+ */
bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, int point_index, float influence);
+/**
+ * Close grease pencil stroke.
+ * \param gps: Stroke to close
+ */
bool BKE_gpencil_stroke_close(struct bGPDstroke *gps);
+/**
+ * Dissolve points in stroke.
+ * \param gpd: Grease pencil data-block
+ * \param gpf: Grease pencil frame
+ * \param gps: Grease pencil stroke
+ * \param tag: Type of tag for point
+ */
void BKE_gpencil_dissolve_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
const short tag);
+/**
+ * Backbone stretch similar to Freestyle.
+ * \param gps: Stroke to sample.
+ * \param dist: Length of the added section.
+ * \param overshoot_fac: Relative length of the curve which is used to determine the extension.
+ * \param mode: Affect to Start, End or Both extremes (0->Both, 1->Start, 2->End).
+ * \param follow_curvature: True for approximating curvature of given overshoot.
+ * \param extra_point_count: When follow_curvature is true, use this amount of extra points.
+ */
bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps,
const float dist,
const float overshoot_fac,
@@ -120,9 +296,20 @@ bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps,
const float segment_influence,
const float max_angle,
const bool invert_curvature);
+/**
+ * Trim stroke to needed segments.
+ * \param gps: Target stroke.
+ * \param index_from: the index of the first point to be used in the trimmed result.
+ * \param index_to: the index of the last point to be used in the trimmed result.
+ */
bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps,
const int index_from,
const int index_to);
+/**
+ * Split the given stroke into several new strokes, partitioning
+ * it based on whether the stroke points have a particular flag
+ * is set (e.g. #GP_SPOINT_SELECT in most cases, but not always).
+ */
struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
@@ -138,33 +325,84 @@ void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd,
struct bGPDcurve *gpc,
int tag_flags);
+/**
+ * Flip stroke.
+ */
void BKE_gpencil_stroke_flip(struct bGPDstroke *gps);
+/**
+ * Split stroke.
+ * \param gpd: Grease pencil data-block.
+ * \param gpf: Grease pencil frame.
+ * \param gps: Grease pencil original stroke.
+ * \param before_index: Position of the point to split.
+ * \param remaining_gps: Secondary stroke after split.
+ * \return True if the split was done
+ */
bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
const int before_index,
struct bGPDstroke **remaining_gps);
+/**
+ * Shrink the stroke by length.
+ * \param gps: Stroke to shrink
+ * \param dist: delta length
+ * \param mode: 1->Start, 2->End
+ */
bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist, const short mode);
+/**
+ * Calculate grease pencil stroke length.
+ * \param gps: Grease pencil stroke.
+ * \param use_3d: Set to true to use 3D points.
+ * \return Length of the stroke.
+ */
float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
+/** Calculate grease pencil stroke length between points. */
float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
const int start_index,
const int end_index,
bool use_3d);
+/**
+ * Set a random color to stroke using vertex color.
+ * \param gps: Stroke
+ */
void BKE_gpencil_stroke_set_random_color(struct bGPDstroke *gps);
+/**
+ * Join two strokes using the shortest distance (reorder stroke if necessary).
+ */
void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a,
struct bGPDstroke *gps_b,
const bool leave_gaps,
const bool fit_thickness,
const bool smooth);
+/**
+ * Copy the stroke of the frame to all frames selected (except current).
+ */
void BKE_gpencil_stroke_copy_to_keyframes(struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
const bool tail);
+/**
+ * Convert a mesh object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer.
+ * \param depsgraph: Original depsgraph.
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_mesh: Mesh to convert.
+ * \param angle: Limit angle to consider a edge-loop ends.
+ * \param thickness: Thickness of the strokes.
+ * \param offset: Offset along the normals.
+ * \param matrix: Transformation matrix.
+ * \param frame_offset: Destination frame number offset.
+ * \param use_seams: Only export seam edges.
+ * \param use_faces: Export faces as filled strokes.
+ */
bool BKE_gpencil_convert_mesh(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -179,24 +417,56 @@ bool BKE_gpencil_convert_mesh(struct Main *bmain,
const bool use_faces,
const bool use_vgroups);
+/**
+ * Subdivide the grease pencil stroke so the number of points is target_number.
+ * Does not change the shape of the stroke. The new points will be distributed as
+ * uniformly as possible by repeatedly subdividing the current longest edge.
+ *
+ * \param gps: The stroke to be up-sampled.
+ * \param target_number: The number of points the up-sampled stroke should have.
+ * \param select: Select/Deselect the stroke.
+ */
void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd,
struct bGPDstroke *gps,
const uint32_t target_number,
const bool select);
+/**
+ * Stroke to view space
+ * Transforms a stroke to view space.
+ * This allows for manipulations in 2D but also easy conversion back to 3D.
+ * \note also takes care of parent space transform.
+ */
void BKE_gpencil_stroke_to_view_space(struct RegionView3D *rv3d,
struct bGPDstroke *gps,
const float diff_mat[4][4]);
+/**
+ * Stroke from view space
+ * Transforms a stroke from view space back to world space.
+ * Inverse of #BKE_gpencil_stroke_to_view_space
+ * \note also takes care of parent space transform.
+ */
void BKE_gpencil_stroke_from_view_space(struct RegionView3D *rv3d,
struct bGPDstroke *gps,
const float diff_mat[4][4]);
+/**
+ * Calculates the perimeter of a stroke projected from the view and returns it as a new stroke.
+ * \param subdivisions: Number of subdivisions for the start and end caps.
+ * \return: bGPDstroke pointer to stroke perimeter.
+ */
struct bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
struct bGPdata *gpd,
const struct bGPDlayer *gpl,
struct bGPDstroke *gps,
const int subdivisions,
const float diff_mat[4][4]);
+/**
+ * Get average pressure.
+ */
float BKE_gpencil_stroke_average_pressure_get(struct bGPDstroke *gps);
+/**
+ * Check if the thickness of the stroke is constant.
+ */
bool BKE_gpencil_stroke_is_pressure_constant(struct bGPDstroke *gps);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index 33524e47473..5fc0abf6a2c 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -249,36 +249,114 @@ typedef struct GpencilModifierTypeInfo {
#define GPENCIL_MODIFIER_TYPE_PANEL_PREFIX "MOD_PT_gpencil_"
-/* Initialize modifier's global data (type info and some common global storage). */
+/**
+ * Initialize modifier's global data (type info and some common global storage).
+ */
void BKE_gpencil_modifier_init(void);
+/**
+ * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
+ *
+ * \param type: Type of modifier.
+ * \param r_idname: ID name.
+ */
void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname);
void BKE_gpencil_modifier_panel_expand(struct GpencilModifierData *md);
+/**
+ * Get grease pencil modifier information.
+ * \param type: Type of modifier.
+ * \return Pointer to type
+ */
const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type);
+/**
+ * Create new grease pencil modifier.
+ * \param type: Type of modifier.
+ * \return New modifier pointer.
+ */
struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
+/**
+ * Free grease pencil modifier data
+ * \param md: Modifier data.
+ * \param flag: Flags.
+ */
void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
+/**
+ * Free grease pencil modifier data
+ * \param md: Modifier data.
+ */
void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
+/* check unique name */
bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
+/**
+ * Check if grease pencil modifier depends on time.
+ * \param md: Modifier data.
+ * \return True if depends on time.
+ */
bool BKE_gpencil_modifier_depends_ontime(struct GpencilModifierData *md);
struct GpencilModifierData *BKE_gpencil_modifiers_findby_type(struct Object *ob,
GpencilModifierType type);
+/**
+ * Find grease pencil modifier by name.
+ * \param ob: Grease pencil object.
+ * \param name: Name to find.
+ * \return Pointer to modifier.
+ */
struct GpencilModifierData *BKE_gpencil_modifiers_findby_name(struct Object *ob, const char *name);
+/**
+ * Generic grease pencil modifier copy data.
+ * \param md_src: Source modifier data.
+ * \param md_dst: Target modifier data.
+ */
void BKE_gpencil_modifier_copydata_generic(const struct GpencilModifierData *md_src,
struct GpencilModifierData *md_dst);
+/**
+ * Copy grease pencil modifier data.
+ * \param md: Source modifier data.
+ * \param target: Target modifier data.
+ */
void BKE_gpencil_modifier_copydata(struct GpencilModifierData *md,
struct GpencilModifierData *target);
+/**
+ * Copy grease pencil modifier data.
+ * \param md: Source modifier data.
+ * \param target: Target modifier data.
+ * \param flag: Flags.
+ */
void BKE_gpencil_modifier_copydata_ex(struct GpencilModifierData *md,
struct GpencilModifierData *target,
const int flag);
+/**
+ * Set grease pencil modifier error.
+ * \param md: Modifier data.
+ * \param format: Format.
+ */
void BKE_gpencil_modifier_set_error(struct GpencilModifierData *md, const char *format, ...)
ATTR_PRINTF_FORMAT(2, 3);
+/**
+ * Link grease pencil modifier related IDs.
+ * \param ob: Grease pencil object.
+ * \param walk: Walk option.
+ * \param userData: User data.
+ */
void BKE_gpencil_modifiers_foreach_ID_link(struct Object *ob,
GreasePencilIDWalkFunc walk,
void *userData);
+/**
+ * Link grease pencil modifier related Texts.
+ * \param ob: Grease pencil object.
+ * \param walk: Walk option.
+ * \param userData: User data.
+ */
void BKE_gpencil_modifiers_foreach_tex_link(struct Object *ob,
GreasePencilTexWalkFunc walk,
void *userData);
+/**
+ * Check whether given modifier is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param gmd: May be NULL, in which case we consider it as a non-local modifier case.
+ */
bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const struct Object *ob,
const struct GpencilModifierData *gmd);
@@ -287,11 +365,30 @@ typedef struct GpencilVirtualModifierData {
LatticeGpencilModifierData lmd;
} GpencilVirtualModifierData;
+/**
+ * This is to include things that are not modifiers in the evaluation of the modifier stack,
+ * for example parenting to an armature or lattice without having a real modifier.
+ */
struct GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
const struct Object *ob, struct GpencilVirtualModifierData *data);
+/**
+ * Check if object has grease pencil Geometry modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
+/**
+ * Check if object has grease pencil Time modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
+/**
+ * Check if object has grease pencil transform stroke modifiers.
+ * \param ob: Grease pencil object.
+ * \return True if exist.
+ */
bool BKE_gpencil_has_transform_modifiers(struct Object *ob);
/* Stores the maximum calculation range in the whole modifier stack for line art so the cache can
@@ -310,21 +407,44 @@ void BKE_gpencil_set_lineart_modifier_limits(struct GpencilModifierData *md,
bool BKE_gpencil_is_first_lineart_in_stack(const struct Object *ob,
const struct GpencilModifierData *md);
-void BKE_gpencil_lattice_init(struct Object *ob);
-void BKE_gpencil_lattice_clear(struct Object *ob);
+void BKE_gpencil_cache_data_init(struct Depsgraph *depsgraph, struct Object *ob);
+void BKE_gpencil_cache_data_clear(struct Object *ob);
+/**
+ * Calculate grease-pencil modifiers.
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ */
void BKE_gpencil_modifiers_calc(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Prepare grease pencil eval data for modifiers
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ */
void BKE_gpencil_prepare_eval_data(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Get the current frame re-timed with time modifiers.
+ * \param depsgraph: Current depsgraph.
+ * \param scene: Current scene.
+ * \param ob: Grease pencil object.
+ * \param gpl: Grease pencil layer.
+ * \return New frame number.
+ */
struct bGPDframe *BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bGPDlayer *gpl);
+/**
+ * Get Time modifier frame number.
+ */
int BKE_gpencil_time_modifier_cfra(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 28a6f837f61..c96a37e0d09 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -97,76 +97,135 @@ enum eIconSizes;
void BKE_icons_init(int first_dyn_id);
-/* return icon id for library object or create new icon if not found */
+/**
+ * Return icon id for library object or create new icon if not found.
+ */
int BKE_icon_id_ensure(struct ID *id);
-/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */
+/**
+ * Return icon id for Grease Pencil layer (color preview) or create new icon if not found.
+ */
int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
+/**
+ * Return icon id of given preview, or create new icon if not found.
+ */
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
+/**
+ * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf,
+ * it needs to be stored separately.
+ * \note Transforms ownership of \a ibuf to the newly created icon.
+ */
int BKE_icon_imbuf_create(struct ImBuf *ibuf) ATTR_WARN_UNUSED_RESULT;
struct ImBuf *BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT;
-/* retrieve icon for id */
+/**
+ * Retrieve icon for id.
+ */
struct Icon *BKE_icon_get(const int icon_id);
-/* set icon for id if not already defined */
-/* used for inserting the internal icons */
+/**
+ * Set icon for id if not already defined.
+ * Used for inserting the internal icons.
+ */
void BKE_icon_set(const int icon_id, struct Icon *icon);
-/* remove icon and free data if library object becomes invalid */
+/**
+ * Remove icon and free data if library object becomes invalid.
+ */
void BKE_icon_id_delete(struct ID *id);
+/**
+ * Remove icon and free data.
+ */
bool BKE_icon_delete(const int icon_id);
bool BKE_icon_delete_unmanaged(const int icon_id);
-/* report changes - icon needs to be recalculated */
+/**
+ * Report changes - icon needs to be recalculated.
+ */
void BKE_icon_changed(const int icon_id);
-/* free all icons */
+/**
+ * Free all icons.
+ */
void BKE_icons_free(void);
-/* free all icons marked for deferred deletion */
+/**
+ * Free all icons marked for deferred deletion.
+ */
void BKE_icons_deferred_free(void);
-/* free the preview image for use in list */
+/**
+ * Free the preview image for use in list.
+ */
void BKE_previewimg_freefunc(void *link);
-/* free the preview image */
+/**
+ * Free the preview image.
+ */
void BKE_previewimg_free(struct PreviewImage **prv);
-/* clear the preview image or icon, but does not free it */
+/**
+ * Clear the preview image or icon, but does not free it.
+ */
void BKE_previewimg_clear(struct PreviewImage *prv);
-/* clear the preview image or icon at a specific size */
+/**
+ * Clear the preview image or icon at a specific size.
+ */
void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size);
-/* get the preview from any pointer */
+/**
+ * Get the preview from any pointer.
+ */
struct PreviewImage **BKE_previewimg_id_get_p(const struct ID *id);
struct PreviewImage *BKE_previewimg_id_get(const struct ID *id);
bool BKE_previewimg_id_supports_jobs(const struct ID *id);
-/* Trigger deferred loading of a custom image file into the preview buffer. */
+/**
+ * Trigger deferred loading of a custom image file into the preview buffer.
+ */
void BKE_previewimg_id_custom_set(struct ID *id, const char *path);
-/* free the preview image belonging to the id */
+/**
+ * Free the preview image belonging to the id.
+ */
void BKE_previewimg_id_free(struct ID *id);
-/* create a new preview image */
+/**
+ * Create a new preview image.
+ */
struct PreviewImage *BKE_previewimg_create(void);
-/* create a copy of the preview image */
+/**
+ * Create a copy of the preview image.
+ */
struct PreviewImage *BKE_previewimg_copy(const struct PreviewImage *prv);
+/**
+ * Duplicate preview image from \a id and clear icon_id,
+ * to be used by data-block copy functions.
+ */
void BKE_previewimg_id_copy(struct ID *new_id, const struct ID *old_id);
-/* retrieve existing or create new preview image */
+/**
+ * Retrieve existing or create new preview image.
+ */
struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
+/**
+ * Handle deferred (lazy) loading/generation of preview image, if needed.
+ * For now, only used with file thumbnails.
+ */
void BKE_previewimg_ensure(struct PreviewImage *prv, const int size);
+/**
+ * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
+ * \note The returned image buffer has to be free'd (#IMB_freeImBuf()).
+ */
struct ImBuf *BKE_previewimg_to_imbuf(struct PreviewImage *prv, const int size);
void BKE_previewimg_finish(struct PreviewImage *prv, const int size);
@@ -174,8 +233,15 @@ bool BKE_previewimg_is_finished(const struct PreviewImage *prv, const int size);
struct PreviewImage *BKE_previewimg_cached_get(const char *name);
+/**
+ * Generate an empty #PreviewImage, if not yet existing.
+ */
struct PreviewImage *BKE_previewimg_cached_ensure(const char *name);
+/**
+ * Generate a #PreviewImage from given file path, using thumbnails management, if not yet existing.
+ * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
+ */
struct PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
const int source,
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index c28ac63388b..1fb3636e9fd 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -56,11 +56,17 @@ typedef union IDPropertyTemplate {
/* ----------- Property Array Type ---------- */
+/**
+ * \note as a start to move away from the stupid #IDP_New function,
+ * this type has its own allocation function.
+ */
struct IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct IDProperty *IDP_CopyIDPArray(const struct IDProperty *array,
const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* shallow copies item */
+/**
+ * Shallow copies item.
+ */
void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL();
struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -68,11 +74,20 @@ void IDP_AppendArray(struct IDProperty *prop, struct IDProperty *item);
void IDP_ResizeIDPArray(struct IDProperty *prop, int len);
/* ----------- Numeric Array Type ----------- */
-/* This function works for strings too! */
+
+/**
+ * This function works for strings too!
+ */
void IDP_ResizeArray(struct IDProperty *prop, int newlen);
void IDP_FreeArray(struct IDProperty *prop);
/* ---------- String Type ------------ */
+/**
+ * \param st: The string to assign.
+ * \param name: The property name.
+ * \param maxlen: The size of the new string (including the \0 terminator).
+ * \return The new string property.
+ */
struct IDProperty *IDP_NewString(const char *st,
const char *name,
int maxlen) ATTR_WARN_UNUSED_RESULT
@@ -91,38 +106,90 @@ void IDP_AssignID(struct IDProperty *prop, struct ID *id, const int flag);
/*-------- Group Functions -------*/
-/** Sync values from one group to another, only where they match */
+/**
+ * Sync values from one group to another when values name and types match,
+ * copy the values, else ignore.
+ *
+ * \note Use for syncing proxies.
+ */
void IDP_SyncGroupValues(struct IDProperty *dest, const struct IDProperty *src) ATTR_NONNULL();
void IDP_SyncGroupTypes(struct IDProperty *dest,
const struct IDProperty *src,
const bool do_arraylen) ATTR_NONNULL();
+/**
+ * Replaces all properties with the same name in a destination group from a source group.
+ */
void IDP_ReplaceGroupInGroup(struct IDProperty *dest, const struct IDProperty *src) ATTR_NONNULL();
void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * Checks if a property with the same name as prop exists, and if so replaces it.
+ * Use this to preserve order!
+ */
void IDP_ReplaceInGroup_ex(struct IDProperty *group,
struct IDProperty *prop,
struct IDProperty *prop_exist);
+/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
void IDP_MergeGroup(struct IDProperty *dest, const struct IDProperty *src, const bool do_overwrite)
ATTR_NONNULL();
+/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
void IDP_MergeGroup_ex(struct IDProperty *dest,
const struct IDProperty *src,
const bool do_overwrite,
const int flag) ATTR_NONNULL();
+/**
+ * This function has a sanity check to make sure ID properties with the same name don't
+ * get added to the group.
+ *
+ * The sanity check just means the property is not added to the group if another property
+ * exists with the same name; the client code using ID properties then needs to detect this
+ * (the function that adds new properties to groups, #IDP_AddToGroup,
+ * returns false if a property can't be added to the group, and true if it can)
+ * and free the property.
+ */
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * This is the same as IDP_AddToGroup, only you pass an item
+ * in the group list to be inserted after.
+ */
bool IDP_InsertToGroup(struct IDProperty *group,
struct IDProperty *previous,
struct IDProperty *pnew) ATTR_NONNULL(1 /* group */, 3 /* pnew */);
+/**
+ * \note this does not free the property!
+ *
+ * To free the property, you have to do:
+ * #IDP_FreeProperty(prop);
+ */
void IDP_RemoveFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
+/**
+ * Removes the property from the group and frees it.
+ */
void IDP_FreeFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
struct IDProperty *IDP_GetPropertyFromGroup(const struct IDProperty *prop,
const char *name) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Same as above but ensure type match.
+ */
struct IDProperty *IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop,
const char *name,
const char type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/*-------- Main Functions --------*/
+/**
+ * Get the Group property that contains the id properties for ID id.
+ *
+ * \param create_if_needed: Set to create the group property and attach it to id if it doesn't
+ * exist; otherwise the function will return NULL if there's no Group property attached to the ID.
+ */
struct IDProperty *IDP_GetProperties(struct ID *id,
const bool create_if_needed) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -130,8 +197,15 @@ struct IDProperty *IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNU
ATTR_NONNULL();
struct IDProperty *IDP_CopyProperty_ex(const struct IDProperty *prop,
const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Copy content from source #IDProperty into destination one,
+ * freeing destination property's content first.
+ */
void IDP_CopyPropertyContent(struct IDProperty *dst, struct IDProperty *src) ATTR_NONNULL();
+/**
+ * \param is_strict: When false treat missing items as a match.
+ */
bool IDP_EqualsProperties_ex(struct IDProperty *prop1,
struct IDProperty *prop2,
const bool is_strict) ATTR_WARN_UNUSED_RESULT;
@@ -139,10 +213,41 @@ bool IDP_EqualsProperties_ex(struct IDProperty *prop1,
bool IDP_EqualsProperties(struct IDProperty *prop1,
struct IDProperty *prop2) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Allocate a new ID.
+ *
+ * This function takes three arguments: the ID property type, a union which defines
+ * its initial value, and a name.
+ *
+ * The union is simple to use; see the top of BKE_idprop.h for its definition.
+ * An example of using this function:
+ *
+ * \code{.c}
+ * IDPropertyTemplate val;
+ * IDProperty *group, *idgroup, *color;
+ * group = IDP_New(IDP_GROUP, val, "group1"); // groups don't need a template.
+ *
+ * val.array.len = 4
+ * val.array.type = IDP_FLOAT;
+ * color = IDP_New(IDP_ARRAY, val, "color1");
+ *
+ * idgroup = IDP_GetProperties(some_id, 1);
+ * IDP_AddToGroup(idgroup, color);
+ * IDP_AddToGroup(idgroup, group);
+ * \endcode
+ *
+ * Note that you MUST either attach the id property to an id property group with
+ * IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
+ * a memory leak.
+ */
struct IDProperty *IDP_New(const char type,
const IDPropertyTemplate *val,
const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
+ * But it does not free the actual #IDProperty struct itself.
+ */
void IDP_FreePropertyContent_ex(struct IDProperty *prop, const bool do_id_user);
void IDP_FreePropertyContent(struct IDProperty *prop);
void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user);
@@ -184,16 +289,35 @@ void IDP_Reset(struct IDProperty *prop, const struct IDProperty *reference);
# define IDP_Id(prop) ((ID *)(prop)->data.pointer)
#endif
+/**
+ * Return an int from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
int IDP_coerce_to_int_or_zero(const struct IDProperty *prop);
+/**
+ * Return a float from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
float IDP_coerce_to_float_or_zero(const struct IDProperty *prop);
+/**
+ * Return a double from an #IDProperty with a compatible type. This should be avoided, but
+ * it's sometimes necessary, for example when legacy files have incorrect property types.
+ */
double IDP_coerce_to_double_or_zero(const struct IDProperty *prop);
/**
- * Call a callback for each idproperty in the hierarchy under given root one (included).
- *
+ * Call a callback for each #IDproperty in the hierarchy under given root one (included).
*/
typedef void (*IDPForeachPropertyCallback)(struct IDProperty *id_property, void *user_data);
+/**
+ * Loop through all ID properties in hierarchy of given \a id_property_root included.
+ *
+ * \note Container types (groups and arrays) are processed after applying the callback on them.
+ *
+ * \param type_filter: If not 0, only apply callback on properties of matching types, see
+ * IDP_TYPE_FILTER_ enum in DNA_ID.h.
+ */
void IDP_foreach_property(struct IDProperty *id_property_root,
const int type_filter,
IDPForeachPropertyCallback callback,
@@ -230,6 +354,11 @@ typedef enum eIDPropertyUIDataType {
bool IDP_ui_data_supported(const struct IDProperty *prop);
eIDPropertyUIDataType IDP_ui_data_type(const struct IDProperty *prop);
void IDP_ui_data_free(struct IDProperty *prop);
+/**
+ * Free allocated pointers in the UI data that isn't shared with the UI data in the `other`
+ * argument. Useful for returning early on failure when updating UI data in place, or when
+ * replacing a subset of the UI data's allocated pointers.
+ */
void IDP_ui_data_free_unique_contents(struct IDPropertyUIData *ui_data,
eIDPropertyUIDataType type,
const struct IDPropertyUIData *other);
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index d33c24f2c75..8cd5d2a2361 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -35,6 +35,7 @@ struct BlendDataReader;
struct BlendExpander;
struct BlendLibReader;
struct BlendWriter;
+struct BPathForeachPathData;
struct ID;
struct LibraryForeachIDData;
struct Main;
@@ -81,7 +82,7 @@ typedef void (*IDTypeCopyDataFunction)(struct Main *bmain,
typedef void (*IDTypeFreeDataFunction)(struct ID *id);
-/** \param flag: See BKE_lib_id.h's LIB_ID_MAKELOCAL_... flags. */
+/** \param flags: See BKE_lib_id.h's LIB_ID_MAKELOCAL_... flags. */
typedef void (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, const int flags);
typedef void (*IDTypeForeachIDFunction)(struct ID *id, struct LibraryForeachIDData *data);
@@ -100,6 +101,8 @@ typedef void (*IDTypeForeachCacheFunction)(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data);
+typedef void (*IDTypeForeachPathFunction)(struct ID *id, struct BPathForeachPathData *bpath_data);
+
typedef struct ID *(*IDTypeEmbeddedOwnerGetFunction)(struct Main *bmain, struct ID *id);
typedef void (*IDTypeBlendWriteFunction)(struct BlendWriter *writer,
@@ -149,11 +152,12 @@ typedef struct IDTypeInfo {
/** Generic info flags about that data-block type. */
uint32_t flags;
- /* ********** ID management callbacks ********** */
+ /**
+ * Information and callbacks for assets, based on the type of asset.
+ */
+ struct AssetTypeInfo *asset_type_info;
- /* TODO: Note about callbacks: Ideally we could also handle here `BKE_lib_query`'s behavior, as
- * well as read/write of files. However, this is a bit more involved than basic ID management
- * callbacks, so we'll check on this later. */
+ /* ********** ID management callbacks ********** */
/**
* Initialize a new, empty calloc'ed data-block. May be NULL if there is nothing to do.
@@ -189,6 +193,11 @@ typedef struct IDTypeInfo {
IDTypeForeachCacheFunction foreach_cache;
/**
+ * Iterator over all file paths of given ID.
+ */
+ IDTypeForeachPathFunction foreach_path;
+
+ /**
* For embedded IDs, return their owner ID.
*/
IDTypeEmbeddedOwnerGetFunction owner_get;
@@ -228,11 +237,6 @@ typedef struct IDTypeInfo {
* \note Currently needed for some update operation on point caches.
*/
IDTypeLibOverrideApplyPost lib_override_apply_post;
-
- /**
- * Callbacks for assets, based on the type of asset.
- */
- struct AssetTypeInfo *asset_type_info;
} IDTypeInfo;
/* ********** Declaration of each IDTypeInfo. ********** */
@@ -279,6 +283,7 @@ extern IDTypeInfo IDType_ID_PT;
extern IDTypeInfo IDType_ID_VO;
extern IDTypeInfo IDType_ID_SIM;
+/** Empty shell mostly, but needed for read code. */
extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
/* ********** Helpers/Utils API. ********** */
@@ -290,32 +295,101 @@ void BKE_idtype_init(void);
const struct IDTypeInfo *BKE_idtype_get_info_from_idcode(const short id_code);
const struct IDTypeInfo *BKE_idtype_get_info_from_id(const struct ID *id);
+/**
+ * Convert an \a idcode into a name.
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the name of the code.
+ */
const char *BKE_idtype_idcode_to_name(const short idcode);
+/**
+ * Convert an \a idcode into a name (plural).
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the name of the code.
+ */
const char *BKE_idtype_idcode_to_name_plural(const short idcode);
+/**
+ * Convert an \a idcode into its translations' context.
+ *
+ * \param idcode: The code to convert.
+ * \return A static string representing the i18n context of the code.
+ */
const char *BKE_idtype_idcode_to_translation_context(const short idcode);
+/**
+ * Return if the ID code is a valid ID code.
+ *
+ * \param idcode: The code to check.
+ * \return Boolean, 0 when invalid.
+ */
bool BKE_idtype_idcode_is_valid(const short idcode);
+/**
+ * Check if an ID type is linkable.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when non linkable, true otherwise.
+ */
bool BKE_idtype_idcode_is_linkable(const short idcode);
+/**
+ * Check if an ID type is only appendable.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when also linkable, true when only appendable.
+ */
bool BKE_idtype_idcode_is_only_appendable(const short idcode);
+/**
+ * Check if an ID type can try to reuse and existing matching local one when being appended again.
+ *
+ * \param idcode: The IDType code to check.
+ * \return Boolean, false when it cannot be re-used, true otherwise.
+ */
bool BKE_idtype_idcode_append_is_reusable(const short idcode);
/* Macro currently, since any linkable IDtype should be localizable. */
#define BKE_idtype_idcode_is_localizable BKE_idtype_idcode_is_linkable
+/**
+ * Convert an ID-type name into an \a idcode (ie. #ID_SCE)
+ *
+ * \param idtype_name: The ID-type's "user visible name" to convert.
+ * \return The \a idcode for the name, or 0 if invalid.
+ */
short BKE_idtype_idcode_from_name(const char *idtype_name);
+/**
+ * Convert an \a idcode into an \a idfilter (e.g. #ID_OB -> #FILTER_ID_OB).
+ */
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode);
+/**
+ * Convert an \a idfilter into an \a idcode (e.g. #FILTER_ID_OB -> #ID_OB).
+ */
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter);
+/**
+ * Convert an \a idcode into an index (e.g. #ID_OB -> #INDEX_ID_OB).
+ */
int BKE_idtype_idcode_to_index(const short idcode);
+/**
+ * Get an \a idcode from an index (e.g. #INDEX_ID_OB -> #ID_OB).
+ */
short BKE_idtype_idcode_from_index(const int index);
+/**
+ * Return an ID code and steps the index forward 1.
+ *
+ * \param index: start as 0.
+ * \return the code, 0 when all codes have been returned.
+ */
short BKE_idtype_idcode_iter_step(int *index);
/* Some helpers/wrappers around callbacks defined in #IDTypeInfo, dealing e.g. with embedded IDs.
* XXX Ideally those would rather belong to #BKE_lib_id, but using callback function pointers makes
* this hard to do properly if we want to avoid headers includes in headers. */
+/**
+ * Wrapper around #IDTypeInfo foreach_cache that also handles embedded IDs.
+ */
void BKE_idtype_id_foreach_cache(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 77f1d197844..4db6da4b3ea 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -50,9 +50,16 @@ struct anim;
void BKE_image_free_packedfiles(struct Image *image);
void BKE_image_free_views(struct Image *image);
void BKE_image_free_buffers(struct Image *image);
+/**
+ * Simply free the image data from memory,
+ * on display the image can load again (except for render buffers).
+ */
void BKE_image_free_buffers_ex(struct Image *image, bool do_lock);
void BKE_image_free_gputextures(struct Image *ima);
-/* call from library */
+/**
+ * Free (or release) any data used by this image (does not free the image itself).
+ * \note Call from library.
+ */
void BKE_image_free_data(struct Image *image);
typedef void(StampCallback)(void *data, const char *propname, char *propvalue, int len);
@@ -66,6 +73,9 @@ void BKE_render_result_stamp_info(struct Scene *scene,
* The caller is responsible for freeing the allocated memory.
*/
struct StampData *BKE_stamp_info_from_scene_static(const struct Scene *scene);
+/**
+ * Check whether the given metadata field name translates to a known field of a stamp.
+ */
bool BKE_stamp_is_known_field(const char *field_name);
void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf);
@@ -90,8 +100,15 @@ int BKE_imbuf_write_stamp(struct Scene *scene,
struct ImBuf *ibuf,
const char *name,
const struct ImageFormatData *imf);
+/**
+ * \note imf->planes is ignored here, its assumed the image channels are already set.
+ */
void BKE_imbuf_write_prepare(struct ImBuf *ibuf, const struct ImageFormatData *imf);
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, const struct ImageFormatData *imf);
+/**
+ * Same as #BKE_imbuf_write() but crappy workaround not to permanently modify _some_,
+ * values in the imbuf.
+ */
int BKE_imbuf_write_as(struct ImBuf *ibuf,
const char *name,
struct ImageFormatData *imf,
@@ -125,11 +142,18 @@ bool BKE_imtype_requires_linear_float(const char imtype);
char BKE_imtype_valid_channels(const char imtype, bool write_file);
char BKE_imtype_valid_depths(const char imtype);
+/**
+ * String is from command line `--render-format` argument,
+ * keep in sync with `creator_args.c` help info.
+ */
char BKE_imtype_from_arg(const char *arg);
void BKE_imformat_defaults(struct ImageFormatData *im_format);
void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
+/**
+ * Used by sequencer too.
+ */
struct anim *openanim(const char *name,
int flags,
int streamindex,
@@ -164,11 +188,18 @@ struct RenderResult;
#define IMA_CHAN_FLAG_RGB 2
#define IMA_CHAN_FLAG_ALPHA 4
-/* checks whether there's an image buffer for given image and user */
+/**
+ * Checks whether there's an image buffer for given image and user.
+ */
bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser);
-/* same as above, but can be used to retrieve images being rendered in
- * a thread safe way, always call both acquire and release */
+/**
+ * Return image buffer for given image and user:
+ * - will lock render result if image type is render result and lock is not NULL
+ * - will return NULL if image is NULL or image type is render or composite result and lock is NULL
+ *
+ * References the result, #BKE_image_release_ibuf should be used to de-reference.
+ */
struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock);
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock);
@@ -179,17 +210,28 @@ struct ImBuf *BKE_image_pool_acquire_ibuf(struct Image *ima,
struct ImagePool *pool);
void BKE_image_pool_release_ibuf(struct Image *ima, struct ImBuf *ibuf, struct ImagePool *pool);
-/* set an alpha mode based on file extension */
+/**
+ * Set an alpha mode based on file extension.
+ */
char BKE_image_alpha_mode_from_extension_ex(const char *filepath);
void BKE_image_alpha_mode_from_extension(struct Image *image);
-/* returns a new image or NULL if it can't load */
+/**
+ * Returns a new image or NULL if it can't load.
+ */
struct Image *BKE_image_load(struct Main *bmain, const char *filepath);
-/* returns existing Image when filename/type is same (frame optional) */
+/**
+ * Returns existing Image when filename/type is same.
+ *
+ * Checks if image was already loaded, then returns same image otherwise creates new
+ * (does not load ibuf itself).
+ */
struct Image *BKE_image_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
struct Image *BKE_image_load_exists(struct Main *bmain, const char *filepath);
-/* adds image, adds ibuf, generates color or pattern */
+/**
+ * Adds new image block, creates ImBuf and initializes color.
+ */
struct Image *BKE_image_add_generated(struct Main *bmain,
unsigned int width,
unsigned int height,
@@ -201,10 +243,15 @@ struct Image *BKE_image_add_generated(struct Main *bmain,
const bool stereo3d,
const bool is_data,
const bool tiled);
-/* adds image from imbuf, owns imbuf */
+/**
+ * Create an image from ibuf. The reference-count of ibuf is increased,
+ * caller should take care to drop its reference by calling #IMB_freeImBuf if needed.
+ */
struct Image *BKE_image_add_from_imbuf(struct Main *bmain, struct ImBuf *ibuf, const char *name);
-/* for reload, refresh, pack */
+/**
+ * For reload, refresh, pack.
+ */
void BKE_imageuser_default(struct ImageUser *iuser);
void BKE_image_init_imageuser(struct Image *ima, struct ImageUser *iuser);
void BKE_image_signal(struct Main *bmain, struct Image *ima, struct ImageUser *iuser, int signal);
@@ -216,61 +263,100 @@ void BKE_image_walk_all_users(const struct Main *mainp,
struct ImageUser *iuser,
void *customdata));
-/* ensures an Image exists for viewing nodes or render */
+/**
+ * Ensures an Image exists for viewing nodes or render
+ * forces existence of 1 Image for render-output or nodes, returns Image.
+ *
+ * \param name: Only for default, when making new one.
+ */
struct Image *BKE_image_ensure_viewer(struct Main *bmain, int type, const char *name);
-/* ensures the view node cache is compatible with the scene views */
+/**
+ * Ensures the view node cache is compatible with the scene views.
+ * Reset the image cache and views when the Viewer Nodes views don't match the scene views.
+ */
void BKE_image_ensure_viewer_views(const struct RenderData *rd,
struct Image *ima,
struct ImageUser *iuser);
-/* called on frame change or before render */
+/**
+ * Called on frame change or before render.
+ */
void BKE_image_user_frame_calc(struct Image *ima, struct ImageUser *iuser, int cfra);
int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range);
void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path);
void BKE_image_editors_update_frame(const struct Main *bmain, int cfra);
-/* dependency graph update for image user users */
+/**
+ * Dependency graph update for image user users.
+ */
bool BKE_image_user_id_has_animation(struct ID *id);
void BKE_image_user_id_eval_animation(struct Depsgraph *depsgraph, struct ID *id);
-/* sets index offset for multilayer files */
+/**
+ * Sets index offset for multi-layer files and because rendered results use fake layer/passes,
+ * don't correct for wrong indices here.
+ */
struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
-/* sets index offset for multiview files */
+/**
+ * Sets index offset for multi-view files.
+ */
void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
-/* for multilayer images as well as for render-viewer */
+/**
+ * For multi-layer images as well as for render-viewer
+ * and because rendered results use fake layer/passes, don't correct for wrong indices here.
+ */
bool BKE_image_is_multilayer(struct Image *ima);
bool BKE_image_is_multiview(struct Image *ima);
bool BKE_image_is_stereo(struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
-/* For multi-layer images as well as for single-layer. */
+/**
+ * For multi-layer images as well as for single-layer.
+ */
bool BKE_image_is_openexr(struct Image *ima);
-/* For multiple slot render, call this before render. */
+/**
+ * For multiple slot render, call this before render.
+ */
void BKE_image_backup_render(struct Scene *scene, struct Image *ima, bool free_current_slot);
-/* For single-layer OpenEXR saving */
+/**
+ * For single-layer OpenEXR saving.
+ */
bool BKE_image_save_openexr_multiview(struct Image *ima,
struct ImBuf *ibuf,
const char *filepath,
const int flags);
-/* goes over all textures that use images */
+/**
+ * Goes over all textures that use images.
+ */
void BKE_image_free_all_textures(struct Main *bmain);
-/* does one image! */
+/**
+ * Operates on one image only!
+ * \param except_frame: This is weak, only works for sequences without offset.
+ */
void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
-/* does all images with type MOVIE or SEQUENCE */
+/**
+ * Does all images with type MOVIE or SEQUENCE.
+ */
void BKE_image_all_free_anim_ibufs(struct Main *bmain, int cfra);
void BKE_image_free_all_gputextures(struct Main *bmain);
+/**
+ * Same as above but only free animated images.
+ */
void BKE_image_free_anim_gputextures(struct Main *bmain);
void BKE_image_free_old_gputextures(struct Main *bmain);
+/**
+ * Pack image to memory.
+ */
bool BKE_image_memorypack(struct Image *ima);
void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath);
void BKE_image_packfiles_from_mem(struct ReportList *reports,
@@ -278,22 +364,34 @@ void BKE_image_packfiles_from_mem(struct ReportList *reports,
char *data,
const size_t data_len);
-/* Prints memory statistics for images. */
+/**
+ * Prints memory statistics for images.
+ */
void BKE_image_print_memlist(struct Main *bmain);
-/* Merge source into dest, and free source. */
+/**
+ * Merge source into `dest`, and free `source`.
+ */
void BKE_image_merge(struct Main *bmain, struct Image *dest, struct Image *source);
-/* Scale the image. */
+/**
+ * Scale the image.
+ */
bool BKE_image_scale(struct Image *image, int width, int height);
-/* Check if texture has alpha (depth=32). */
+/**
+ * Check if texture has alpha (depth=32).
+ */
bool BKE_image_has_alpha(struct Image *image);
-/* Check if texture has GPU texture code. */
+/**
+ * Check if texture has GPU texture code.
+ */
bool BKE_image_has_opengl_texture(struct Image *ima);
-/* Get tile index for tiled images. */
+/**
+ * Get tile index for tiled images.
+ */
void BKE_image_get_tile_label(struct Image *ima,
struct ImageTile *tile,
char *label,
@@ -320,6 +418,9 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
const float uv[2],
float r_uv[2],
float r_ofs[2]);
+/**
+ * Return the tile_number for the closest UDIM tile.
+ */
int BKE_image_find_nearest_tile(const struct Image *image, const float co[2]);
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *r_width, int *r_height);
@@ -327,6 +428,7 @@ void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float r
void BKE_image_get_aspect(struct Image *image, float *r_aspx, float *r_aspy);
/* image_gen.c */
+
void BKE_image_buf_fill_color(
unsigned char *rect, float *rect_float, int width, int height, const float color[4]);
void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height);
@@ -336,36 +438,64 @@ void BKE_image_buf_fill_checker_color(unsigned char *rect,
int height);
/* Cycles hookup */
+
unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame, int tile);
float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int tile);
/* Image modifications */
+
bool BKE_image_is_dirty(struct Image *image);
void BKE_image_mark_dirty(struct Image *image, struct ImBuf *ibuf);
bool BKE_image_buffer_format_writable(struct ImBuf *ibuf);
+
bool BKE_image_is_dirty_writable(struct Image *image, bool *is_format_writable);
-/* Guess offset for the first frame in the sequence */
+/**
+ * Guess offset for the first frame in the sequence.
+ */
int BKE_image_sequence_guess_offset(struct Image *image);
bool BKE_image_has_anim(struct Image *image);
bool BKE_image_has_packedfile(const struct Image *image);
bool BKE_image_has_filepath(struct Image *ima);
+/**
+ * Checks the image buffer changes with time (not keyframed values).
+ */
bool BKE_image_is_animated(struct Image *image);
+/**
+ * Checks whether the image consists of multiple buffers.
+ */
bool BKE_image_has_multiple_ibufs(struct Image *image);
void BKE_image_file_format_set(struct Image *image,
int ftype,
const struct ImbFormatOptions *options);
bool BKE_image_has_loaded_ibuf(struct Image *image);
+/**
+ * References the result, #BKE_image_release_ibuf is to be called to de-reference.
+ * Use lock=NULL when calling #BKE_image_release_ibuf().
+ */
struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name);
+/**
+ * References the result, #BKE_image_release_ibuf is to be called to de-reference.
+ * Use lock=NULL when calling #BKE_image_release_ibuf().
+ *
+ * TODO(sergey): This is actually "get first item from the cache", which is
+ * not so much predictable. But using first loaded image buffer
+ * was also malicious logic and all the areas which uses this
+ * function are to be re-considered.
+ */
struct ImBuf *BKE_image_get_first_ibuf(struct Image *image);
-/* Not to be use directly. */
+/**
+ * Not to be use directly.
+ */
struct GPUTexture *BKE_image_create_gpu_texture_from_ibuf(struct Image *image, struct ImBuf *ibuf);
-/* Get the #GPUTexture for a given `Image`.
+/**
+ * Get the #GPUTexture for a given `Image`.
*
* `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
- * available. It is also required when requesting the #GPUTexture for a render result. */
+ * available. It is also required when requesting the #GPUTexture for a render result.
+ */
struct GPUTexture *BKE_image_get_gpu_texture(struct Image *image,
struct ImageUser *iuser,
struct ImBuf *ibuf);
@@ -375,14 +505,33 @@ struct GPUTexture *BKE_image_get_gpu_tiles(struct Image *image,
struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image,
struct ImageUser *iuser,
struct ImBuf *ibuf);
+/**
+ * Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied.
+ */
bool BKE_image_has_gpu_texture_premultiplied_alpha(struct Image *image, struct ImBuf *ibuf);
+/**
+ * Partial update of texture for texture painting.
+ * This is often much quicker than fully updating the texture for high resolution images.
+ */
void BKE_image_update_gputexture(
struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
+/**
+ * Mark areas on the #GPUTexture that needs to be updated. The areas are marked in chunks.
+ * The next time the #GPUTexture is used these tiles will be refreshes. This saves time
+ * when writing to the same place multiple times This happens for during foreground rendering.
+ */
void BKE_image_update_gputexture_delayed(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+/**
+ * Called on entering and exiting texture paint mode,
+ * temporary disabling/enabling mipmapping on all images for quick texture
+ * updates with glTexSubImage2D. images that didn't change don't have to be re-uploaded to OpenGL.
+ */
void BKE_image_paint_set_mipmap(struct Main *bmain, bool mipmap);
-/* Delayed free of OpenGL buffers by main thread */
+/**
+ * Delayed free of OpenGL buffers by main thread.
+ */
void BKE_image_free_unused_gpu_textures(void);
struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name);
diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h
index f4871c83caf..5899db6c6ce 100644
--- a/source/blender/blenkernel/BKE_ipo.h
+++ b/source/blender/blenkernel/BKE_ipo.h
@@ -28,6 +28,19 @@ extern "C" {
struct Main;
+/**
+ * Called from #do_versions() in `readfile.c` to convert the old 'IPO/adrcode' system
+ * to the new 'Animato/RNA' system.
+ *
+ * The basic method used here, is to loop over data-blocks which have IPO-data,
+ * and add those IPO's to new AnimData blocks as Actions.
+ * Action/NLA data only works well for Objects, so these only need to be checked for there.
+ *
+ * Data that has been converted should be freed immediately, which means that it is immediately
+ * clear which data-blocks have yet to be converted, and also prevent freeing errors when we exit.
+ *
+ * \note Currently done after all file reading.
+ */
void do_versions_ipos_to_animato(struct Main *main);
/* --------------------- xxx stuff ------------------------ */
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index cb4fc607703..de069d6236f 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -36,21 +36,44 @@ struct Object;
extern "C" {
#endif
+/**
+ * Free (or release) any data used by this shapekey (does not free the key itself).
+ */
void BKE_key_free_data(struct Key *key);
void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct Main *bmain, struct ID *id);
+/**
+ * Sort shape keys after a change.
+ * This assumes that at most one key was moved,
+ * which is a valid assumption for the places it's currently being called.
+ */
void BKE_key_sort(struct Key *key);
void key_curve_position_weights(float t, float data[4], int type);
+/**
+ * First derivative.
+ */
void key_curve_tangent_weights(float t, float data[4], int type);
+/**
+ * Second derivative.
+ */
void key_curve_normal_weights(float t, float data[4], int type);
+/**
+ * Returns key coordinates (+ tilt) when key applied, NULL otherwise.
+ */
float *BKE_key_evaluate_object_ex(struct Object *ob, int *r_totelem, float *arr, size_t arr_size);
float *BKE_key_evaluate_object(struct Object *ob, int *r_totelem);
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
int BKE_keyblock_element_count_from_shape(const struct Key *key, const int shape_index);
int BKE_keyblock_element_count(const struct Key *key);
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
size_t BKE_keyblock_element_calc_size_from_shape(const struct Key *key, const int shape_index);
size_t BKE_keyblock_element_calc_size(const struct Key *key);
@@ -60,18 +83,43 @@ struct Key **BKE_key_from_id_p(struct ID *id);
struct Key *BKE_key_from_id(struct ID *id);
struct Key **BKE_key_from_object_p(const struct Object *ob);
struct Key *BKE_key_from_object(const struct Object *ob);
+/**
+ * Only the active key-block.
+ */
struct KeyBlock *BKE_keyblock_from_object(struct Object *ob);
struct KeyBlock *BKE_keyblock_from_object_reference(struct Object *ob);
struct KeyBlock *BKE_keyblock_add(struct Key *key, const char *name);
+/**
+ * \note sorting is a problematic side effect in some cases,
+ * better only do this explicitly by having its own function,
+ *
+ * \param key: The key datablock to add to.
+ * \param name: Optional name for the new keyblock.
+ * \param do_force: always use ctime even for relative keys.
+ */
struct KeyBlock *BKE_keyblock_add_ctime(struct Key *key, const char *name, const bool do_force);
+/**
+ * Get the appropriate #KeyBlock given an index.
+ */
struct KeyBlock *BKE_keyblock_from_key(struct Key *key, int index);
+/**
+ * Get the appropriate #KeyBlock given a name to search for.
+ */
struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]);
+/**
+ * \brief copy shape-key attributes, but not key data or name/UID.
+ */
void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src);
+/**
+ * Get RNA-Path for 'value' setting of the given shape-key.
+ * \note the user needs to free the returned string once they're finish with it.
+ */
char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb);
/* conversion functions */
/* NOTE: 'update_from' versions do not (re)allocate mem in kb, while 'convert_from' do. */
+
void BKE_keyblock_update_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_to_lattice(struct KeyBlock *kb, struct Lattice *lt);
@@ -88,6 +136,15 @@ void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct
void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb);
void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct Key *key, struct KeyBlock *kb);
void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me);
+/**
+ * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
+ *
+ * \param kb: the KeyBlock to use to compute normals.
+ * \param mesh: the Mesh to apply key-block to.
+ * \param r_vertnors: if non-NULL, an array of vectors, same length as number of vertices.
+ * \param r_polynors: if non-NULL, an array of vectors, same length as number of polygons.
+ * \param r_loopnors: if non-NULL, an array of vectors, same length as number of loops.
+ */
void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
struct Mesh *mesh,
float (*r_vertnors)[3],
@@ -107,28 +164,54 @@ void BKE_keyblock_update_from_offset(struct Object *ob,
const float (*ofs)[3]);
/* other management */
+
+/**
+ * Move shape key from org_index to new_index. Safe, clamps index to valid range,
+ * updates reference keys, the object's active shape index,
+ * the 'frame' value in case of absolute keys, etc.
+ * Note indices are expected in real values (not 'fake' shapenr +1 ones).
+ *
+ * \param org_index: if < 0, current object's active shape will be used as skey to move.
+ * \return true if something was done, else false.
+ */
bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
+/**
+ * Check if given key-block (as index) is used as basis by others in given key.
+ */
bool BKE_keyblock_is_basis(struct Key *key, const int index);
/* -------------------------------------------------------------------- */
/** \name Key-Block Data Access
* \{ */
+/**
+ * \param shape_index: The index to use or all (when -1).
+ */
void BKE_keyblock_data_get_from_shape(const struct Key *key,
float (*arr)[3],
const int shape_index);
void BKE_keyblock_data_get(const struct Key *key, float (*arr)[3]);
+/**
+ * Set the data to all key-blocks (or shape_index if != -1).
+ */
void BKE_keyblock_data_set_with_mat4(struct Key *key,
const int shape_index,
const float (*coords)[3],
const float mat[4][4]);
+/**
+ * Set the data for all key-blocks (or shape_index if != -1),
+ * transforming by \a mat.
+ */
void BKE_keyblock_curve_data_set_with_mat4(struct Key *key,
const struct ListBase *nurb,
const int shape_index,
const void *data,
const float mat[4][4]);
+/**
+ * Set the data for all key-blocks (or shape_index if != -1).
+ */
void BKE_keyblock_data_set(struct Key *key, const int shape_index, const void *data);
/** \} */
diff --git a/source/blender/blenkernel/BKE_keyconfig.h b/source/blender/blenkernel/BKE_keyconfig.h
index 1cacbf61976..132994ede3a 100644
--- a/source/blender/blenkernel/BKE_keyconfig.h
+++ b/source/blender/blenkernel/BKE_keyconfig.h
@@ -43,10 +43,12 @@ typedef struct wmKeyConfigPrefType_Runtime {
typedef struct wmKeyConfigPrefType_Runtime wmKeyConfigPrefType_Runtime;
#endif
-/* KeyConfig preferences (UserDef). */
+/* KeyConfig preferences (#UserDef). */
+
struct wmKeyConfigPref *BKE_keyconfig_pref_ensure(struct UserDef *userdef, const char *kc_idname);
/* KeyConfig preferences (RNA). */
+
struct wmKeyConfigPrefType_Runtime *BKE_keyconfig_pref_type_find(const char *idname, bool quiet);
void BKE_keyconfig_pref_type_add(struct wmKeyConfigPrefType_Runtime *kpt_rt);
void BKE_keyconfig_pref_type_remove(const struct wmKeyConfigPrefType_Runtime *kpt_rt);
@@ -55,6 +57,10 @@ void BKE_keyconfig_pref_type_init(void);
void BKE_keyconfig_pref_type_free(void);
/* Versioning. */
+
+/**
+ * Set select mouse, for versioning code.
+ */
void BKE_keyconfig_pref_set_select_mouse(struct UserDef *userdef, int value, bool override);
struct wmKeyConfigFilterItemParams {
@@ -67,6 +73,10 @@ void BKE_keyconfig_keymap_filter_item(struct wmKeyMap *keymap,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(struct wmKeyMapItem *kmi, void *user_data),
void *user_data);
+/**
+ * Filter & optionally remove key-map items,
+ * intended for versioning, but may be used in other situations too.
+ */
void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(struct wmKeyMapItem *kmi, void *user_data),
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 02fa8b306d3..bf03e99bbc3 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -132,6 +132,7 @@ void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice,
const char *defgrp_name,
const float fac,
struct BMEditMesh *em_target);
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index 08b44959096..b2fa464aedc 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -52,23 +52,57 @@ typedef enum eViewLayerCopyMethod {
VIEWLAYER_ADD_COPY = 2,
} eViewLayerCopyMethod;
+/**
+ * Returns the default view layer to view in work-spaces if there is
+ * none linked to the workspace yet.
+ */
struct ViewLayer *BKE_view_layer_default_view(const struct Scene *scene);
+/**
+ * Returns the default view layer to render if we need to render just one.
+ */
struct ViewLayer *BKE_view_layer_default_render(const struct Scene *scene);
+/**
+ * Returns view layer with matching name, or NULL if not found.
+ */
struct ViewLayer *BKE_view_layer_find(const struct Scene *scene, const char *layer_name);
+/**
+ * Add a new view layer by default, a view layer has the master collection.
+ */
struct ViewLayer *BKE_view_layer_add(struct Scene *scene,
const char *name,
struct ViewLayer *view_layer_source,
const int type);
/* DEPRECATED */
+/**
+ * This is a placeholder to know which areas of the code need to be addressed
+ * for the Workspace changes. Never use this, you should typically get the
+ * active layer from the context or window.
+ */
struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene);
void BKE_view_layer_free(struct ViewLayer *view_layer);
+/**
+ * Free (or release) any data used by this #ViewLayer.
+ */
void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user);
+/**
+ * Tag all the selected objects of a render-layer.
+ */
void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag);
+/**
+ * Fallback for when a Scene has no camera to use.
+ *
+ * \param view_layer: in general you want to use the same #ViewLayer that is used for depsgraph.
+ * If rendering you pass the scene active layer, when viewing in the viewport
+ * you want to get #ViewLayer from context.
+ */
struct Object *BKE_view_layer_camera_find(struct ViewLayer *view_layer);
+/**
+ * Find the #ViewLayer a #LayerCollection belongs to.
+ */
struct ViewLayer *BKE_view_layer_find_from_collection(const struct Scene *scene,
struct LayerCollection *lc);
struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob);
@@ -76,6 +110,11 @@ void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer);
void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, struct Base *selbase);
+/**
+ * Only copy internal data of #ViewLayer from source to already allocated/initialized destination.
+ *
+ * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
+ */
void BKE_view_layer_copy_data(struct Scene *scene_dst,
const struct Scene *scene_src,
struct ViewLayer *view_layer_dst,
@@ -87,15 +126,33 @@ void BKE_view_layer_rename(struct Main *bmain,
struct ViewLayer *view_layer,
const char *name);
+/**
+ * Get the active collection
+ */
struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer);
+/**
+ * Activate collection
+ */
bool BKE_layer_collection_activate(struct ViewLayer *view_layer, struct LayerCollection *lc);
+/**
+ * Activate first parent collection.
+ */
struct LayerCollection *BKE_layer_collection_activate_parent(struct ViewLayer *view_layer,
struct LayerCollection *lc);
+/**
+ * Get the total number of collections (including all the nested collections)
+ */
int BKE_layer_collection_count(const struct ViewLayer *view_layer);
+/**
+ * Get the collection for a given index.
+ */
struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer,
const int index);
+/**
+ * \return -1 if not found.
+ */
int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct LayerCollection *lc);
void BKE_layer_collection_resync_forbid(void);
@@ -103,20 +160,43 @@ void BKE_layer_collection_resync_allow(void);
void BKE_main_collection_sync(const struct Main *bmain);
void BKE_scene_collection_sync(const struct Scene *scene);
+/**
+ * Update view layer collection tree from collections used in the scene.
+ * This is used when collections are removed or added, both while editing
+ * and on file loaded in case linked data changed or went missing.
+ */
void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer);
void BKE_layer_collection_local_sync(struct ViewLayer *view_layer, const struct View3D *v3d);
+/**
+ * Sync the local collection for all the 3D Viewports.
+ */
void BKE_layer_collection_local_sync_all(const struct Main *bmain);
void BKE_main_collection_sync_remap(const struct Main *bmain);
+/**
+ * Return the first matching #LayerCollection in the #ViewLayer for the Collection.
+ */
struct LayerCollection *BKE_layer_collection_first_from_scene_collection(
const struct ViewLayer *view_layer, const struct Collection *collection);
+/**
+ * See if view layer has the scene collection linked directly, or indirectly (nested).
+ */
bool BKE_view_layer_has_collection(const struct ViewLayer *view_layer,
const struct Collection *collection);
+/**
+ * See if the object is in any of the scene layers of the scene.
+ */
bool BKE_scene_has_object(struct Scene *scene, struct Object *ob);
-/* selection and hiding */
+/* Selection and hiding. */
+/**
+ * Select all the objects of this layer collection
+ *
+ * It also select the objects that are in nested collections.
+ * \note Recursive.
+ */
bool BKE_layer_collection_objects_select(struct ViewLayer *view_layer,
struct LayerCollection *lc,
bool deselect);
@@ -125,28 +205,54 @@ bool BKE_layer_collection_has_selected_objects(struct ViewLayer *view_layer,
bool BKE_layer_collection_has_layer_collection(struct LayerCollection *lc_parent,
struct LayerCollection *lc_child);
+/**
+ * Update after toggling visibility of an object base.
+ */
void BKE_base_set_visible(struct Scene *scene,
struct ViewLayer *view_layer,
struct Base *base,
bool extend);
bool BKE_base_is_visible(const struct View3D *v3d, const struct Base *base);
bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob);
+/**
+ * Isolate the collection - hide all other collections but this one.
+ * Make sure to show all the direct parents and all children of the layer collection as well.
+ * When extending we simply show the collections and its direct family.
+ *
+ * If the collection or any of its parents is disabled, make it enabled.
+ * Don't change the children disable state though.
+ */
void BKE_layer_collection_isolate_global(struct Scene *scene,
struct ViewLayer *view_layer,
struct LayerCollection *lc,
bool extend);
+/**
+ * Isolate the collection locally
+ *
+ * Same as #BKE_layer_collection_isolate_local but for a viewport
+ */
void BKE_layer_collection_isolate_local(struct ViewLayer *view_layer,
const struct View3D *v3d,
struct LayerCollection *lc,
bool extend);
+/**
+ * Hide/show all the elements of a collection.
+ * Don't change the collection children enable/disable state,
+ * but it may change it for the collection itself.
+ */
void BKE_layer_collection_set_visible(struct ViewLayer *view_layer,
struct LayerCollection *lc,
const bool visible,
const bool hierarchy);
void BKE_layer_collection_set_flag(struct LayerCollection *lc, const int flag, const bool value);
-/* evaluation */
+/* Evaluation. */
+/**
+ * Applies object's restrict flags on top of flags coming from the collection
+ * and stores those in `base->flag`. #BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility
+ * (i.e., restriction and local collection).
+ */
void BKE_base_eval_flags(struct Base *base);
void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph,
@@ -380,6 +486,13 @@ struct Object **BKE_view_layer_array_selected_objects_params(
uint *r_len,
const struct ObjectsInViewLayerParams *params);
+/**
+ * Use this in rare cases we need to detect a pair of objects (active, selected).
+ * This returns the other non-active selected object.
+ *
+ * Returns NULL with it finds multiple other selected objects
+ * as behavior in this case would be random from the user perspective.
+ */
struct Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
const struct View3D *v3d);
@@ -451,9 +564,20 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(const struct Object *ob, void *us
struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer);
void BKE_view_layer_remove_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
void BKE_view_layer_set_active_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov);
+/**
+ * Update the naming and conflicts of the AOVs.
+ *
+ * Name must be unique between all AOVs.
+ * Conflicts with render passes will show a conflict icon. Reason is that switching a render
+ * engine or activating a render pass could lead to other conflicts that wouldn't be that clear
+ * for the user.
+ */
void BKE_view_layer_verify_aov(struct RenderEngine *engine,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Check if the given view layer has at least one valid AOV.
+ */
bool BKE_view_layer_has_valid_aov(struct ViewLayer *view_layer);
struct ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene,
struct ViewLayerAOV *view_layer_aov);
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 359fb72534a..34339c4ff9f 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -62,21 +62,65 @@ struct PointerRNA;
struct PropertyRNA;
struct bContext;
+/**
+ * Get allocation size of a given data-block type and optionally allocation name.
+ */
size_t BKE_libblock_get_alloc_info(short type, const char **name);
+/**
+ * Allocates and returns memory of the right size for the specified block type,
+ * initialized to zero.
+ */
void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Allocates and returns a block of the specified type, with the specified name
+ * (adjusted as necessary to ensure uniqueness), and appended to the specified list.
+ * The user count is set to 1, all other content (apart from name and links) being
+ * initialized to zero.
+ */
void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Initialize an ID of given type, such that it has valid 'empty' data.
+ * ID is assumed to be just calloc'ed.
+ */
void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
/* *** ID's session_uuid management. *** */
-/* When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.). */
+/**
+ * When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.).
+ */
#define MAIN_ID_SESSION_UUID_UNSET 0
+/**
+ * Generate a session-wise uuid for the given \a id.
+ *
+ * \note "session-wise" here means while editing a given .blend file. Once a new .blend file is
+ * loaded or created, undo history is cleared/reset, and so is the uuid counter.
+ */
void BKE_lib_libblock_session_uuid_ensure(struct ID *id);
+/**
+ * Re-generate a new session-wise uuid for the given \a id.
+ *
+ * \warning This has a few very specific use-cases, no other usage is expected currently:
+ * - To handle UI-related data-blocks that are kept across new file reading, when we do keep
+ * existing UI.
+ * - For IDs that are made local without needing any copying.
+ */
void BKE_lib_libblock_session_uuid_renew(struct ID *id);
+/**
+ * Generic helper to create a new empty data-block of given type in given \a bmain database.
+ *
+ * \param name: can be NULL, in which case we get default name for this ID type.
+ */
void *BKE_id_new(struct Main *bmain, const short type, const char *name);
+/**
+ * Generic helper to create a new temporary empty data-block of given type,
+ * *outside* of any Main database.
+ *
+ * \param name: can be NULL, in which case we get default name for this ID type.
+ */
void *BKE_id_new_nomain(const short type, const char *name);
/**
@@ -159,10 +203,20 @@ void BKE_libblock_copy_ex(struct Main *bmain,
const struct ID *id,
struct ID **r_newid,
const int orig_flag);
+/**
+ * Used everywhere in blenkernel.
+ */
void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Sets the name of a block to name, suitably adjusted for uniqueness.
+ */
void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
+/**
+ * Use after setting the ID's name
+ * When name exists: call 'new_id'
+ */
void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
struct ID *BKE_libblock_find_name(struct Main *bmain,
@@ -216,17 +270,70 @@ enum {
void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL();
void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL();
+/**
+ * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
+ * this function will need to be called too, if Python has access to the data.
+ *
+ * ID data-blocks such as #Material.nodetree are not stored in #Main.
+ */
void BKE_libblock_free_data_py(struct ID *id);
+/**
+ * Complete ID freeing, extended version for corner cases.
+ * Can override default (and safe!) freeing process, to gain some speed up.
+ *
+ * At that point, given id is assumed to not be used by any other data-block already
+ * (might not be actually true, in case e.g. several inter-related IDs get freed together...).
+ * However, they might still be using (referencing) other IDs, this code takes care of it if
+ * #LIB_TAG_NO_USER_REFCOUNT is not defined.
+ *
+ * \param bmain: #Main database containing the freed #ID,
+ * can be NULL in case it's a temp ID outside of any #Main.
+ * \param idv: Pointer to ID to be freed.
+ * \param flag: Set of \a LIB_ID_FREE_... flags controlling/overriding usual freeing process,
+ * 0 to get default safe behavior.
+ * \param use_flag_from_idtag: Still use freeing info flags from given #ID datablock,
+ * even if some overriding ones are passed in \a flag parameter.
+ */
void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag);
+/**
+ * Complete ID freeing, should be usable in most cases (even for out-of-Main IDs).
+ *
+ * See #BKE_id_free_ex description for full details.
+ *
+ * \param bmain: Main database containing the freed ID,
+ * can be NULL in case it's a temp ID outside of any Main.
+ * \param idv: Pointer to ID to be freed.
+ */
void BKE_id_free(struct Main *bmain, void *idv);
+/**
+ * Not really a freeing function by itself,
+ * it decrements usercount of given id, and only frees it if it reaches 0.
+ */
void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
+/**
+ * Properly delete a single ID from given \a bmain database.
+ */
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
+/**
+ * Properly delete all IDs tagged with \a LIB_TAG_DOIT, in given \a bmain database.
+ *
+ * This is more efficient than calling #BKE_id_delete repetitively on a large set of IDs
+ * (several times faster when deleting most of the IDs at once).
+ *
+ * \warning Considered experimental for now, seems to be working OK but this is
+ * risky code in a complicated area.
+ * \return Number of deleted datablocks.
+ */
size_t BKE_id_multi_tagged_delete(struct Main *bmain) ATTR_NONNULL();
+/**
+ * Add a 'NO_MAIN' data-block to given main (also sets usercounts of its IDs if needed).
+ */
void BKE_libblock_management_main_add(struct Main *bmain, void *idv);
+/** Remove a data-block from given main (set it to 'NO_MAIN' status). */
void BKE_libblock_management_main_remove(struct Main *bmain, void *idv);
void BKE_libblock_management_usercounts_set(struct Main *bmain, void *idv);
@@ -234,10 +341,23 @@ void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv);
void id_lib_extern(struct ID *id);
void id_lib_indirect_weak_link(struct ID *id);
+/**
+ * Ensure we have a real user
+ *
+ * \note Now that we have flags, we could get rid of the 'fake_user' special case,
+ * flags are enough to ensure we always have a real user.
+ * However, #ID_REAL_USERS is used in several places outside of core lib.c,
+ * so think we can wait later to make this change.
+ */
void id_us_ensure_real(struct ID *id);
void id_us_clear_real(struct ID *id);
+/**
+ * Same as \a id_us_plus, but does not handle lib indirect -> extern.
+ * Only used by readfile.c so far, but simpler/safer to keep it here nonetheless.
+ */
void id_us_plus_no_lib(struct ID *id);
void id_us_plus(struct ID *id);
+/* decrements the user count for *id. */
void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
@@ -262,66 +382,212 @@ enum {
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16,
};
+/**
+ * Generic 'make local' function, works for most of data-block types.
+ */
void BKE_lib_id_make_local_generic(struct Main *bmain, struct ID *id, const int flags);
+/**
+ * Calls the appropriate make_local method for the block, unless test is set.
+ *
+ * \note Always set #ID.newid pointer in case it gets duplicated.
+ *
+ * \param flags: Special flag used when making a whole library's content local,
+ * it needs specific handling.
+ * \return true is the ID has successfully been made local.
+ */
bool BKE_lib_id_make_local(struct Main *bmain, struct ID *id, const int flags);
+/**
+ * \note Does *not* set #ID.newid pointer.
+ */
bool id_single_user(struct bContext *C,
struct ID *id,
struct PointerRNA *ptr,
struct PropertyRNA *prop);
bool BKE_id_copy_is_allowed(const struct ID *id);
+/**
+ * Invokes the appropriate copy method for the block and returns the result in
+ * #ID.newid, unless test. Returns true if the block can be copied.
+ */
struct ID *BKE_id_copy(struct Main *bmain, const struct ID *id);
+/**
+ * Generic entry point for copying a data-block (new API).
+ *
+ * \note Copy is generally only affecting the given data-block
+ * (no ID used by copied one will be affected, besides user-count).
+ *
+ * There are exceptions though:
+ * - Embedded IDs (root node trees and master collections) are always copied with their owner.
+ * - If #LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated.
+ * - If #LIB_ID_COPY_SHAPEKEY is defined, shape-keys will be duplicated.
+ * - If #LIB_ID_CREATE_LOCAL is defined, root node trees will be deep-duplicated recursively.
+ *
+ * \note User-count of new copy is always set to 1.
+ *
+ * \param bmain: Main database, may be NULL only if LIB_ID_CREATE_NO_MAIN is specified.
+ * \param id: Source data-block.
+ * \param r_newid: Pointer to new (copied) ID pointer, may be NULL.
+ * Used to allow copying into already allocated memory.
+ * \param flag: Set of copy options, see `DNA_ID.h` enum for details
+ * (leave to zero for default, full copy).
+ * \return NULL when copying that ID type is not supported, the new copy otherwise.
+ */
struct ID *BKE_id_copy_ex(struct Main *bmain,
const struct ID *id,
struct ID **r_newid,
const int flag);
+/**
+ * Invokes the appropriate copy method for the block and returns the result in
+ * newid, unless test. Returns true if the block can be copied.
+ */
struct ID *BKE_id_copy_for_duplicate(struct Main *bmain,
struct ID *id,
const uint duplicate_flags,
const int copy_flags);
+/**
+ * Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note Most internal ID data itself is not swapped (only IDProperties are).
+ *
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
+ * itself.
+ */
void BKE_lib_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
+/**
+ * Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note All internal ID data itself is also swapped.
+ *
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
+ * itself.
+ */
void BKE_lib_id_swap_full(struct Main *bmain, struct ID *id_a, struct ID *id_b);
+/**
+ * Sort given \a id into given \a lb list, using case-insensitive comparison of the id names.
+ *
+ * \note All other IDs beside given one are assumed already properly sorted in the list.
+ *
+ * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
+ * immediately before or after that pointer. It must always be into given \a lb list.
+ */
void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_hint);
+/**
+ * Expand ID usages of given id as 'extern' (and no more indirect) linked data.
+ * Used by ID copy/make_local functions.
+ */
void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id, const int flags);
+/**
+ * Ensures given ID has a unique name in given listbase.
+ *
+ * Only for local IDs (linked ones already have a unique ID in their library).
+ *
+ * \param do_linked_data: if true, also ensure a unique name in case the given \a id is linked
+ * (otherwise, just ensure that it is properly sorted).
+ *
+ * \return true if a new name had to be created.
+ */
bool BKE_id_new_name_validate(struct ListBase *lb,
struct ID *id,
const char *name,
const bool do_linked_data) ATTR_NONNULL(1, 2);
+/**
+ * Pull an ID out of a library (make it local). Only call this for IDs that
+ * don't have other library users.
+ *
+ * \param flags: Same set of `LIB_ID_MAKELOCAL_` flags as passed to #BKE_lib_id_make_local.
+ */
void BKE_lib_id_clear_library_data(struct Main *bmain, struct ID *id, const int flags);
-/* Affect whole Main database. */
+/**
+ * Clear or set given tags for all ids of given type in `bmain` (runtime tags).
+ *
+ * \note Affect whole Main database.
+ */
void BKE_main_id_tag_idcode(struct Main *mainvar,
const short type,
const int tag,
const bool value);
+/**
+ * Clear or set given tags for all ids in listbase (runtime tags).
+ */
void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value);
+/**
+ * Clear or set given tags for all ids in bmain (runtime tags).
+ */
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value);
+/**
+ * Clear or set given flags for all ids in listbase (persistent flags).
+ */
void BKE_main_id_flag_listbase(struct ListBase *lb, const int flag, const bool value);
+/**
+ * Clear or set given flags for all ids in bmain (persistent flags).
+ */
void BKE_main_id_flag_all(struct Main *bmain, const int flag, const bool value);
+/**
+ * Next to indirect usage in `readfile.c/writefile.c` also in `editobject.c`, `scene.c`.
+ */
void BKE_main_id_newptr_and_tag_clear(struct Main *bmain);
void BKE_main_id_refcount_recompute(struct Main *bmain, const bool do_linked_only);
void BKE_main_lib_objects_recalc_all(struct Main *bmain);
-/* Only for repairing files via versioning, avoid for general use. */
+/**
+ * Only for repairing files via versioning, avoid for general use.
+ */
void BKE_main_id_repair_duplicate_names_listbase(struct ListBase *lb);
#define MAX_ID_FULL_NAME (64 + 64 + 3 + 1) /* 64 is MAX_ID_NAME - 2 */
#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at beginning. */
+/**
+ * Generate full name of the data-block (without ID code, but with library if any).
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME,
+ * will be filled with generated string.
+ * \param separator_char: Character to use for separating name and library name.
+ * Can be 0 to use default (' ').
+ */
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id, char separator_char);
+/**
+ * Generate full name of the data-block (without ID code, but with library if any),
+ * with a 2 to 3 character prefix prepended indicating whether it comes from a library,
+ * is overriding, has a fake or no user, etc.
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME_UI,
+ * will be filled with generated string.
+ * \param separator_char: Character to use for separating name and library name.
+ * Can be 0 to use default (' ').
+ * \param r_prefix_len: The length of the prefix added.
+ */
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
const struct ID *id,
const bool add_lib_hint,
char separator_char,
int *r_prefix_len);
+/**
+ * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any.
+ *
+ * \return A unique allocated string key for any ID in the whole Main database.
+ */
char *BKE_id_to_unique_string_key(const struct ID *id);
+/**
+ * Make linked data-blocks local.
+ *
+ * \param bmain: Almost certainly global main.
+ * \param lib: If not NULL, only make local data-blocks from this library.
+ * \param untagged_only: If true, only make local data-blocks not tagged with
+ * #LIB_TAG_PRE_EXISTING.
+ * \param set_fake: If true, set fake user on all localized data-blocks
+ * (except group and objects ones).
+ */
void BKE_library_make_local(struct Main *bmain,
const struct Library *lib,
struct GHash *old_to_new_ids,
@@ -331,11 +597,22 @@ void BKE_library_make_local(struct Main *bmain,
void BKE_id_tag_set_atomic(struct ID *id, int tag);
void BKE_id_tag_clear_atomic(struct ID *id, int tag);
+/**
+ * Check that given ID pointer actually is in G_MAIN.
+ * Main intended use is for debug asserts in places we cannot easily get rid of #G_Main.
+ */
bool BKE_id_is_in_global_main(struct ID *id);
bool BKE_id_can_be_asset(const struct ID *id);
+/**
+ * Returns ordered list of data-blocks for display in the UI.
+ * Result is list of #LinkData of IDs that must be freed.
+ */
void BKE_id_ordered_list(struct ListBase *ordered_lb, const struct ListBase *lb);
+/**
+ * Reorder ID in the list, before or after the "relative" ID.
+ */
void BKE_id_reorder(const struct ListBase *lb, struct ID *id, struct ID *relative, bool after);
void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id);
@@ -343,6 +620,12 @@ void BKE_id_blend_write(struct BlendWriter *writer, struct ID *id);
#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT))
/* lib_id_eval.c */
+
+/**
+ * Copy relatives parameters, from `id` to `id_cow`.
+ * Use handle the #ID_RECALC_PARAMETERS tag.
+ * \note Keep in sync with #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW.
+ */
void BKE_id_eval_properties_copy(struct ID *id_cow, struct ID *id);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index b94a1b33606..1c30db7a714 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -57,35 +57,117 @@ struct ReportList;
struct Scene;
struct ViewLayer;
+/**
+ * Initialize empty overriding of \a reference_id by \a local_id.
+ */
struct IDOverrideLibrary *BKE_lib_override_library_init(struct ID *local_id,
struct ID *reference_id);
+/**
+ * Shallow or deep copy of a whole override from \a src_id to \a dst_id.
+ */
void BKE_lib_override_library_copy(struct ID *dst_id,
const struct ID *src_id,
const bool do_full_copy);
+/**
+ * Clear any overriding data from given \a override.
+ */
void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, const bool do_id_user);
+/**
+ * Free given \a override.
+ */
void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user);
+/**
+ * Check if given ID has some override rules that actually indicate the user edited it.
+ */
bool BKE_lib_override_library_is_user_edited(struct ID *id);
+/**
+ * Create an overridden local copy of linked reference.
+ */
struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
struct ID *reference_id,
const bool do_tagged_remap);
+/**
+ * Create overridden local copies of all tagged data-blocks in given Main.
+ *
+ * \note Set `id->newid` of overridden libs with newly created overrides,
+ * caller is responsible to clean those pointers before/after usage as needed.
+ *
+ * \note By default, it will only remap newly created local overriding data-blocks between
+ * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
+ * main. You can add more local IDs to be remapped to use new overriding ones by setting their
+ * LIB_TAG_DOIT tag.
+ *
+ * \param reference_library: the library from which the linked data being overridden come from
+ * (i.e. the library of the linked reference ID).
+ *
+ * \param do_no_main: Create the new override data outside of Main database.
+ * Used for resyncing of linked overrides.
+ *
+ * \return \a true on success, \a false otherwise.
+ */
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
const struct Library *reference_library,
const bool do_no_main);
+/**
+ * Advanced 'smart' function to create fully functional overrides.
+ *
+ * \note Currently it only does special things if given \a id_root is an object or collection, more
+ * specific behaviors may be added in the future for other ID types.
+ *
+ * \note It will override all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at
+ * its beginning, so caller code can add extra data-blocks to be overridden as well.
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \param id_root: The root ID to create an override from.
+ * \param id_reference: Some reference ID used to do some post-processing after overrides have been
+ * created, may be NULL. Typically, the Empty object instantiating the linked collection we
+ * override, currently.
+ * \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
+ * \return true if override was successfully created.
+ */
bool BKE_lib_override_library_create(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct ID *id_root,
struct ID *id_reference,
struct ID **r_id_root_override);
+/**
+ * Create a library override template.
+ */
bool BKE_lib_override_library_template_create(struct ID *id);
+/**
+ * Convert a given proxy object into a library override.
+ *
+ * \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to
+ * actually convert the proxy itself into an override first.
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \return true if override was successfully created.
+ */
bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Object *ob_proxy);
+/**
+ * Convert all proxy objects into library overrides.
+ *
+ * \note Only affects local proxies, linked ones are not affected.
+ */
void BKE_lib_override_library_main_proxy_convert(struct Main *bmain,
struct BlendFileReadReport *reports);
+/**
+ * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
+ * data, from an existing override hierarchy.
+ *
+ * \param id_root: The root liboverride ID to resync from.
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ * \return true if override was successfully resynced.
+ */
bool BKE_lib_override_library_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -94,26 +176,76 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
const bool do_hierarchy_enforce,
const bool do_post_process,
struct BlendFileReadReport *reports);
+/**
+ * Detect and handle required resync of overrides data, when relations between reference linked IDs
+ * have changed.
+ *
+ * This is a fairly complex and costly operation, typically it should be called after
+ * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
+ *
+ * This function will first detect the remaining cases requiring a resync (namely, either when an
+ * existing linked ID that did not require to be overridden before now would be, or when new IDs
+ * are added to the hierarchy).
+ *
+ * Then it will handle the resync of necessary IDs (through calls to
+ * #BKE_lib_override_library_resync).
+ *
+ * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
+ * which case \a scene's master collection children hierarchy is used instead).
+ */
void BKE_lib_override_library_main_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct BlendFileReadReport *reports);
+/**
+ * Advanced 'smart' function to delete library overrides (including their existing override
+ * hierarchy) and remap their usages to their linked reference IDs.
+ *
+ * \note All IDs tagged with #LIB_TAG_DOIT will be deleted.
+ *
+ * \param id_root: The root liboverride ID to delete.
+ */
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);
+/**
+ * Make given ID fully local.
+ *
+ * \note Only differs from lower-level #BKE_lib_override_library_free in infamous embedded ID
+ * cases.
+ */
void BKE_lib_override_library_make_local(struct ID *id);
+/**
+ * Find override property from given RNA path, if it exists.
+ */
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find(
struct IDOverrideLibrary *override, const char *rna_path);
+/**
+ * Find override property from given RNA path, or create it if it does not exist.
+ */
struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get(
struct IDOverrideLibrary *override, const char *rna_path, bool *r_created);
+/**
+ * Remove and free given \a override_property from given ID \a override.
+ */
void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override,
struct IDOverrideLibraryProperty *override_property);
+/**
+ * Get the RNA-property matching the \a library_prop override property. Used for UI to query
+ * additional data about the overridden property (e.g. UI name).
+ *
+ * \param idpoin: Pointer to the override ID.
+ * \param library_prop: The library override property to find the matching RNA property for.
+ */
bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin,
const struct IDOverrideLibraryProperty *library_prop,
struct PointerRNA *r_override_poin,
struct PropertyRNA **r_override_prop);
+/**
+ * Find override property operation from given sub-item(s), if it exists.
+ */
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
struct IDOverrideLibraryProperty *override_property,
const char *subitem_refname,
@@ -122,6 +254,9 @@ struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_ope
const int subitem_locindex,
const bool strict,
bool *r_strict);
+/**
+ * Find override property operation from given sub-item(s), or create it if it does not exist.
+ */
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
struct IDOverrideLibraryProperty *override_property,
const short operation,
@@ -132,10 +267,16 @@ struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_ope
const bool strict,
bool *r_strict,
bool *r_created);
+/**
+ * Remove and free given \a override_property_operation from given ID \a override_property.
+ */
void BKE_lib_override_library_property_operation_delete(
struct IDOverrideLibraryProperty *override_property,
struct IDOverrideLibraryPropertyOperation *override_property_operation);
+/**
+ * Validate that required data for a given operation are available.
+ */
bool BKE_lib_override_library_property_operation_operands_validate(
struct IDOverrideLibraryPropertyOperation *override_property_operation,
struct PointerRNA *ptr_dst,
@@ -145,34 +286,107 @@ bool BKE_lib_override_library_property_operation_operands_validate(
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage);
+/**
+ * Check against potential \a bmain.
+ */
void BKE_lib_override_library_validate(struct Main *bmain,
struct ID *id,
struct ReportList *reports);
+/**
+ * Check against potential \a bmain.
+ */
void BKE_lib_override_library_main_validate(struct Main *bmain, struct ReportList *reports);
+/**
+ * Check that status of local data-block is still valid against current reference one.
+ *
+ * It means that all overridable, but not overridden, properties' local values must be equal to
+ * reference ones. Clears #LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some property has been changed in local and a new
+ * #IDOverrideProperty (of #IDOverridePropertyOperation) has to be added.
+ *
+ * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local);
+/**
+ * Check that status of reference data-block is still valid against current local one.
+ *
+ * It means that all non-overridden properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some reference has changed and local
+ * needs to be updated against it.
+ *
+ * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
+/**
+ * Compare local and reference data-blocks and create new override operations as needed,
+ * or reset to reference values if overriding is not allowed.
+ *
+ * \note Defining override operations is only mandatory before saving a `.blend` file on disk
+ * (not for undo!).
+ * Knowing that info at runtime is only useful for UI/UX feedback.
+ *
+ * \note This is by far the biggest operation (the more time-consuming) of the three so far,
+ * since it has to go over all properties in depth (all overridable ones at least).
+ * Generating differential values and applying overrides are much cheaper.
+ *
+ * \return true if any library operation was created.
+ */
bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *local);
+/**
+ * Check all overrides from given \a bmain and create/update overriding operations as needed.
+ */
bool BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto);
+/**
+ * Reset all overrides in given \a id_root, while preserving ID relations.
+ */
void BKE_lib_override_library_id_reset(struct Main *bmain, struct ID *id_root);
+/**
+ * Reset all overrides in given \a id_root and its dependencies, while preserving ID relations.
+ */
void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, struct ID *id_root);
+/**
+ * Set or clear given tag in all operations in that override property data.
+ */
void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
const short tag,
const bool do_set);
+/**
+ * Set or clear given tag in all properties and operations in that override data.
+ */
void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
const short tag,
const bool do_set);
+/**
+ * Set or clear given tag in all properties and operations in that Main's ID override data.
+ */
void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set);
+/**
+ * Remove all tagged-as-unused properties and operations from that ID override data.
+ */
void BKE_lib_override_library_id_unused_cleanup(struct ID *local);
+/**
+ * Remove all tagged-as-unused properties and operations from that Main's ID override data.
+ */
void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain);
+/**
+ * Update given override from its reference (re-applying overridden properties).
+ */
void BKE_lib_override_library_update(struct Main *bmain, struct ID *local);
+/**
+ * Update all overrides from given \a bmain.
+ */
void BKE_lib_override_library_main_update(struct Main *bmain);
+/**
+ * In case an ID is used by another liboverride ID, user may not be allowed to delete it.
+ */
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id);
/* Storage (.blend file writing) part. */
@@ -180,9 +394,22 @@ bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID
/* For now, we just use a temp main list. */
typedef struct Main OverrideLibraryStorage;
+/**
+ * Initialize an override storage.
+ */
OverrideLibraryStorage *BKE_lib_override_library_operations_store_init(void);
+/**
+ * Generate suitable 'write' data (this only affects differential override operations).
+ *
+ * Note that \a local ID is no more modified by this call,
+ * all extra data are stored in its temp \a storage_id copy.
+ */
struct ID *BKE_lib_override_library_operations_store_start(
struct Main *bmain, OverrideLibraryStorage *override_storage, struct ID *local);
+/**
+ * Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
+ * original state.
+ */
void BKE_lib_override_library_operations_store_end(OverrideLibraryStorage *override_storage,
struct ID *local);
void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage);
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index 30c742e3af6..91f72cc0762 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -143,6 +143,10 @@ enum {
typedef struct LibraryForeachIDData LibraryForeachIDData;
+/**
+ * Check whether current iteration over ID usages should be stopped or not.
+ * \return true if the iteration should be stopped, false otherwise.
+ */
bool BKE_lib_query_foreachid_iter_stop(struct LibraryForeachIDData *data);
void BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
struct ID **id_pp,
@@ -181,25 +185,77 @@ int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeach
} \
((void)0)
+/**
+ * Process embedded ID pointers (root node-trees, master collections, ...).
+ *
+ * Those require specific care, since they are technically sub-data of their owner, yet in some
+ * cases they still behave as regular IDs.
+ */
void BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp);
void BKE_lib_query_idpropertiesForeachIDLink_callback(struct IDProperty *id_prop, void *user_data);
-/* Loop over all of the ID's this datablock links to. */
+/**
+ * Loop over all of the ID's this data-block links to.
+ */
void BKE_library_foreach_ID_link(
struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
+/**
+ * Re-usable function, use when replacing ID's.
+ */
void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cb_flag);
+/**
+ * Return the number of times given \a id_user uses/references \a id_used.
+ *
+ * \note This only checks for pointer references of an ID, shallow usages
+ * (like e.g. by RNA paths, as done for FCurves) are not detected at all.
+ *
+ * \param id_user: the ID which is supposed to use (reference) \a id_used.
+ * \param id_used: the ID which is supposed to be used (referenced) by \a id_user.
+ * \return the number of direct usages/references of \a id_used by \a id_user.
+ */
int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
+/**
+ * Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used.
+ *
+ * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above,
+ * quite useful to reduce useless iterations in some cases.
+ */
bool BKE_library_id_can_use_idtype(struct ID *id_owner, const short id_type_used);
+/**
+ * Check whether given ID is used locally (i.e. by another non-linked ID).
+ */
bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
+/**
+ * Check whether given ID is used indirectly (i.e. by another linked ID).
+ */
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
+/**
+ * Combine #BKE_library_ID_is_locally_used() and #BKE_library_ID_is_indirectly_used()
+ * in a single call.
+ */
void BKE_library_ID_test_usages(struct Main *bmain,
void *idv,
bool *is_used_local,
bool *is_used_linked);
+/**
+ * Tag all unused IDs (a.k.a 'orphaned').
+ *
+ * By default only tag IDs with `0` user count.
+ * If `do_tag_recursive` is set, it will check dependencies to detect all IDs that are not actually
+ * used in current file, including 'archipelagos` (i.e. set of IDs referencing each other in
+ * loops, but without any 'external' valid usages.
+ *
+ * Valid usages here are defined as ref-counting usages, which are not towards embedded or
+ * loop-back data.
+ *
+ * \param r_num_tagged: If non-NULL, must be a zero-initialized array of #INDEX_ID_MAX integers.
+ * Number of tagged-as-unused IDs is then set for each type, and as total in
+ * #INDEX_ID_NULL item.
+ */
void BKE_lib_query_unused_ids_tag(struct Main *bmain,
const int tag,
const bool do_local_ids,
@@ -207,7 +263,24 @@ void BKE_lib_query_unused_ids_tag(struct Main *bmain,
const bool do_tag_recursive,
int *r_num_tagged);
+/**
+ * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly)
+ * in any way by any local data), including complex cases like 'linked archipelagoes', i.e.
+ * linked data-blocks that use each other in loops,
+ * which prevents their deletion by 'basic' usage checks.
+ *
+ * \param do_init_tag: if \a true, all linked data are checked, if \a false,
+ * only linked data-blocks already tagged with #LIB_TAG_DOIT are checked.
+ */
void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag);
+/**
+ * Untag linked data blocks used by other untagged linked data-blocks.
+ * Used to detect data-blocks that we can forcefully make local
+ * (instead of copying them to later get rid of original):
+ * All data-blocks we want to make local are tagged by caller,
+ * after this function has ran caller knows data-blocks still tagged can directly be made local,
+ * since they are only used by other data-blocks that will also be made fully local.
+ */
void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index 5e154459a6c..9c8caa0266b 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -97,8 +97,13 @@ enum {
ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 9,
};
-/* NOTE: Requiring new_id to be non-null, this *may* not be the case ultimately,
- * but makes things simpler for now. */
+/**
+ * Replace all references in given Main to \a old_id by \a new_id
+ * (if \a new_id is NULL, it unlinks \a old_id).
+ *
+ * \note Requiring new_id to be non-null, this *may* not be the case ultimately,
+ * but makes things simpler for now.
+ */
void BKE_libblock_remap_locked(struct Main *bmain,
void *old_idv,
void *new_idv,
@@ -106,17 +111,39 @@ void BKE_libblock_remap_locked(struct Main *bmain,
void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
ATTR_NONNULL(1, 2);
+/**
+ * Unlink given \a id from given \a bmain
+ * (does not touch to indirect, i.e. library, usages of the ID).
+ *
+ * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by
+ * #LIB_TAG_DOIT flag (quite obviously, 'non-NULL' usages can never be unlinked by this function).
+ */
void BKE_libblock_unlink(struct Main *bmain,
void *idv,
const bool do_flag_never_null,
const bool do_skip_indirect) ATTR_NONNULL();
+/**
+ * Similar to libblock_remap, but only affects IDs used by given \a idv ID.
+ *
+ * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
+ * in which case all ID usages by given \a idv will be cleared.
+ */
void BKE_libblock_relink_ex(struct Main *bmain,
void *idv,
void *old_idv,
void *new_idv,
const short remap_flags) ATTR_NONNULL(1, 2);
+/**
+ * Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
+ * in the dependency tree of IDs for all data-blocks tagged with `LIB_TAG_NEW`.
+ *
+ * \note `LIB_TAG_NEW` is cleared.
+ *
+ * Very specific usage, not sure we'll keep it on the long run,
+ * currently only used in Object/Collection duplication code.
+ */
void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, const int remap_flag)
ATTR_NONNULL();
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index 1236a96c8d9..eb17ff78688 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -80,6 +80,10 @@ int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle,
int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier);
+/**
+ * Reinsert \a modifier in modifier list with an offset of \a direction.
+ * \return if position of \a modifier has changed.
+ */
bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier,
int direction);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 9ded97e0003..41ef5e3f5ba 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -116,12 +116,14 @@ enum {
typedef struct Main {
struct Main *next, *prev;
- char name[1024]; /* 1024 = FILE_MAX */
+ /** The file-path of this blend file, an empty string indicates an unsaved file. */
+ char filepath[1024]; /* 1024 = FILE_MAX */
short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */
short minversionfile, minsubversionfile;
uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */
char build_hash[16]; /* hash from buildinfo */
- char recovered; /* indicate the main->name (file) is the recovered one */
+ /** Indicate the #Main.filepath (file) is the recovered one. */
+ char recovered;
/** All current ID's exist in the last memfile undo step. */
char is_memfile_undo_written;
/**
@@ -201,40 +203,99 @@ typedef struct Main {
struct Main *BKE_main_new(void);
void BKE_main_free(struct Main *mainvar);
+/**
+ * Check whether given `bmain` is empty or contains some IDs.
+ */
bool BKE_main_is_empty(struct Main *bmain);
void BKE_main_lock(struct Main *bmain);
void BKE_main_unlock(struct Main *bmain);
+/** Generate the mappings between used IDs and their users, and vice-versa. */
void BKE_main_relations_create(struct Main *bmain, const short flag);
void BKE_main_relations_free(struct Main *bmain);
+/** Set or clear given `tag` in all relation entries of given `bmain`. */
void BKE_main_relations_tag_set(struct Main *bmain,
const eMainIDRelationsEntryTags tag,
const bool value);
+/**
+ * Create a #GSet storing all IDs present in given \a bmain, by their pointers.
+ *
+ * \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain,
+ * instead of creating a new one.
+ */
struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset);
-/*
- * Temporary runtime API to allow re-using local (already appended) IDs instead of appending a new
- * copy again.
- */
+/* Temporary runtime API to allow re-using local (already appended)
+ * IDs instead of appending a new copy again. */
+/**
+ * Generate a mapping between 'library path' of an ID
+ * (as a pair (relative blend file path, id name)), and a current local ID, if any.
+ *
+ * This uses the information stored in `ID.library_weak_reference`.
+ */
struct GHash *BKE_main_library_weak_reference_create(struct Main *bmain) ATTR_NONNULL();
+/**
+ * Destroy the data generated by #BKE_main_library_weak_reference_create.
+ */
void BKE_main_library_weak_reference_destroy(struct GHash *library_weak_reference_mapping)
ATTR_NONNULL();
+/**
+ * Search for a local ID matching the given linked ID reference.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID
+ * type.
+ */
struct ID *BKE_main_library_weak_reference_search_item(
struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name) ATTR_NONNULL();
+/**
+ * Add the given ID weak library reference to given local ID and the runtime mapping.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param new_id: New local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_add_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
struct ID *new_id) ATTR_NONNULL();
+/**
+ * Update the status of the given ID weak library reference in current local IDs and the runtime
+ * mapping.
+ *
+ * This effectively transfers the 'ownership' of the given weak reference from `old_id` to
+ * `new_id`.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param old_id: Existing local ID matching given weak reference.
+ * \param new_id: New local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_update_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
struct ID *old_id,
struct ID *new_id) ATTR_NONNULL();
+/**
+ * Remove the given ID weak library reference from the given local ID and the runtime mapping.
+ *
+ * \param library_weak_reference_mapping: the mapping data generated by
+ * #BKE_main_library_weak_reference_create.
+ * \param library_filepath: the path of a blend file library (relative to current working one).
+ * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
+ * \param old_id: Existing local ID matching given weak reference.
+ */
void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -286,16 +347,57 @@ void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_refe
} \
((void)0)
+/**
+ * Generates a raw .blend file thumbnail data from given image.
+ *
+ * \param bmain: If not NULL, also store generated data in this Main.
+ * \param img: ImBuf image to generate thumbnail data from.
+ * \return The generated .blend file raw thumbnail data.
+ */
struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
+/**
+ * Generates an image from raw .blend file thumbnail \a data.
+ *
+ * \param bmain: Use this bmain->blen_thumb data if given \a data is NULL.
+ * \param data: Raw .blend file thumbnail data.
+ * \return An ImBuf from given data, or NULL if invalid.
+ */
struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
+/**
+ * Generates an empty (black) thumbnail for given Main.
+ */
void BKE_main_thumbnail_create(struct Main *bmain);
+/**
+ * Return file-path of given \a main.
+ */
const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL();
+/**
+ * Return file-path of global main #G_MAIN.
+ *
+ * \warning Usage is not recommended,
+ * you should always try to get a valid Main pointer from context.
+ */
const char *BKE_main_blendfile_path_from_global(void);
+/**
+ * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type.
+ */
struct ListBase *which_libbase(struct Main *bmain, short type);
//#define INDEX_ID_MAX 41
+/**
+ * Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]`
+ * array, and return the number of those for convenience.
+ *
+ * This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists
+ * in turn), without worrying about block types.
+ *
+ * \param lb: Array of lists #INDEX_ID_MAX in length.
+ *
+ * \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>`
+ * enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h`
+ */
int set_listbasepointers(struct Main *main, struct ListBase *lb[]);
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
diff --git a/source/blender/blenkernel/BKE_main_idmap.h b/source/blender/blenkernel/BKE_main_idmap.h
index ff69883f0fb..13ddcaa93ba 100644
--- a/source/blender/blenkernel/BKE_main_idmap.h
+++ b/source/blender/blenkernel/BKE_main_idmap.h
@@ -44,6 +44,17 @@ enum {
MAIN_IDMAP_TYPE_UUID = 1 << 1,
};
+/**
+ * Generate mapping from ID type/name to ID pointer for given \a bmain.
+ *
+ * \note When used during undo/redo, there is no guaranty that ID pointers from UI area are not
+ * pointing to freed memory (when some IDs have been deleted). To avoid crashes in those cases, one
+ * can provide the 'old' (aka current) Main database as reference. #BKE_main_idmap_lookup_id will
+ * then check that given ID does exist in \a old_bmain before trying to use it.
+ *
+ * \param create_valid_ids_set: If \a true, generate a reference to prevent freed memory accesses.
+ * \param old_bmain: If not NULL, its IDs will be added the valid references set.
+ */
struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
const bool create_valid_ids_set,
struct Main *old_bmain,
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 8e2f6e6f10c..2a2b080217c 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -56,16 +56,20 @@ typedef enum {
MASK_HANDLE_MODE_INDIVIDUAL_HANDLES = 2,
} eMaskhandleMode;
-struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline);
-struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(
- struct MaskSpline *spline, const struct MaskSplinePoint *point_ref);
+/* -------------------------------------------------------------------- */
+/** \name Mask Layers
+ * \{ */
-/* mask layers */
struct MaskLayer *BKE_mask_layer_new(struct Mask *mask, const char *name);
+/**
+ * \note The returned mask-layer may be hidden, caller needs to check.
+ */
struct MaskLayer *BKE_mask_layer_active(struct Mask *mask);
void BKE_mask_layer_active_set(struct Mask *mask, struct MaskLayer *masklay);
void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay);
+/** \brief Free all animation keys for a mask layer.
+ */
void BKE_mask_layer_free_shapes(struct MaskLayer *masklay);
void BKE_mask_layer_free(struct MaskLayer *masklay);
void BKE_mask_layer_free_list(struct ListBase *masklayers);
@@ -83,7 +87,16 @@ void BKE_mask_layer_rename(struct Mask *mask,
struct MaskLayer *BKE_mask_layer_copy(const struct MaskLayer *masklay);
void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, const struct ListBase *masklayers);
-/* splines */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Splines
+ * \{ */
+
+struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline);
+struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(
+ struct MaskSpline *spline, const struct MaskSplinePoint *point_ref);
+
struct MaskSpline *BKE_mask_spline_add(struct MaskLayer *masklay);
bool BKE_mask_spline_remove(struct MaskLayer *mask_layer, struct MaskSpline *spline);
void BKE_mask_point_direction_switch(struct MaskSplinePoint *point);
@@ -104,7 +117,12 @@ float BKE_mask_spline_project_co(struct MaskSpline *spline,
const float co[2],
const eMaskSign sign);
-/* point */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Point
+ * \{ */
+
eMaskhandleMode BKE_mask_point_handles_mode_get(const struct MaskSplinePoint *point);
void BKE_mask_point_handle(const struct MaskSplinePoint *point,
eMaskWhichHandle which_handle,
@@ -139,7 +157,12 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point,
const eMaskWhichHandle which_handle,
const bool do_select);
-/* general */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name General
+ * \{ */
+
struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]);
@@ -151,6 +174,9 @@ void BKE_mask_coord_from_image(struct Image *image,
struct ImageUser *iuser,
float r_co[2],
const float co[2]);
+/**
+ * Inverse of #BKE_mask_coord_from_image.
+ */
void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2]);
void BKE_mask_coord_to_movieclip(struct MovieClip *clip,
struct MovieClipUser *user,
@@ -161,7 +187,11 @@ void BKE_mask_coord_to_image(struct Image *image,
float r_co[2],
const float co[2]);
-/* parenting */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Parenting
+ * \{ */
void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe);
void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe);
@@ -169,10 +199,19 @@ void BKE_mask_parent_init(struct MaskParent *parent);
void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline,
struct MaskSplinePoint *point,
const float u);
+/**
+ * Calculates the tangent of a point by its previous and next
+ * (ignoring handles - as if its a poly line).
+ */
void BKE_mask_calc_tangent_polyline(struct MaskSpline *spline,
struct MaskSplinePoint *point,
float t[2]);
void BKE_mask_calc_handle_point(struct MaskSpline *spline, struct MaskSplinePoint *point);
+/**
+ * \brief Resets auto handles even for non-auto bezier points
+ *
+ * Useful for giving sane defaults.
+ */
void BKE_mask_calc_handle_point_auto(struct MaskSpline *spline,
struct MaskSplinePoint *point,
const bool do_recalc_length);
@@ -186,20 +225,40 @@ void BKE_mask_point_parent_matrix_get(struct MaskSplinePoint *point,
float ctime,
float parent_matrix[3][3]);
-/* animation */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation
+ * \{ */
+
int BKE_mask_layer_shape_totvert(struct MaskLayer *masklay);
+/**
+ * Inverse of #BKE_mask_layer_shape_to_mask
+ */
void BKE_mask_layer_shape_from_mask(struct MaskLayer *masklay,
struct MaskLayerShape *masklay_shape);
+/**
+ * Inverse of #BKE_mask_layer_shape_from_mask
+ */
void BKE_mask_layer_shape_to_mask(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape);
+/**
+ * \note Linear interpolation only.
+ */
void BKE_mask_layer_shape_to_mask_interp(struct MaskLayer *masklay,
struct MaskLayerShape *masklay_shape_a,
struct MaskLayerShape *masklay_shape_b,
const float fac);
struct MaskLayerShape *BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, const int frame);
+/**
+ * When returning 2 - the frame isn't found but before/after frames are.
+ */
int BKE_mask_layer_shape_find_frame_range(struct MaskLayer *masklay,
const float frame,
struct MaskLayerShape **r_masklay_shape_a,
struct MaskLayerShape **r_masklay_shape_b);
+/**
+ * \note Does *not* add to the list.
+ */
struct MaskLayerShape *BKE_mask_layer_shape_alloc(struct MaskLayer *masklay, const int frame);
void BKE_mask_layer_shape_free(struct MaskLayerShape *masklay_shape);
struct MaskLayerShape *BKE_mask_layer_shape_verify_frame(struct MaskLayer *masklay,
@@ -214,19 +273,42 @@ bool BKE_mask_layer_shape_spline_from_index(struct MaskLayer *masklay,
int *r_index);
int BKE_mask_layer_shape_spline_to_index(struct MaskLayer *masklay, struct MaskSpline *spline);
+/**
+ * When a new points added, resizing all shape-key arrays.
+ */
void BKE_mask_layer_shape_changed_add(struct MaskLayer *masklay,
int index,
bool do_init,
bool do_init_interpolate);
+/**
+ * Move array elements to account for removed point.
+ */
void BKE_mask_layer_shape_changed_remove(struct MaskLayer *masklay, int index, int count);
int BKE_mask_get_duration(struct Mask *mask);
-/* clipboard */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clipboard
+ * \{ */
+
+/**
+ * Free the clipboard.
+ */
void BKE_mask_clipboard_free(void);
+/**
+ * Copy selected visible splines from the given layer to clipboard.
+ */
void BKE_mask_clipboard_copy_from_layer(struct MaskLayer *mask_layer);
+/**
+ * Check clipboard is empty.
+ */
bool BKE_mask_clipboard_is_empty(void);
+/**
+ * Paste the contents of clipboard to given mask layer.
+ */
void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mask_layer);
#define MASKPOINT_ISSEL_ANY(p) ((((p)->bezt.f1 | (p)->bezt.f2 | (p)->bezt.f3) & SELECT) != 0)
@@ -260,9 +342,16 @@ void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mas
} \
(void)0
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
+
#define MASK_RESOL_MAX 128
/* mask_evaluate.c */
+
unsigned int BKE_mask_spline_resolution(struct MaskSpline *spline, int width, int height);
unsigned int BKE_mask_spline_feather_resolution(struct MaskSpline *spline, int width, int height);
int BKE_mask_spline_differentiate_calc_total(const struct MaskSpline *spline,
@@ -276,6 +365,10 @@ void BKE_mask_spline_feather_collapse_inner_loops(struct MaskSpline *spline,
const unsigned int tot_feather_point);
float (*BKE_mask_spline_differentiate(
struct MaskSpline *spline, int width, int height, unsigned int *r_tot_diff_point))[2];
+/**
+ * values align with #BKE_mask_spline_differentiate_with_resolution
+ * when \a resol arguments match.
+ */
float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
struct MaskSpline *spline,
const unsigned int resol,
@@ -283,6 +376,7 @@ float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
unsigned int *r_tot_feather_point))[2];
/* *** mask point functions which involve evaluation *** */
+
float (*BKE_mask_spline_feather_points(struct MaskSpline *spline, int *tot_feather_point))[2];
float *BKE_mask_point_segment_diff(struct MaskSpline *spline,
@@ -291,6 +385,8 @@ float *BKE_mask_point_segment_diff(struct MaskSpline *spline,
int height,
unsigned int *r_tot_diff_point);
+/* *** mask point functions which involve evaluation *** */
+
float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline,
struct MaskSplinePoint *point,
int width,
@@ -303,7 +399,14 @@ void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime
void BKE_mask_eval_animation(struct Depsgraph *depsgraph, struct Mask *mask);
void BKE_mask_eval_update(struct Depsgraph *depsgraph, struct Mask *mask);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Rasterization
+ * \{ */
+
/* mask_rasterize.c */
+
struct MaskRasterHandle;
typedef struct MaskRasterHandle MaskRasterHandle;
@@ -318,11 +421,16 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
const bool do_feather);
float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float xy[2]);
+/**
+ * \brief Rasterize a buffer from a single mask (threaded execution).
+ */
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
const unsigned int width,
const unsigned int height,
float *buffer);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index b1eaf7207fa..5f9007c79b0 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -34,12 +34,18 @@ struct Object;
struct Scene;
struct bNode;
-/* Module */
+/* -------------------------------------------------------------------- */
+/** \name Module
+ * \{ */
void BKE_materials_init(void);
void BKE_materials_exit(void);
-/* Materials */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Materials
+ * \{ */
void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID *id);
void BKE_objects_materials_test_all(struct Main *bmain, struct ID *id);
@@ -48,9 +54,18 @@ void BKE_object_material_resize(struct Main *bmain,
const short totcol,
bool do_id_user);
void BKE_object_material_remap(struct Object *ob, const unsigned int *remap);
+/**
+ * Calculate a material remapping from \a ob_src to \a ob_dst.
+ *
+ * \param remap_src_to_dst: An array the size of `ob_src->totcol`
+ * where index values are filled in which map to \a ob_dst materials.
+ */
void BKE_object_material_remap_calc(struct Object *ob_dst,
struct Object *ob_src,
short *remap_src_to_dst);
+/**
+ * Copy materials from evaluated geometry to the original geometry of an object.
+ */
void BKE_object_material_from_eval_data(struct Main *bmain,
struct Object *ob_orig,
struct ID *data_eval);
@@ -61,10 +76,17 @@ void BKE_gpencil_material_attr_init(struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
-/* material slots */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Material Slots
+ * \{ */
struct Material ***BKE_object_material_array_p(struct Object *ob);
short *BKE_object_material_len_p(struct Object *ob);
+/**
+ * \note Same as #BKE_object_material_len_p but for ID's.
+ */
struct Material ***BKE_id_material_array_p(struct ID *id); /* same but for ID's */
short *BKE_id_material_len_p(struct ID *id);
@@ -81,6 +103,9 @@ struct Material *BKE_object_material_get(struct Object *ob, short act);
void BKE_id_material_assign(struct Main *bmain, struct ID *id, struct Material *ma, short act);
void BKE_object_material_assign(
struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type);
+/**
+ * \warning this calls many more update calls per object then are needed, could be optimized.
+ */
void BKE_object_material_array_assign(struct Main *bmain,
struct Object *ob,
struct Material ***matar,
@@ -99,7 +124,12 @@ void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
struct bNode *BKE_texpaint_slot_material_find_node(struct Material *ma, short texpaint_slot);
-/* rna api */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA API
+ * \{ */
+
void BKE_id_materials_copy(struct Main *bmain, struct ID *id_src, struct ID *id_dst);
void BKE_id_material_resize(struct Main *bmain, struct ID *id, short totcol, bool do_id_user);
void BKE_id_material_append(struct Main *bmain, struct ID *id, struct Material *ma);
@@ -109,23 +139,57 @@ struct Material *BKE_id_material_pop(struct Main *bmain,
int index);
void BKE_id_material_clear(struct Main *bmain, struct ID *id);
-/* eval api */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation API
+ * \{ */
+
+/**
+ * On evaluated objects the number of materials on an object and its data might go out of sync.
+ * This is because during evaluation materials can be added/removed on the object data.
+ *
+ * For rendering or exporting we generally use the materials on the object data. However, some
+ * material indices might be overwritten by the object.
+ */
struct Material *BKE_object_material_get_eval(struct Object *ob, short act);
int BKE_object_material_count_eval(struct Object *ob);
void BKE_id_material_eval_assign(struct ID *id, int slot, struct Material *material);
+/**
+ * Add an empty material slot if the id has no material slots. This material slot allows the
+ * material to be overwritten by object-linked materials.
+ */
void BKE_id_material_eval_ensure_default_slot(struct ID *id);
-/* rendering */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Rendering
+ * \{ */
+
+/**
+ * \param r_col: current value.
+ * \param col: new value.
+ * \param fac: Zero for is no change.
+ */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3]);
-/* copy/paste */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy/Paste
+ * \{ */
+
void BKE_material_copybuf_clear(void);
void BKE_material_copybuf_free(void);
void BKE_material_copybuf_copy(struct Main *bmain, struct Material *ma);
void BKE_material_copybuf_paste(struct Main *bmain, struct Material *ma);
-/* Default Materials */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Default Materials
+ * \{ */
struct Material *BKE_material_default_empty(void);
struct Material *BKE_material_default_holdout(void);
@@ -135,12 +199,18 @@ struct Material *BKE_material_default_gpencil(void);
void BKE_material_defaults_free_gpu(void);
-/* Dependency graph evaluation. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dependency graph evaluation
+ * \{ */
struct Depsgraph;
void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index db4dca14535..895fe5a28f9 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -41,13 +41,45 @@ bool BKE_mball_is_any_selected(const struct MetaBall *mb);
bool BKE_mball_is_any_selected_multi(struct Base **bases, int bases_len);
bool BKE_mball_is_any_unselected(const struct MetaBall *mb);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
+/**
+ * Test, if \a ob is a basis meta-ball.
+ *
+ * It test last character of Object ID name.
+ * If last character is digit it return 0, else it return 1.
+ */
bool BKE_mball_is_basis(struct Object *ob);
+/**
+ * This function finds the basis meta-ball.
+ *
+ * Basis meta-ball doesn't include any number at the end of
+ * its name. All meta-balls with same base of name can be
+ * blended. meta-balls with different basic name can't be blended.
+ *
+ * \warning #BKE_mball_is_basis() can fail on returned object, see function docs for details.
+ */
struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
+/**
+ * Compute bounding box of all meta-elements / meta-ball.
+ *
+ * Bounding box is computed from polygonized surface. \a ob is
+ * basic meta-balls (with name `Meta` for example). All other meta-ball objects
+ * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box.
+ */
void BKE_mball_texspace_calc(struct Object *ob);
+/**
+ * Return or compute bounding-box for given meta-ball object.
+ */
struct BoundBox *BKE_mball_boundbox_get(struct Object *ob);
float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase);
+/**
+ * Copy some properties from object to other meta-ball object with same base name.
+ *
+ * When some properties (wire-size, threshold, update flags) of meta-ball are changed, then this
+ * properties are copied to all meta-balls in same "group" (meta-balls with same base name:
+ * `MBall`, `MBall.001`, `MBall.002`, etc). The most important is to copy properties to the base
+ * meta-ball, because this meta-ball influence polygonization of meta-balls. */
void BKE_mball_properties_copy(struct Scene *scene, struct Object *active_object);
bool BKE_mball_minmax_ex(const struct MetaBall *mb,
@@ -55,14 +87,24 @@ bool BKE_mball_minmax_ex(const struct MetaBall *mb,
float max[3],
const float obmat[4][4],
const short flag);
+
+/* Basic vertex data functions. */
+
bool BKE_mball_minmax(const struct MetaBall *mb, float min[3], float max[3]);
bool BKE_mball_center_median(const struct MetaBall *mb, float r_cent[3]);
bool BKE_mball_center_bounds(const struct MetaBall *mb, float r_cent[3]);
void BKE_mball_transform(struct MetaBall *mb, const float mat[4][4], const bool do_props);
void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
+/**
+ * Most simple meta-element adding function.
+ *
+ * \note don't do context manipulation here (rna uses).
+ */
struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type);
+/* *** select funcs *** */
+
int BKE_mball_select_count(const struct MetaBall *mb);
int BKE_mball_select_count_multi(struct Base **bases, int bases_len);
bool BKE_mball_select_all(struct MetaBall *mb);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index be9b84ccd62..c39583d234a 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -84,21 +84,51 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
const struct CustomData_MeshMasks *cd_mask_extra,
const struct Mesh *me_settings);
+/**
+ * Find the index of the loop in 'poly' which references vertex,
+ * returns -1 if not found
+ */
int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, uint vert);
+/**
+ * Fill \a r_adj with the loop indices in \a poly adjacent to the
+ * vertex. Returns the index of the loop matching vertex, or -1 if the
+ * vertex is not in \a poly
+ */
int poly_get_adj_loops_from_vert(const struct MPoly *poly,
const struct MLoop *mloop,
unsigned int vert,
unsigned int r_adj[2]);
+/**
+ * Return the index of the edge vert that is not equal to \a v. If
+ * neither edge vertex is equal to \a v, returns -1.
+ */
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
+/**
+ * Sets each output array element to the edge index if it is a real edge, or -1.
+ */
void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh,
const struct MLoopTri *looptri,
int r_edges[3]);
+/**
+ * Free (or release) any data used by this mesh (does not free the mesh itself).
+ * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used.
+ */
void BKE_mesh_free_data_for_undo(struct Mesh *me);
void BKE_mesh_clear_geometry(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
+/**
+ * A version of #BKE_mesh_copy_parameters that is intended for evaluated output
+ * (the modifier stack for example).
+ *
+ * \warning User counts are not handled for ID's.
+ */
void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *me_src);
+/**
+ * Copy user editable settings that we want to preserve
+ * when a new mesh is based on an existing mesh.
+ */
void BKE_mesh_copy_parameters(struct Mesh *me_dst, const struct Mesh *me_src);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
@@ -121,12 +151,16 @@ struct Mesh *BKE_mesh_new_nomain_from_template_ex(const struct Mesh *me_src,
void BKE_mesh_eval_delete(struct Mesh *mesh_eval);
-/* Performs copy for use during evaluation,
- * optional referencing original arrays to reduce memory. */
+/**
+ * Performs copy for use during evaluation,
+ * optional referencing original arrays to reduce memory.
+ */
struct Mesh *BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference);
-/* These functions construct a new Mesh,
- * contrary to BKE_mesh_to_curve_nurblist which modifies ob itself. */
+/**
+ * These functions construct a new Mesh,
+ * contrary to #BKE_mesh_to_curve_nurblist which modifies ob itself.
+ */
struct Mesh *BKE_mesh_new_nomain_from_curve(const struct Object *ob);
struct Mesh *BKE_mesh_new_nomain_from_curve_displist(const struct Object *ob,
const struct ListBase *dispbase);
@@ -136,6 +170,16 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
+
+/**
+ * Add a #CD_ORCO layer to the Mesh if there is none already.
+ */
+void BKE_mesh_orco_ensure(struct Object *ob, struct Mesh *mesh);
+
+/**
+ * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
+ * this is necessary to make the if #MFace.v4 check for quads work.
+ */
int BKE_mesh_mface_index_validate(struct MFace *mface,
struct CustomData *mfdata,
int mfindex,
@@ -166,9 +210,17 @@ void BKE_mesh_material_index_clear(struct Mesh *me);
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
void BKE_mesh_smooth_flag_set(struct Mesh *me, const bool use_smooth);
-/* Needed after converting a mesh with subsurf optimal display to mesh. */
+/**
+ * Needed after converting a mesh with subsurf optimal display to mesh.
+ */
void BKE_mesh_edges_set_draw_render(struct Mesh *me);
+/**
+ * Used for unit testing; compares two meshes, checking only
+ * differences we care about. should be usable with leaf's
+ * testing framework I get RNA work done, will use hackish
+ * testing code for now.
+ */
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob);
@@ -177,34 +229,49 @@ void BKE_mesh_texspace_calc(struct Mesh *me);
void BKE_mesh_texspace_ensure(struct Mesh *me);
void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_size[3]);
void BKE_mesh_texspace_get_reference(struct Mesh *me,
- short **r_texflag,
+ char **r_texflag,
float **r_loc,
float **r_size);
void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
+/**
+ * Split faces based on the edge angle and loop normals.
+ * Matches behavior of face splitting in render engines.
+ *
+ * \note Will leave #CD_NORMAL loop data layer which is used by render engines to set shading up.
+ */
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
-/* Create new mesh from the given object at its current state.
+/**
+ * Create new mesh from the given object at its current state.
* The owner of this mesh is unknown, it is up to the caller to decide.
*
* If preserve_all_data_layers is truth then the modifier stack is re-evaluated to ensure it
* preserves all possible custom data layers.
*
- * NOTE: Dependency graph argument is required when preserve_all_data_layers is truth, and is
- * ignored otherwise. */
+ * \note Dependency graph argument is required when preserve_all_data_layers is truth, and is
+ * ignored otherwise.
+ */
struct Mesh *BKE_mesh_new_from_object(struct Depsgraph *depsgraph,
struct Object *object,
const bool preserve_all_data_layers,
const bool preserve_origindex);
-/* This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database.
+/**
+ * This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database.
* However, that function enforces object type to be a geometry one, and ensures a mesh is always
- * generated, be it empty. */
+ * generated, be it empty.
+ */
struct Mesh *BKE_mesh_new_from_object_to_bmain(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Object *object,
bool preserve_all_data_layers);
+/**
+ * \param use_virtual_modifiers: When enabled calculate virtual-modifiers before applying `md_eval`
+ * support this since virtual-modifiers are not modifiers from a user perspective,
+ * allowing shape keys to be included with the modifier being applied, see: T91923.
+ */
struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_eval,
@@ -212,7 +279,9 @@ struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
const bool use_virtual_modifiers,
const bool build_shapekey_layers);
-/* Copies a nomain-Mesh into an existing Mesh. */
+/**
+ * Copies a nomain-Mesh into an existing Mesh.
+ */
void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src,
struct Mesh *mesh_dst,
struct Object *ob,
@@ -222,6 +291,7 @@ void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, st
/* vertex level transformations & checks (no derived mesh) */
+/* basic vertex data functions */
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]);
void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys);
void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys);
@@ -233,7 +303,13 @@ void BKE_mesh_do_versions_cd_flag_init(struct Mesh *mesh);
void BKE_mesh_mselect_clear(struct Mesh *me);
void BKE_mesh_mselect_validate(struct Mesh *me);
+/**
+ * \return the index within `me->mselect`, or -1
+ */
int BKE_mesh_mselect_find(struct Mesh *me, int index, int type);
+/**
+ * \return The index of the active element.
+ */
int BKE_mesh_mselect_active_get(struct Mesh *me, int type);
void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type);
@@ -250,6 +326,17 @@ void BKE_mesh_vert_normals_apply(struct Mesh *mesh, const short (*vert_normals)[
/* *** mesh_tessellate.c *** */
+/**
+ * Recreate #MFace Tessellation.
+ *
+ * \param do_face_nor_copy: Controls whether the normals from the poly
+ * are copied to the tessellated faces.
+ *
+ * \return number of tessellation faces.
+ *
+ * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since
+ * it's not used in many places and #MFace should be phased out.
+ */
int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
struct CustomData *ldata,
struct CustomData *pdata,
@@ -260,12 +347,23 @@ int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
const bool do_face_nor_copy);
void BKE_mesh_tessface_calc(struct Mesh *mesh);
+/**
+ * Calculate tessellation into #MLoopTri which exist only for this purpose.
+ */
void BKE_mesh_recalc_looptri(const struct MLoop *mloop,
const struct MPoly *mpoly,
const struct MVert *mvert,
int totloop,
int totpoly,
struct MLoopTri *mlooptri);
+/**
+ * A version of #BKE_mesh_recalc_looptri which takes pre-calculated polygon normals
+ * (used to avoid having to calculate the face normal for NGON tessellation).
+ *
+ * \note Only use this function if normals have already been calculated, there is no need
+ * to calculate normals just to use this function as it will cause the normals for triangles
+ * to be calculated which aren't needed for tessellation.
+ */
void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
const struct MPoly *mpoly,
const struct MVert *mvert,
@@ -292,8 +390,15 @@ void BKE_mesh_calc_normals_poly_and_vertex(struct MVert *mvert,
int mpoly_len,
float (*r_poly_normals)[3],
float (*r_vert_normals)[3]);
+/**
+ * \note this does not update the #CD_NORMAL layer,
+ * but does update the normals in the #CD_MVERT layer.
+ */
void BKE_mesh_calc_normals(struct Mesh *me);
void BKE_mesh_ensure_normals(struct Mesh *me);
+/**
+ * Called after calculating all modifiers.
+ */
void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
void BKE_mesh_calc_normals_looptri(struct MVert *mverts,
int numVerts,
@@ -311,6 +416,12 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const struct MLoop *mloops,
int *r_mlfan_vert_index,
int *r_mpfan_curr_index);
+/**
+ * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
+ *
+ * Used when defining an empty custom loop normals data layer,
+ * to keep same shading as with auto-smooth!
+ */
void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
const int numVerts,
struct MEdge *medges,
@@ -379,17 +490,42 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr);
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr);
+/**
+ * Utility for multi-threaded calculation that ensures
+ * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr`
+ * that would cause it not to be thread safe.
+ *
+ * \note This works as long as threads never operate on the same loops at once.
+ */
void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls);
+/**
+ * Utility for multi-threaded calculation
+ * that merges `lnors_spacearr_tls` into `lnors_spacearr`.
+ */
void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls);
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr);
+/**
+ * Should only be called once.
+ * Beware, this modifies ref_vec and other_vec in place!
+ * In case no valid space can be generated, ref_alpha and ref_beta are set to zero
+ * (which means 'use auto lnors').
+ */
void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
float vec_ref[3],
float vec_other[3],
struct BLI_Stack *edge_vectors);
+/**
+ * Add a new given loop to given lnor_space.
+ * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct
+ * (in case of BMLOOP_PTR), or nullptr (in case of LOOP_INDEX), loop index is then stored in
+ * pointer. If \a is_single is set, the BMLoop or loop index is directly stored in \a
+ * lnor_space->loops pointer (since there is only one loop in this fan), else it is added to the
+ * linked list of loops in the fan.
+ */
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpace *lnor_space,
const int ml_index,
@@ -403,6 +539,12 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space,
short r_clnor_data[2]);
/* Medium-level custom normals functions. */
+
+/**
+ * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
+ * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
+ * (splitting edges).
+ */
void BKE_mesh_normals_loop_split(const struct MVert *mverts,
const int numVerts,
struct MEdge *medges,
@@ -442,20 +584,49 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(const struct MVert *mverts,
const int numPolys,
short (*r_clnors_data)[2]);
+/**
+ * Computes average per-vertex normals from given custom loop normals.
+ *
+ * \param clnors: The computed custom loop normals.
+ * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
+ */
void BKE_mesh_normals_loop_to_vertex(const int numVerts,
const struct MLoop *mloops,
const int numLoops,
const float (*clnors)[3],
float (*r_vert_clnors)[3]);
-/* High-level custom normals functions. */
+/**
+ * High-level custom normals functions.
+ */
bool BKE_mesh_has_custom_loop_normals(struct Mesh *me);
void BKE_mesh_calc_normals_split(struct Mesh *mesh);
+/**
+ * Compute 'split' (aka loop, or per face corner's) normals.
+ *
+ * \param r_lnors_spacearr: Allows to get computed loop normal space array.
+ * That data, among other things, contains 'smooth fan' info, useful e.g.
+ * to split geometry along sharp edges.
+ */
void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh,
struct MLoopNorSpaceArray *r_lnors_spacearr);
+/**
+ * Higher level functions hiding most of the code needed around call to
+ * #BKE_mesh_normals_loop_custom_set().
+ *
+ * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there
+ * with automatically computed vectors.
+ */
void BKE_mesh_set_custom_normals(struct Mesh *mesh, float (*r_custom_loopnors)[3]);
+/**
+ * Higher level functions hiding most of the code needed around call to
+ * #BKE_mesh_normals_loop_custom_from_vertices_set().
+ *
+ * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there
+ * with automatically computed vectors.
+ */
void BKE_mesh_set_custom_normals_from_vertices(struct Mesh *mesh, float (*r_custom_vertnors)[3]);
/* *** mesh_evaluate.cc *** */
@@ -472,6 +643,7 @@ void BKE_mesh_calc_poly_center(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray,
float r_cent[3]);
+/* NOTE: passing poly-normal is only a speedup so we can skip calculating it. */
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly,
const struct MLoop *loopstart,
const struct MVert *mvarray);
@@ -490,11 +662,25 @@ void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap,
const struct MLoop *mloop);
bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]);
+/**
+ * Calculate the center from polygons,
+ * use when we want to ignore vertex locations that don't have connected faces.
+ */
bool BKE_mesh_center_median_from_polys(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]);
+/**
+ * \note Mesh must be manifold with consistent face-winding,
+ * see #mesh_calc_poly_volume_centroid for details.
+ */
bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]);
+/**
+ * Calculate the volume and center.
+ *
+ * \param r_volume: Volume (unsigned).
+ * \param r_center: Center of mass.
+ */
void BKE_mesh_calc_volume(const struct MVert *mverts,
const int mverts_num,
const struct MLoopTri *mlooptri,
@@ -505,6 +691,19 @@ void BKE_mesh_calc_volume(const struct MVert *mverts,
/* tessface */
void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh);
+/**
+ * The same as #BKE_mesh_convert_mfaces_to_mpolys
+ * but oriented to be used in #do_versions from `readfile.c`
+ * the difference is how active/render/clone/stencil indices are handled here.
+ *
+ * normally they're being set from `pdata` which totally makes sense for meshes which are already
+ * converted to #BMesh structures, but when loading older files indices shall be updated in other
+ * way around, so newly added `pdata` and `ldata` would have this indices set
+ * based on `fdata` layer.
+ *
+ * this is normally only needed when reading older files,
+ * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used.
+ */
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh);
void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id,
struct CustomData *fdata,
@@ -521,8 +720,20 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id,
struct MLoop **r_mloop,
struct MPoly **r_mpoly);
+/**
+ * Flip a single MLoop's #MDisps structure,
+ * low level function to be called from face-flipping code which re-arranged the mdisps themselves.
+ */
void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip);
+/**
+ * Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
+ * (keeping the same vertex as 'start point').
+ *
+ * \param mpoly: the polygon to flip.
+ * \param mloop: the full loops array.
+ * \param ldata: the loops custom data.
+ */
void BKE_mesh_polygon_flip_ex(struct MPoly *mpoly,
struct MLoop *mloop,
struct CustomData *ldata,
@@ -530,6 +741,11 @@ void BKE_mesh_polygon_flip_ex(struct MPoly *mpoly,
struct MDisps *mdisp,
const bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
+/**
+ * Flip (invert winding of) all polygons (used to inverse their normals).
+ *
+ * \note Invalidates tessellation, caller must handle that.
+ */
void BKE_mesh_polygons_flip(struct MPoly *mpoly,
struct MLoop *mloop,
struct CustomData *ldata,
@@ -542,12 +758,48 @@ enum {
MESH_MERGE_VERTS_DUMP_IF_MAPPED,
MESH_MERGE_VERTS_DUMP_IF_EQUAL,
};
+/**
+ * Merge Verts
+ *
+ * This frees the given mesh and returns a new mesh.
+ *
+ * \param vtargetmap: The table that maps vertices to target vertices. a value of -1
+ * indicates a vertex is a target, and is to be kept.
+ * This array is aligned with 'mesh->totvert'
+ * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.),
+ * this is not supported and will likely generate corrupted geometry.
+ *
+ * \param tot_vtargetmap: The number of non '-1' values in vtargetmap. (not the size)
+ *
+ * \param merge_mode: enum with two modes.
+ * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
+ * When called by the Mirror Modifier,
+ * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
+ * of faces sharing the same set of vertices)
+ * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
+ * When called by the Array Modifier,
+ * In this mode, faces where all vertices are merged are double-checked,
+ * to see whether all target vertices actually make up a poly already.
+ * Indeed it could be that all of a poly's vertices are merged,
+ * but merged to vertices that do not make up a single poly,
+ * in which case the original poly should not be dumped.
+ * Actually this later behavior could apply to the Mirror Modifier as well,
+ * but the additional checks are costly and not necessary in the case of mirror,
+ * because each vertex is only merged to its own mirror.
+ *
+ * \note #BKE_mesh_tessface_calc_ex has to run on the returned DM
+ * if you want to access tess-faces.
+ */
struct Mesh *BKE_mesh_merge_verts(struct Mesh *mesh,
const int *vtargetmap,
const int tot_vtargetmap,
const int merge_mode);
-/* flush flags */
+/* Flush flags. */
+
+/**
+ * Update the hide flag for edges and faces from the corresponding flag in verts.
+ */
void BKE_mesh_flush_hidden_from_verts_ex(const struct MVert *mvert,
const struct MLoop *mloop,
struct MEdge *medge,
@@ -562,6 +814,9 @@ void BKE_mesh_flush_hidden_from_polys_ex(struct MVert *mvert,
const struct MPoly *mpoly,
const int totpoly);
void BKE_mesh_flush_hidden_from_polys(struct Mesh *me);
+/**
+ * simple poly -> vert/edge selection.
+ */
void BKE_mesh_flush_select_from_polys_ex(struct MVert *mvert,
const int totvert,
const struct MLoop *mloop,
@@ -580,6 +835,17 @@ void BKE_mesh_flush_select_from_verts_ex(const struct MVert *mvert,
void BKE_mesh_flush_select_from_verts(struct Mesh *me);
/* spatial evaluation */
+/**
+ * This function takes the difference between 2 vertex-coord-arrays
+ * (\a vert_cos_src, \a vert_cos_dst),
+ * and applies the difference to \a vert_cos_new relative to \a vert_cos_org.
+ *
+ * \param vert_cos_src: reference deform source.
+ * \param vert_cos_dst: reference deform destination.
+ *
+ * \param vert_cos_org: reference for the output location.
+ * \param vert_cos_new: resulting coords.
+ */
void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
const int totpoly,
const struct MLoop *mloop,
@@ -593,10 +859,41 @@ void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
/* *** mesh_validate.c *** */
+/**
+ * Validates and corrects a Mesh.
+ *
+ * \returns true if a change is made.
+ */
bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask);
+/**
+ * Checks if a Mesh is valid without any modification. This is always verbose.
+ *
+ * \see #DM_is_valid to call on derived meshes
+ *
+ * \returns is_valid.
+ */
bool BKE_mesh_is_valid(struct Mesh *me);
+/**
+ * Check all material indices of polygons are valid, invalid ones are set to 0.
+ * \returns is_valid.
+ */
bool BKE_mesh_validate_material_indices(struct Mesh *me);
+/**
+ * Validate the mesh, \a do_fixes requires \a mesh to be non-null.
+ *
+ * \return false if no changes needed to be made.
+ *
+ * Vertex Normals
+ * ==============
+ *
+ * While zeroed normals are checked, these checks aren't comprehensive.
+ * Technically, to detect errors here a normal recalculation and comparison is necessary.
+ * However this function is mainly to prevent severe errors in geometry
+ * (invalid data that will crash Blender, or cause some features to behave incorrectly),
+ * not to detect subtle differences in the resulting normals which could be caused
+ * by importers that load normals (for example).
+ */
bool BKE_mesh_validate_arrays(struct Mesh *me,
struct MVert *mverts,
unsigned int totvert,
@@ -613,6 +910,9 @@ bool BKE_mesh_validate_arrays(struct Mesh *me,
const bool do_fixes,
bool *r_change);
+/**
+ * \returns is_valid.
+ */
bool BKE_mesh_validate_all_customdata(struct CustomData *vdata,
const uint totvert,
struct CustomData *edata,
@@ -627,12 +927,31 @@ bool BKE_mesh_validate_all_customdata(struct CustomData *vdata,
bool *r_change);
void BKE_mesh_strip_loose_faces(struct Mesh *me);
+/**
+ * Works on both loops and polys!
+ *
+ * \note It won't try to guess which loops of an invalid poly to remove!
+ * this is the work of the caller, to mark those loops.
+ * See e.g. #BKE_mesh_validate_arrays().
+ */
void BKE_mesh_strip_loose_polysloops(struct Mesh *me);
void BKE_mesh_strip_loose_edges(struct Mesh *me);
+/**
+ * If the mesh is from a very old blender version,
+ * convert mface->edcode to edge drawflags
+ */
void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old);
void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
+/**
+ * Calculate edges from polygons.
+ */
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, const bool select_new_edges);
+/**
+ * Calculate/create edges from tessface data
+ *
+ * \param mesh: The mesh to add edges into
+ */
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* In DerivedMesh.cc */
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
index 59f6e75183e..a7a7529f217 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
@@ -32,6 +32,16 @@ struct Mesh;
namespace blender::meshintersect {
+/**
+ * Do a mesh boolean operation directly on meshes (without going back and forth to BMesh).
+ * \param meshes: An array of Mesh pointers.
+ * \param obmats: An array of pointers to the obmat matrices that transform local
+ * coordinates to global ones. It is allowed for the pointers to be null, meaning the
+ * transformation is the identity.
+ * \param material_remaps: An array of pointers to arrays of maps from material slot numbers in the
+ * corresponding mesh to the material slot in the first mesh. It is OK for material_remaps or any
+ * of its constituent arrays to be empty.
+ */
Mesh *direct_mesh_boolean(blender::Span<const Mesh *> meshes,
blender::Span<const float4x4 *> obmats,
const float4x4 &target_transform,
diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h
index a65f25ee182..83f0228dc76 100644
--- a/source/blender/blenkernel/BKE_mesh_iterators.h
+++ b/source/blender/blenkernel/BKE_mesh_iterators.h
@@ -39,6 +39,11 @@ void BKE_mesh_foreach_mapped_vert(struct Mesh *mesh,
const short no_s[3]),
void *userData,
MeshForeachFlag flag);
+/**
+ * Copied from #cdDM_foreachMappedEdge.
+ * \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
+ * edge indices.
+ */
void BKE_mesh_foreach_mapped_edge(
struct Mesh *mesh,
int tot_edges,
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index 0518f303744..acc1628de1d 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -105,6 +105,11 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly,
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of polys that use that vertex as a corner.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
@@ -112,6 +117,11 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int totvert,
int totpoly,
int totloop);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of loops that use that vertex as a corner.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
@@ -119,6 +129,11 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int totvert,
int totpoly,
int totloop);
+/**
+ * Generates a map where the key is the edge and the value
+ * is a list of looptris that use that edge.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MVert *mvert,
@@ -127,10 +142,24 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
const int totlooptri,
const struct MLoop *mloop,
const int totloop);
+/**
+ * Generates a map where the key is the vertex and the value
+ * is a list of edges that use that vertex as an endpoint.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
+/**
+ * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly
+ * (not their edges).
+ */
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
+/**
+ * Generates a map where the key is the edge and the value is a list of loops that use that edge.
+ * Loops indices of a same poly are contiguous and in winding order.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
@@ -139,6 +168,11 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
const int totpoly,
const struct MLoop *mloop,
const int totloop);
+/**
+ * Generates a map where the key is the edge and the value
+ * is a list of polygons that use that edge.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
@@ -147,11 +181,29 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
const int totpoly,
const struct MLoop *mloop,
const int totloop);
+/**
+ * This function creates a map so the source-data (vert/edge/loop/poly)
+ * can loop over the destination data (using the destination arrays origindex).
+ *
+ * This has the advantage that it can operate on any data-types.
+ *
+ * \param totsource: The total number of elements that \a final_origindex points to.
+ * \param totfinal: The size of \a final_origindex
+ * \param final_origindex: The size of the final array.
+ *
+ * \note `totsource` could be `totpoly`,
+ * `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
+ * This would allow an MPoly to loop over its tessfaces.
+ */
void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
int **r_mem,
const int totsource,
const int *final_origindex,
const int totfinal);
+/**
+ * A version of #BKE_mesh_origindex_map_create that takes a looptri array.
+ * Making a poly -> looptri map.
+ */
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
@@ -212,7 +264,11 @@ typedef bool (*MeshRemapIslandsCalc)(struct MVert *verts,
struct MeshIslandStore *r_island_store);
/* Above vert/UV mapping stuff does not do what we need here, but does things we do not need here.
- * So better keep them separated for now, I think.
+ * So better keep them separated for now, I think. */
+
+/**
+ * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams),
+ * not some UV layers coordinates.
*/
bool BKE_mesh_calc_islands_loop_poly_edgeseam(struct MVert *verts,
const int totvert,
@@ -224,6 +280,19 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(struct MVert *verts,
const int totloop,
MeshIslandStore *r_island_store);
+/**
+ * Calculate UV islands.
+ *
+ * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
+ * This has the advantages of simplicity, and being valid/common to all UV maps.
+ * However, it means actual UV islands without matching UV seams will not be handled correctly.
+ * If a valid UV layer is passed as \a luvs parameter,
+ * UV coordinates are also used to detect islands boundaries.
+ *
+ * \note All this could be optimized.
+ * Not sure it would be worth the more complex code, though,
+ * those loops are supposed to be really quick to do.
+ */
bool BKE_mesh_calc_islands_loop_poly_uvmap(struct MVert *verts,
const int totvert,
struct MEdge *edges,
@@ -235,6 +304,14 @@ bool BKE_mesh_calc_islands_loop_poly_uvmap(struct MVert *verts,
const struct MLoopUV *luvs,
MeshIslandStore *r_island_store);
+/**
+ * Calculate smooth groups from sharp edges.
+ *
+ * \param r_totgroup: The total number of groups, 1 or more.
+ * \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
+ * starting at 1 (0 being used as 'invalid' flag).
+ * Note it's callers's responsibility to MEM_freeN returned array.
+ */
int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
const int totedge,
const struct MPoly *mpoly,
diff --git a/source/blender/blenkernel/BKE_mesh_mirror.h b/source/blender/blenkernel/BKE_mesh_mirror.h
index 7b230b04410..abb8e4d3e44 100644
--- a/source/blender/blenkernel/BKE_mesh_mirror.h
+++ b/source/blender/blenkernel/BKE_mesh_mirror.h
@@ -43,10 +43,16 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
const int axis,
const float dist);
-struct Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(struct MirrorModifierData *mmd,
- struct Object *ob,
- const struct Mesh *mesh,
- const int axis);
+/**
+ * \warning This should _not_ be used to modify original meshes since
+ * it doesn't handle shape-keys, use #BKE_mesh_mirror_apply_mirror_on_axis instead.
+ */
+struct Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ struct MirrorModifierData *mmd,
+ struct Object *ob,
+ const struct Mesh *mesh,
+ const int axis,
+ const bool use_correct_order_on_merge);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 7f8f028c26b..c33b3800aa4 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -161,11 +161,24 @@ void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
const int poly_mode,
struct CustomData_MeshMasks *cddata_mask);
+/**
+ * Compute a value of the difference between both given meshes.
+ * The smaller the result, the better the match.
+ *
+ * We return the inverse of the average of the inversed
+ * shortest distance from each dst vertex to src ones.
+ * In other words, beyond a certain (relatively small) distance, all differences have more or less
+ * the same weight in final result, which allows to reduce influence of a few high differences,
+ * in favor of a global good matching.
+ */
float BKE_mesh_remap_calc_difference_from_mesh(const struct SpaceTransform *space_transform,
const struct MVert *verts_dst,
const int numverts_dst,
struct Mesh *me_src);
+/**
+ * Set r_space_transform so that best bbox of dst matches best bbox of src.
+ */
void BKE_mesh_remap_find_best_match_from_mesh(const struct MVert *verts_dst,
const int numverts_dst,
struct Mesh *me_src,
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
index df111360bcd..764241e7f92 100644
--- a/source/blender/blenkernel/BKE_mesh_runtime.h
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -41,18 +41,42 @@ struct Mesh;
struct Object;
struct Scene;
+/**
+ * \brief Initialize the runtime of the given mesh.
+ *
+ * Function expects that the runtime is already cleared.
+ */
void BKE_mesh_runtime_init_data(struct Mesh *mesh);
+/**
+ * \brief Free all data (and mutexes) inside the runtime of the given mesh.
+ */
void BKE_mesh_runtime_free_data(struct Mesh *mesh);
+/**
+ * Clear all pointers which we don't want to be shared on copying the datablock.
+ * However, keep all the flags which defines what the mesh is (for example, that
+ * it's deformed only, or that its custom data layers are out of date.)
+ */
void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, const int flag);
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
+/**
+ * \note This function only fills a cache, and therefore the mesh argument can
+ * be considered logically const. Concurrent access is protected by a mutex.
+ * \note This is a ported copy of dm_getLoopTriArray(dm).
+ */
const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh);
bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh);
bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh);
bool BKE_mesh_runtime_reset_edit_data(struct Mesh *mesh);
void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh);
+/**
+ * \brief This function clears runtime cache of the given mesh.
+ *
+ * Call this function to recalculate runtime data when used.
+ */
void BKE_mesh_runtime_clear_cache(struct Mesh *mesh);
+/* This is a copy of DM_verttri_from_looptri(). */
void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
@@ -62,6 +86,7 @@ void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
* to a more suitable location when that file is removed.
* They should also be renamed to use conventions from BKE, not old DerivedMesh.cc.
* For now keep the names similar to avoid confusion. */
+
struct Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -99,6 +124,7 @@ void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed,
#ifndef NDEBUG
char *BKE_mesh_runtime_debug_info(struct Mesh *me_eval);
void BKE_mesh_runtime_debug_print(struct Mesh *me_eval);
+/* XXX Should go in customdata file? */
void BKE_mesh_runtime_debug_print_cdlayers(struct CustomData *data);
bool BKE_mesh_runtime_is_valid(struct Mesh *me_eval);
#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
index 96eaa23ce71..39d4072085c 100644
--- a/source/blender/blenkernel/BKE_mesh_tangent.h
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -25,6 +25,12 @@ extern "C" {
struct ReportList;
+/**
+ * Compute simplified tangent space normals, i.e.
+ * tangent vector + sign of bi-tangent one, which combined with
+ * split normals can be used to recreate the full tangent space.
+ * NOTE: * The mesh should be made of only tris and quads!
+ */
void BKE_mesh_calc_loop_tangent_single_ex(const struct MVert *mverts,
const int numVerts,
const struct MLoop *mloops,
@@ -35,11 +41,20 @@ void BKE_mesh_calc_loop_tangent_single_ex(const struct MVert *mverts,
const struct MPoly *mpolys,
const int numPolys,
struct ReportList *reports);
+/**
+ * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
+ * \note
+ * - There must be a valid loop's CD_NORMALS available.
+ * - The mesh should be made of only tris and quads!
+ */
void BKE_mesh_calc_loop_tangent_single(struct Mesh *mesh,
const char *uvmap,
float (*r_looptangents)[4],
struct ReportList *reports);
+/**
+ * See: #BKE_editmesh_loop_tangent_calc (matching logic).
+ */
void BKE_mesh_calc_loop_tangent_ex(const struct MVert *mvert,
const struct MPoly *mpoly,
const uint mpoly_len,
@@ -71,6 +86,12 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(struct CustomData *uv_data,
const char *layer_name);
#define DM_TANGENT_MASK_ORCO (1 << 9)
+/**
+ * Here we get some useful information such as active uv layer name and
+ * search if it is already in tangent_names.
+ * Also, we calculate tangent_mask that works as a descriptor of tangents state.
+ * If tangent_mask has changed, then recalculate tangents.
+ */
void BKE_mesh_calc_loop_tangent_step_0(const struct CustomData *loopData,
bool calc_active_tangent,
const char (*tangent_names)[64],
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 8be563e4c96..278189633a6 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -98,7 +98,7 @@ typedef enum {
eModifierTypeFlag_RequiresOriginalData = (1 << 5),
/**
- * For modifiers that support pointcache,
+ * For modifiers that support point-cache,
* so we can check to see if it has files we need to deal with.
*/
eModifierTypeFlag_UsesPointCache = (1 << 6),
@@ -403,6 +403,10 @@ void BKE_modifier_init(void);
const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type);
/* For modifier UI panels. */
+
+/**
+ * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
+ */
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname);
void BKE_modifier_panel_expand(struct ModifierData *md);
@@ -413,6 +417,9 @@ struct ModifierData *BKE_modifier_new(int type);
void BKE_modifier_free_ex(struct ModifierData *md, const int flag);
void BKE_modifier_free(struct ModifierData *md);
+/**
+ * Use instead of `BLI_remlink` when the object's active modifier should change.
+ */
void BKE_modifier_remove_from_list(struct Object *ob, struct ModifierData *md);
/* Generate new UUID for the given modifier. */
@@ -420,6 +427,9 @@ void BKE_modifier_session_uuid_generate(struct ModifierData *md);
bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
+/**
+ * Callback's can use this to avoid copying every member.
+ */
void BKE_modifier_copydata_generic(const struct ModifierData *md,
struct ModifierData *md_dst,
const int flag);
@@ -434,9 +444,21 @@ bool BKE_modifier_couldbe_cage(struct Scene *scene, struct ModifierData *md);
bool BKE_modifier_is_correctable_deformed(struct ModifierData *md);
bool BKE_modifier_is_same_topology(ModifierData *md);
bool BKE_modifier_is_non_geometrical(ModifierData *md);
+/**
+ * Check whether is enabled.
+ *
+ * \param scene: Current scene, may be NULL,
+ * in which case `isDisabled` callback of the modifier is never called.
+ */
bool BKE_modifier_is_enabled(const struct Scene *scene,
struct ModifierData *md,
int required_mode);
+/**
+ * Check whether given modifier is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param md: May be NULL, in which case we consider it as a non-local modifier case.
+ */
bool BKE_modifier_is_nonlocal_in_liboverride(const struct Object *ob,
const struct ModifierData *md);
void BKE_modifier_set_error(const struct Object *ob,
@@ -451,6 +473,12 @@ void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *u
struct ModifierData *BKE_modifiers_findby_type(const struct Object *ob, ModifierType type);
struct ModifierData *BKE_modifiers_findby_name(const struct Object *ob, const char *name);
void BKE_modifiers_clear_errors(struct Object *ob);
+/**
+ * used for buttons, to find out if the 'draw deformed in edit-mode option is there.
+ *
+ * Also used in transform_conversion.c, to detect crazy-space (2nd arg then is NULL).
+ * Also used for some mesh tools to give warnings.
+ */
int BKE_modifiers_get_cage_index(const struct Scene *scene,
struct Object *ob,
int *r_lastPossibleCageIndex,
@@ -461,9 +489,21 @@ bool BKE_modifiers_is_softbody_enabled(struct Object *ob);
bool BKE_modifiers_is_cloth_enabled(struct Object *ob);
bool BKE_modifiers_is_particle_enabled(struct Object *ob);
+/**
+ * Takes an object and returns its first selected armature, else just its armature.
+ * This should work for multiple armatures per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_armature(struct Object *ob);
struct Object *BKE_modifiers_is_deformed_by_meshdeform(struct Object *ob);
+/**
+ * Takes an object and returns its first selected lattice, else just its lattice.
+ * This should work for multiple lattices per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_lattice(struct Object *ob);
+/**
+ * Takes an object and returns its first selected curve, else just its curve.
+ * This should work for multiple curves per object.
+ */
struct Object *BKE_modifiers_is_deformed_by_curve(struct Object *ob);
bool BKE_modifiers_uses_multires(struct Object *ob);
bool BKE_modifiers_uses_armature(struct Object *ob, struct bArmature *arm);
@@ -500,23 +540,36 @@ typedef struct VirtualModifierData {
ShapeKeyModifierData smd;
} VirtualModifierData;
+/**
+ * This is to include things that are not modifiers in the evaluation of the modifier stack,
+ * for example parenting to an armature.
+ */
struct ModifierData *BKE_modifiers_get_virtual_modifierlist(const struct Object *ob,
struct VirtualModifierData *data);
-/** Ensure modifier correctness when changing ob->data. */
+/**
+ * Ensure modifier correctness when changing `ob->data`.
+ */
void BKE_modifiers_test_object(struct Object *ob);
-/* here for do_versions */
+/**
+ * Here for #do_versions.
+ */
void BKE_modifier_mdef_compact_influences(struct ModifierData *md);
+/**
+ * Initializes `path` with either the blend file or temporary directory.
+ */
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name);
const char *BKE_modifier_path_relbase(struct Main *bmain, struct Object *ob);
const char *BKE_modifier_path_relbase_from_global(struct Object *ob);
/* Accessors of original/evaluated modifiers. */
-/* For a given modifier data, get corresponding original one.
- * If the modifier data is already original, return it as-is. */
+/**
+ * For a given modifier data, get corresponding original one.
+ * If the modifier data is already original, return it as-is.
+ */
struct ModifierData *BKE_modifier_get_original(struct ModifierData *md);
struct ModifierData *BKE_modifier_get_evaluated(struct Depsgraph *depsgraph,
struct Object *object,
@@ -541,6 +594,15 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
float (*vertexCos)[3],
int numVerts);
+/**
+ * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
+ * e.g. second operand for boolean modifier.
+ * Note that modifiers in stack always get fully evaluated COW ID pointers,
+ * never original ones. Makes things simpler.
+ *
+ * \param get_cage_mesh: Return evaluated mesh with only deforming modifiers applied
+ * (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh).
+ */
struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval,
const bool get_cage_mesh);
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 73c7494b8fa..9148d5b760f 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -35,6 +35,10 @@ struct MovieClipScopes;
struct MovieClipUser;
struct MovieDistortion;
+/**
+ * Checks if image was already loaded, then returns same image otherwise creates new.
+ * does not load ibuf itself pass on optional frame for #name images.
+ */
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain,
const char *filepath,
@@ -44,6 +48,11 @@ void BKE_movieclip_reload(struct Main *bmain, struct MovieClip *clip);
void BKE_movieclip_clear_cache(struct MovieClip *clip);
void BKE_movieclip_clear_proxy_cache(struct MovieClip *clip);
+/**
+ * Will try to make image buffer usable when originating from the multi-layer source.
+ * Internally finds a first combined pass and uses that as a buffer.
+ * Not ideal, but is better than a complete empty buffer.
+ */
void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf);
struct ImBuf *BKE_movieclip_get_ibuf(struct MovieClip *clip, struct MovieClipUser *user);
@@ -75,11 +84,18 @@ void BKE_movieclip_update_scopes(struct MovieClip *clip,
struct MovieClipUser *user,
struct MovieClipScopes *scopes);
+/**
+ * Get segments of cached frames. useful for debugging cache policies.
+ */
void BKE_movieclip_get_cache_segments(struct MovieClip *clip,
struct MovieClipUser *user,
int *r_totseg,
int **r_points);
+/**
+ * \note currently used by proxy job for movies, threading happens within single frame
+ * (meaning scaling shall be threaded).
+ */
void BKE_movieclip_build_proxy_frame(struct MovieClip *clip,
int clip_flag,
struct MovieDistortion *distortion,
@@ -88,6 +104,10 @@ void BKE_movieclip_build_proxy_frame(struct MovieClip *clip,
int build_count,
bool undistorted);
+/**
+ * \note currently used by proxy job for sequences, threading happens within sequence
+ * (different threads handles different frames, no threading within frame is needed)
+ */
void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip,
struct ImBuf *ibuf,
struct MovieDistortion *distortion,
@@ -104,8 +124,10 @@ void BKE_movieclip_filename_for_frame(struct MovieClip *clip,
struct MovieClipUser *user,
char *name);
-/* Read image buffer from the given movie clip without acquiring the `LOCK_MOVIECLIP` lock.
- * Used by a prefetch job which takes care of creating a local copy of the clip. */
+/**
+ * Read image buffer from the given movie clip without acquiring the #LOCK_MOVIECLIP lock.
+ * Used by a prefetch job which takes care of creating a local copy of the clip.
+ */
struct ImBuf *BKE_movieclip_anim_ibuf_for_frame_no_lock(struct MovieClip *clip,
struct MovieClipUser *user);
@@ -126,10 +148,10 @@ void BKE_movieclip_eval_update(struct Depsgraph *depsgraph,
struct MovieClip *clip);
void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, struct MovieClip *clip);
-/* caching flags */
+/** Caching flags. */
#define MOVIECLIP_CACHE_SKIP (1 << 0)
-/* postprocessing flags */
+/** Post-processing flags. */
#define MOVIECLIP_DISABLE_RED (1 << 0)
#define MOVIECLIP_DISABLE_GREEN (1 << 1)
#define MOVIECLIP_DISABLE_BLUE (1 << 2)
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index 11bfc4b2b3a..c83022c4658 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -45,7 +45,9 @@ struct MLoopTri;
struct MPoly;
struct MVert;
-/* Delete mesh mdisps and grid paint masks */
+/**
+ * Delete mesh mdisps and grid paint masks.
+ */
void multires_customdata_delete(struct Mesh *me);
void multires_set_tot_level(struct Object *ob, struct MultiresModifierData *mmd, int lvl);
@@ -62,6 +64,9 @@ void multires_force_external_reload(struct Object *object);
void multires_modifier_update_mdisps(struct DerivedMesh *dm, struct Scene *scene);
void multires_modifier_update_hidden(struct DerivedMesh *dm);
+/**
+ * Reset the multi-res levels to match the number of mdisps.
+ */
void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, struct Object *ob);
typedef enum {
@@ -79,6 +84,10 @@ struct DerivedMesh *multires_make_derived_from_derived(struct DerivedMesh *dm,
struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene,
struct ModifierData *lastmd);
+/**
+ * used for applying scale on mdisps layer and syncing subdivide levels when joining objects.
+ * \param use_first: return first multi-res modifier if all multi-res'es are disabled.
+ */
struct MultiresModifierData *get_multires_modifier(struct Scene *scene,
struct Object *ob,
bool use_first);
@@ -88,18 +97,25 @@ int multires_get_level(const struct Scene *scene,
bool render,
bool ignore_simplify);
-/* Creates mesh with multires modifier applied on current object's deform mesh. */
+/**
+ * Creates mesh with multi-res modifier applied on current object's deform mesh.
+ */
struct Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd);
-/* Get coordinates of a deformed base mesh which is an input to the given multires modifier.
- * NOTE: The modifiers will be re-evaluated. */
+/**
+ * Get coordinates of a deformed base mesh which is an input to the given multi-res modifier.
+ * \note The modifiers will be re-evaluated.
+ */
float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd,
int *r_num_deformed_verts))[3];
+/**
+ * \param direction: 1 for delete higher, 0 for lower (not implemented yet).
+ */
void multiresModifier_del_levels(struct MultiresModifierData *mmd,
struct Scene *scene,
struct Object *object,
@@ -112,6 +128,10 @@ int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
int rebuild_limit,
bool switch_view_to_lower_level);
+/**
+ * If `ob_src` and `ob_dst` both have multi-res modifiers,
+ * synchronize them such that `ob_dst` has the same total number of levels as `ob_src`.
+ */
void multiresModifier_sync_levels_ex(struct Object *ob_dst,
struct MultiresModifierData *mmd_src,
struct MultiresModifierData *mmd_dst);
@@ -128,15 +148,29 @@ void multiresModifier_prepare_join(struct Depsgraph *depsgraph,
int multires_mdisp_corners(struct MDisps *s);
-/* update multires data after topology changing */
+/**
+ * Update multi-res data after topology changing.
+ */
void multires_topology_changed(struct Mesh *me);
+/**
+ * Makes sure data from an external file is fully read.
+ *
+ * Since the multi-res data files only contain displacement vectors without knowledge about
+ * subdivision level some extra work is needed. Namely make is to all displacement grids have
+ * proper level and number of displacement vectors set.
+ */
void multires_ensure_external_read(struct Mesh *mesh, int top_level);
void multiresModifier_ensure_external_read(struct Mesh *mesh,
const struct MultiresModifierData *mmd);
/**** interpolation stuff ****/
+/* Adapted from `sculptmode.c` */
+
void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v);
+/**
+ * Find per-corner coordinate with given per-face UV coord.
+ */
int mdisp_rot_face_to_crn(struct MVert *mvert,
struct MPoly *mpoly,
struct MLoop *mloop,
@@ -154,6 +188,12 @@ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
const float (*vert_coords)[3],
const int num_vert_coords);
+/**
+ * Returns truth on success, false otherwise.
+ *
+ * This function might fail in cases like source and destination not having
+ * matched amount of vertices.
+ */
bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
struct Object *dst,
@@ -166,7 +206,7 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
struct Mesh *coarse_mesh,
struct SubdivCCG *subdiv_ccg);
-/* Subdivide multires displacement once. */
+/* Subdivide multi-res displacement once. */
typedef enum eMultiresSubdivideModeType {
MULTIRES_SUBDIVIDE_CATMULL_CLARK,
@@ -180,8 +220,10 @@ void multiresModifier_subdivide(struct Object *object,
void multires_subdivide_create_tangent_displacement_linear_grids(struct Object *object,
struct MultiresModifierData *mmd);
-/* Subdivide displacement to the given level.
- * If level is lower than the current top level nothing happens. */
+/**
+ * Subdivide displacement to the given level.
+ * If level is lower than the current top level nothing happens.
+ */
void multiresModifier_subdivide_to_level(struct Object *object,
struct MultiresModifierData *mmd,
const int top_level,
@@ -206,12 +248,12 @@ void BKE_multires_subdiv_mesh_settings_init(struct SubdivToMeshSettings *mesh_se
/* General helpers. */
-/* For a given partial derivatives of a ptex face get tangent matrix for
- * displacement.
+/**
+ * For a given partial derivatives of a PTEX face get tangent matrix for displacement.
*
* Corner needs to be known to properly "rotate" partial derivatives when the
- * matrix is being constructed for quad. For non-quad the corner is to be set
- * to 0. */
+ * matrix is being constructed for quad. For non-quad the corner is to be set to 0.
+ */
BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3],
const float dPdu[3],
const float dPdv[3],
@@ -219,8 +261,10 @@ BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3]
/* Versioning. */
-/* Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark
- * subdivided mesh. */
+/**
+ * Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark
+ * subdivided mesh.
+ */
void multires_do_versions_simple_to_catmull_clark(struct Object *object,
struct MultiresModifierData *mmd);
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index cf8848fe607..b297851ad90 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -46,106 +46,291 @@ struct PropertyRNA;
/* ----------------------------- */
/* Data Management */
+/**
+ * Remove the given NLA strip from the NLA track it occupies, free the strip's data,
+ * and the strip itself.
+ */
void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user);
+/**
+ * Remove the given NLA track from the set of NLA tracks, free the track's data,
+ * and the track itself.
+ */
void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user);
+/**
+ * Free the elements of type NLA Tracks provided in the given list, but do not free
+ * the list itself since that is not free-standing
+ */
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user);
+/**
+ * Copy NLA strip
+ *
+ * \param use_same_action: When true, the existing action is used (instead of being duplicated)
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain,
struct NlaStrip *strip,
const bool use_same_action,
const int flag);
+/**
+ * Copy a single NLA Track.
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain,
struct NlaTrack *nlt,
const bool use_same_actions,
const int flag);
+/**
+ * Copy all NLA data.
+ * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
+ * flags in BKE_lib_id.h
+ */
void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, const ListBase *src, const int flag);
-/* Copy NLA tracks from #adt_source to #adt_dest, and update the active track/strip pointers to
- * point at those copies. */
+/**
+ * Copy NLA tracks from #adt_source to #adt_dest, and update the active track/strip pointers to
+ * point at those copies.
+ */
void BKE_nla_tracks_copy_from_adt(struct Main *bmain,
struct AnimData *adt_dest,
const struct AnimData *adt_source,
int flag);
+/**
+ * Add a NLA Track to the given AnimData.
+ * \param prev: NLA-Track to add the new one after.
+ */
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt,
struct NlaTrack *prev,
bool is_liboverride);
+/**
+ * Create a NLA Strip referencing the given Action.
+ */
struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
+/**
+ * Add new NLA-strip to the top of the NLA stack - i.e.
+ * into the last track if space, or a new one otherwise.
+ */
struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt,
struct bAction *act,
const bool is_liboverride);
+/**
+ * Add a NLA Strip referencing the given speaker's sound.
+ */
struct NlaStrip *BKE_nla_add_soundstrip(struct Main *bmain,
struct Scene *scene,
struct Speaker *speaker);
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_nla_strip_foreach_id(struct NlaStrip *strip, struct LibraryForeachIDData *data);
/* ----------------------------- */
/* API */
+/**
+ * Check if there is any space in the given list to add the given strip.
+ */
bool BKE_nlastrips_has_space(ListBase *strips, float start, float end);
+/**
+ * Rearrange the strips in the track so that they are always in order
+ * (usually only needed after a strip has been moved)
+ */
void BKE_nlastrips_sort_strips(ListBase *strips);
+/**
+ * Add the given NLA-Strip to the given list of strips, assuming that it
+ * isn't currently a member of another list
+ */
bool BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip);
+/**
+ * Convert 'islands' (i.e. continuous string of) selected strips to be
+ * contained within 'Meta-Strips' which act as strips which contain strips.
+ *
+ * \param is_temp: are the meta-strips to be created 'temporary' ones used for transforms?
+ */
void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp);
+/**
+ * Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips.
+ *
+ * \param only_sel: only consider selected meta-strips, otherwise all meta-strips are removed
+ * \param only_temp: only remove the 'temporary' meta-strips used for transforms
+ */
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp);
+/**
+ * Split a meta-strip into a set of normal strips.
+ */
void BKE_nlastrips_clear_metastrip(ListBase *strips, struct NlaStrip *strip);
+/**
+ * Add the given NLA-Strip to the given Meta-Strip, assuming that the
+ * strip isn't attached to any list of strips
+ */
bool BKE_nlameta_add_strip(struct NlaStrip *mstrip, struct NlaStrip *strip);
+/**
+ * Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
+ * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
+ */
void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip);
/* ............ */
+/**
+ * Find the active NLA-track for the given stack.
+ */
struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks);
+/**
+ * Make the given NLA-track the active one for the given stack. If no track is provided,
+ * this function can be used to simply deactivate all the NLA tracks in the given stack too.
+ */
void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
+/**
+ * Get the NLA Track that the active action/action strip comes from,
+ * since this info is not stored in AnimData. It also isn't as simple
+ * as just using the active track, since multiple tracks may have been
+ * entered at the same time.
+ */
struct NlaTrack *BKE_nlatrack_find_tweaked(struct AnimData *adt);
+/**
+ * Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
+ * that has this status in its AnimData block.
+ */
void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
+/**
+ * Check if there is any space in the given track to add a strip of the given length.
+ */
bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
+/**
+ * Rearrange the strips in the track so that they are always in order
+ * (usually only needed after a strip has been moved).
+ */
void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
+/**
+ * Add the given NLA-Strip to the given NLA-Track, assuming that it
+ * isn't currently attached to another one.
+ */
bool BKE_nlatrack_add_strip(struct NlaTrack *nlt,
struct NlaStrip *strip,
const bool is_liboverride);
+/**
+ * Get the extents of the given NLA-Track including gaps between strips,
+ * returning whether this succeeded or not
+ */
bool BKE_nlatrack_get_bounds(struct NlaTrack *nlt, float bounds[2]);
-
+/**
+ * Check whether given NLA track is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param nlt: May be NULL, in which case we consider it as a non-local track case.
+ */
bool BKE_nlatrack_is_nonlocal_in_liboverride(const struct ID *id, const struct NlaTrack *nlt);
/* ............ */
+/**
+ * Find the active NLA-strip within the given track.
+ */
struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
+/**
+ * Make the given NLA-Strip the active one within the given block.
+ */
void BKE_nlastrip_set_active(struct AnimData *adt, struct NlaStrip *strip);
+/**
+ * Does the given NLA-strip fall within the given bounds (times)?.
+ */
bool BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max);
+/**
+ * Recalculate the start and end frames for the current strip, after changing
+ * the extents of the action or the mapping (repeats or scale factor) info.
+ */
void BKE_nlastrip_recalculate_bounds(struct NlaStrip *strip);
+/**
+ * Recalculate the start and end frames for the strip to match the bounds of its action such that
+ * the overall NLA animation result is unchanged.
+ */
void BKE_nlastrip_recalculate_bounds_sync_action(struct NlaStrip *strip);
+/**
+ * Find (and set) a unique name for a strip from the whole AnimData block
+ * Uses a similar method to the BLI method, but is implemented differently
+ * as we need to ensure that the name is unique over several lists of tracks,
+ * not just a single track.
+ */
void BKE_nlastrip_validate_name(struct AnimData *adt, struct NlaStrip *strip);
/* ............ */
+/**
+ * Check if the given NLA-Track has any strips with own F-Curves.
+ */
bool BKE_nlatrack_has_animated_strips(struct NlaTrack *nlt);
+/**
+ * Check if given NLA-Tracks have any strips with own F-Curves.
+ */
bool BKE_nlatracks_have_animated_strips(ListBase *tracks);
+/**
+ * Validate the NLA-Strips 'control' F-Curves based on the flags set.
+ */
void BKE_nlastrip_validate_fcurves(struct NlaStrip *strip);
+/**
+ * Check if the given RNA pointer + property combo should be handled by
+ * NLA strip curves or not.
+ */
bool BKE_nlastrip_has_curves_for_property(const struct PointerRNA *ptr,
const struct PropertyRNA *prop);
+/**
+ * Ensure that auto-blending and other settings are set correctly.
+ */
void BKE_nla_validate_state(struct AnimData *adt);
/* ............ */
+/**
+ * Check if an action is "stashed" in the NLA already
+ *
+ * The criteria for this are:
+ * 1) The action in question lives in a "stash" track.
+ * 2) We only check first-level strips. That is, we will not check inside meta strips.
+ */
bool BKE_nla_action_is_stashed(struct AnimData *adt, struct bAction *act);
+/**
+ * "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
+ * to retain it in the file for future uses.
+ */
bool BKE_nla_action_stash(struct AnimData *adt, const bool is_liboverride);
/* ............ */
+/**
+ * For the given AnimData block, add the active action to the NLA
+ * stack (i.e. 'push-down' action). The UI should only allow this
+ * for normal editing only (i.e. not in edit-mode for some strip's action),
+ * so no checks for this are performed.
+ *
+ * TODO: maybe we should have checks for this too.
+ */
void BKE_nla_action_pushdown(struct AnimData *adt, const bool is_liboverride);
+/**
+ * Find the active strip + track combination, and set them up as the tweaking track,
+ * and return if successful or not.
+ */
bool BKE_nla_tweakmode_enter(struct AnimData *adt);
+/**
+ * Exit tweak-mode for this AnimData block.
+ */
void BKE_nla_tweakmode_exit(struct AnimData *adt);
/* ----------------------------- */
@@ -163,6 +348,13 @@ enum eNlaTime_ConvertModes {
NLATIME_CONVERT_MAP,
};
+/**
+ * Non clipped mapping for strip-time <-> global time:
+ * `mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*`
+ *
+ * Public API method - perform this mapping using the given AnimData block
+ * and perform any necessary sanity checks on the value
+ */
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode);
/* ----------------------------- */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index bbeb01de0ff..a2959556810 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -34,6 +34,10 @@
#include "RNA_types.h"
#ifdef __cplusplus
+# include "BLI_string_ref.hh"
+#endif
+
+#ifdef __cplusplus
extern "C" {
#endif
@@ -114,6 +118,7 @@ namespace nodes {
class NodeMultiFunctionBuilder;
class GeoNodeExecParams;
class NodeDeclarationBuilder;
+class GatherLinkSearchOpParams;
} // namespace nodes
namespace fn {
class CPPType;
@@ -121,23 +126,28 @@ class MFDataType;
} // namespace fn
} // namespace blender
+using CPPTypeHandle = blender::fn::CPPType;
using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder);
using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params);
using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder);
-using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
-using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket,
void *r_value);
+/* Adds socket link operations that are specific to this node type. */
+using NodeGatherSocketLinkOperationsFunction =
+ void (*)(blender::nodes::GatherLinkSearchOpParams &params);
+
#else
typedef void *NodeMultiFunctionBuildFunction;
typedef void *NodeGeometryExecFunction;
typedef void *NodeDeclareFunction;
+typedef void *NodeGatherSocketLinkOperationsFunction;
typedef void *SocketGetCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPValueFunction;
typedef void *SocketGetCPPValueFunction;
+typedef struct CPPTypeHandle CPPTypeHandle;
#endif
/**
@@ -164,20 +174,20 @@ typedef struct bNodeSocketType {
void (*interface_draw)(struct bContext *C, struct uiLayout *layout, struct PointerRNA *ptr);
void (*interface_draw_color)(struct bContext *C, struct PointerRNA *ptr, float *r_color);
void (*interface_register_properties)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ struct bNodeSocket *interface_socket,
struct StructRNA *data_srna);
void (*interface_init_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ const struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock,
const char *data_path);
void (*interface_verify_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ const struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock,
const char *data_path);
void (*interface_from_socket)(struct bNodeTree *ntree,
- struct bNodeSocket *stemp,
+ struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock);
@@ -197,11 +207,11 @@ typedef struct bNodeSocketType {
void (*free_self)(struct bNodeSocketType *stype);
/* Return the CPPType of this socket. */
- SocketGetCPPTypeFunction get_base_cpp_type;
+ const CPPTypeHandle *base_cpp_type;
/* Get the value of this socket in a generic way. */
SocketGetCPPValueFunction get_base_cpp_value;
/* Get geometry nodes cpp type. */
- SocketGetGeometryNodesCPPTypeFunction get_geometry_nodes_cpp_type;
+ const CPPTypeHandle *geometry_nodes_cpp_type;
/* Get geometry nodes cpp value. */
SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value;
} bNodeSocketType;
@@ -229,8 +239,6 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat,
* implementing the node behavior.
*/
typedef struct bNodeType {
- void *next, *prev;
-
char idname[64]; /* identifier name */
int type;
@@ -247,18 +255,6 @@ typedef struct bNodeType {
char storagename[64]; /* struct name for DNA */
- /* Main draw function for the node */
- void (*draw_nodetype)(const struct bContext *C,
- struct ARegion *region,
- struct SpaceNode *snode,
- struct bNodeTree *ntree,
- struct bNode *node,
- bNodeInstanceKey key);
- /* Updates the node geometry attributes according to internal state before actual drawing */
- void (*draw_nodetype_prepare)(const struct bContext *C,
- struct bNodeTree *ntree,
- struct bNode *node);
-
/* Draw the option buttons on the node */
void (*draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr);
/* Additional parameters in the side panel */
@@ -272,13 +268,10 @@ typedef struct bNodeType {
* Optional custom label function for the node header.
* \note Used as a fallback when #bNode.label isn't set.
*/
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
- /** Optional custom resize handle polling. */
- int (*resize_area_func)(struct bNode *node, int x, int y);
- /** Optional selection area polling. */
- int (*select_area_func)(struct bNode *node, int x, int y);
- /** Optional tweak area polling (for grabbing). */
- int (*tweak_area_func)(struct bNode *node, int x, int y);
+ void (*labelfunc)(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
/** Called when the node is updated in the editor. */
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node);
@@ -301,7 +294,7 @@ typedef struct bNodeType {
/**
* Can this node type be added to a node tree?
- * \param r_disabled_hint: Optional hint to display in the UI when the poll fails.
+ * \param r_disabled_hint: Hint to display in the UI when the poll fails.
* The callback can set this to a static string without having to
* null-check it (or without setting it to null if it's not used).
* The caller must pass a valid `const char **` and null-initialize it
@@ -342,6 +335,13 @@ typedef struct bNodeType {
/* Declaration to be used when it is not dynamic. */
NodeDeclarationHandle *fixed_declaration;
+ /**
+ * Add to the list of search names and operations gathered by node link drag searching.
+ * Usually it isn't necessary to override the default behavior here, but a node type can have
+ * custom behavior here like adding custom search items.
+ */
+ NodeGatherSocketLinkOperationsFunction gather_link_search_ops;
+
/** True when the node cannot be muted. */
bool no_muting;
@@ -379,12 +379,6 @@ typedef struct bNodeType {
#define NODE_CLASS_ATTRIBUTE 42
#define NODE_CLASS_LAYOUT 100
-/* node resize directions */
-#define NODE_RESIZE_TOP 1
-#define NODE_RESIZE_BOTTOM 2
-#define NODE_RESIZE_RIGHT 4
-#define NODE_RESIZE_LEFT 8
-
typedef enum eNodeSizePreset {
NODE_SIZE_DEFAULT,
NODE_SIZE_SMALL,
@@ -425,7 +419,7 @@ typedef struct bNodeTreeType {
/* Tree update. Overrides `nodetype->updatetreefunc` ! */
void (*update)(struct bNodeTree *ntree);
- bool (*validate_link)(struct bNodeTree *ntree, struct bNodeLink *link);
+ bool (*validate_link)(eNodeSocketDatatype from, eNodeSocketDatatype to);
void (*node_add_init)(struct bNodeTree *ntree, struct bNode *bnode);
@@ -462,20 +456,44 @@ struct GHashIterator *ntreeTypeGetIterator(void);
} \
(void)0
+/**
+ * Try to initialize all type-info in a node tree.
+ *
+ * \note In general undefined type-info is a perfectly valid case,
+ * the type may just be registered later.
+ * In that case the update_typeinfo function will set type-info on registration
+ * and do necessary updates.
+ */
void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree);
struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
/* copy/free funcs, need to manage ID users */
+
+/**
+ * Free (or release) any data used by this node-tree.
+ * Does not free the node-tree itself and does no ID user counting.
+ */
void ntreeFreeTree(struct bNodeTree *ntree);
-/* Free tree which is embedded into another datablock. */
+/**
+ * Free tree which is embedded into another data-block.
+ */
void ntreeFreeEmbeddedTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree,
struct Main *bmain,
const bool do_id_user);
struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree);
+/**
+ * Get address of potential node-tree pointer of given ID.
+ *
+ * \warning Using this function directly is potentially dangerous, if you don't know or are not
+ * sure, please use `ntreeFromID()` instead.
+ */
struct bNodeTree **BKE_ntree_ptr_from_id(struct ID *id);
+/**
+ * Returns the private NodeTree object of the data-block, if it has one.
+ */
struct bNodeTree *ntreeFromID(struct ID *id);
void ntreeFreeLocalNode(struct bNodeTree *ntree, struct bNode *node);
@@ -485,13 +503,17 @@ bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
void ntreeUpdateAllNew(struct Main *main);
+/**
+ * \param tree_update_flag: #eNodeTreeUpdate enum.
+ */
void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag);
void ntreeGetDependencyList(struct bNodeTree *ntree,
struct bNode ***r_deplist,
int *r_deplist_len);
-/* XXX old trees handle output flags automatically based on special output
+/**
+ * XXX: old trees handle output flags automatically based on special output
* node types and last active selection.
* New tree types have a per-output socket flag to indicate the final output to use explicitly.
*/
@@ -502,11 +524,31 @@ void ntreeFreeCache(struct bNodeTree *ntree);
bool ntreeNodeExists(const struct bNodeTree *ntree, const struct bNode *testnode);
bool ntreeOutputExists(const struct bNode *node, const struct bNodeSocket *testsock);
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable);
+/**
+ * Returns localized tree for execution in threads.
+ */
struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree);
+/**
+ * Sync local composite with real tree.
+ * The local tree is supposed to be running, be careful moving previews!
+ *
+ * Is called by jobs manager, outside threads, so it doesn't happen during draw.
+ */
void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree);
+/**
+ * Merge local tree results back, and free local tree.
+ *
+ * We have to assume the editor already changed completely.
+ */
void ntreeLocalMerge(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree);
+/**
+ * This is only direct data, tree itself should have been written.
+ */
void ntreeBlendWrite(struct BlendWriter *writer, struct bNodeTree *ntree);
+/**
+ * \note `ntree` itself has been read!
+ */
void ntreeBlendReadData(struct BlendDataReader *reader, struct bNodeTree *ntree);
void ntreeBlendReadLib(struct BlendLibReader *reader, struct bNodeTree *ntree);
void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntree);
@@ -516,6 +558,7 @@ void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntre
/* -------------------------------------------------------------------- */
/** \name Node Tree Interface
* \{ */
+
struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree,
eNodeSocketInOut in_out,
const char *identifier);
@@ -550,7 +593,7 @@ void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree);
struct bNodeType *nodeTypeFind(const char *idname);
void nodeRegisterType(struct bNodeType *ntype);
void nodeUnregisterType(struct bNodeType *ntype);
-bool nodeTypeUndefined(struct bNode *node);
+bool nodeTypeUndefined(const struct bNode *node);
struct GHashIterator *nodeTypeGetIterator(void);
/* Helper macros for iterating over node types. */
@@ -640,27 +683,42 @@ void nodeModifySocketTypeStatic(
struct bNode *nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname);
struct bNode *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type);
+/**
+ * \note Goes over entire tree.
+ */
void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Find the first available, non-duplicate name for a given node.
+ */
void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node);
-/* Delete node, associated animation data and ID user count. */
+/**
+ * Delete node, associated animation data and ID user count.
+ */
void nodeRemoveNode(struct Main *bmain,
struct bNodeTree *ntree,
struct bNode *node,
bool do_id_user);
+/**
+ * \param ntree: is the target tree.
+ *
+ * \note keep socket list order identical, for copying links.
+ * \note `unique_name` needs to be true. It's only disabled for speed when doing GPUnodetrees.
+ */
struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree,
const struct bNode *node_src,
const int flag,
const bool unique_name);
-/* Same as BKE_node_copy_ex() but stores pointers to a new node and its sockets in the source
- * node.
+/**
+ * Same as #BKE_node_copy_ex but stores pointers to a new node and its sockets in the source node.
*
* NOTE: DANGER ZONE!
*
* TODO(sergey): Maybe it's better to make BKE_node_copy_ex() return a mapping from old node and
- * sockets to new one. */
+ * sockets to new one.
+ */
struct bNode *BKE_node_copy_store_new_pointers(struct bNodeTree *ntree,
struct bNode *node_src,
const int flag);
@@ -668,6 +726,9 @@ struct bNodeTree *ntreeCopyTree_ex_new_pointers(const struct bNodeTree *ntree,
struct Main *bmain,
const bool do_id_user);
+/**
+ * Also used via RNA API, so we check for proper input output direction.
+ */
struct bNodeLink *nodeAddLink(struct bNodeTree *ntree,
struct bNode *fromnode,
struct bNodeSocket *fromsock,
@@ -691,25 +752,62 @@ void nodePositionRelative(struct bNode *from_node,
struct bNodeSocket *to_sock);
void nodePositionPropagate(struct bNode *node);
+/**
+ * Finds a node based on its name.
+ */
struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name);
+/**
+ * Finds a node based on given socket and returns true on success.
+ */
bool nodeFindNode(struct bNodeTree *ntree,
struct bNodeSocket *sock,
struct bNode **r_node,
int *r_sockindex);
+/**
+ * \note Recursive.
+ */
struct bNode *nodeFindRootParent(bNode *node);
+/**
+ * \returns true if \a child has \a parent as a parent/grandparent/... etc.
+ * \note Recursive
+ */
bool nodeIsChildOf(const bNode *parent, const bNode *child);
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * \param reversed: for backwards iteration
+ * \note Recursive
+ */
void nodeChainIter(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *, const bool),
void *userdata,
const bool reversed);
+/**
+ * Iterate over a chain of nodes, starting with \a node_start, executing
+ * \a callback for each node (which can return false to end iterator).
+ *
+ * Faster than nodeChainIter. Iter only once per node.
+ * Can be called recursively (using another nodeChainIterBackwards) by
+ * setting the recursion_lvl accordingly.
+ *
+ * \note Needs updated socket links (ntreeUpdateTree).
+ * \note Recursive
+ */
void nodeChainIterBackwards(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *),
void *userdata,
int recursion_lvl);
+/**
+ * Iterate over all parents of \a node, executing \a callback for each parent
+ * (which can return false to end iterator)
+ *
+ * \note Recursive
+ */
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
@@ -718,11 +816,20 @@ struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
int nodeCountSocketLinks(const struct bNodeTree *ntree, const struct bNodeSocket *sock);
void nodeSetSelected(struct bNode *node, bool select);
+/**
+ * Two active flags, ID nodes have special flag for buttons display.
+ */
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node);
struct bNode *nodeGetActive(struct bNodeTree *ntree);
+/**
+ * Two active flags, ID nodes have special flag for buttons display.
+ */
struct bNode *nodeGetActiveID(struct bNodeTree *ntree, short idtype);
bool nodeSetActiveID(struct bNodeTree *ntree, short idtype, struct ID *id);
void nodeClearActive(struct bNodeTree *ntree);
+/**
+ * Two active flags, ID nodes have special flag for buttons display.
+ */
void nodeClearActiveID(struct bNodeTree *ntree, short idtype);
struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
@@ -738,14 +845,31 @@ void nodeSetSocketAvailability(struct bNodeTree *ntree,
int nodeSocketLinkLimit(const struct bNodeSocket *sock);
+/**
+ * If the node implements a `declare` function, this function makes sure that `node->declaration`
+ * is up to date. It is expected that the sockets of the node are up to date already.
+ */
bool nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Just update `node->declaration` if necessary. This can also be called on nodes that may not be
+ * up to date (e.g. because the need versioning or are dynamic).
+ */
bool nodeDeclarationEnsureOnOutdatedNode(struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration
+ * and sockets are up to date already.
+ */
void nodeSocketDeclarationsUpdate(struct bNode *node);
-/* Node Clipboard */
+/**
+ * Node Clipboard.
+ */
void BKE_node_clipboard_init(const struct bNodeTree *ntree);
void BKE_node_clipboard_clear(void);
void BKE_node_clipboard_free(void);
+/**
+ * Return false when one or more ID's are lost.
+ */
bool BKE_node_clipboard_validate(void);
void BKE_node_clipboard_add_node(struct bNode *node);
void BKE_node_clipboard_add_link(struct bNodeLink *link);
@@ -753,7 +877,9 @@ const struct ListBase *BKE_node_clipboard_get_nodes(void);
const struct ListBase *BKE_node_clipboard_get_links(void);
int BKE_node_clipboard_get_type(void);
-/* Node Instance Hash */
+/**
+ * Node Instance Hash.
+ */
typedef struct bNodeInstanceHash {
/** XXX should be made a direct member, #GHash allocation needs to support it */
GHash *ghash;
@@ -761,6 +887,9 @@ typedef struct bNodeInstanceHash {
typedef void (*bNodeInstanceValueFP)(void *value);
+/**
+ * Magic number for initial hash key.
+ */
extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE;
extern const bNodeInstanceKey NODE_INSTANCE_KEY_NONE;
@@ -845,6 +974,11 @@ void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree,
struct bNodeTree *from_ntree,
bool remove_old);
+/**
+ * Hack warning! this function is only used for shader previews,
+ * and since it gets called multiple times per pixel for Z-transparency we only add the color once.
+ * Preview gets cleared before it starts render though.
+ */
void BKE_node_preview_set_pixel(
struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage);
@@ -854,14 +988,19 @@ void BKE_node_preview_set_pixel(
/** \name Node Type Access
* \{ */
-void nodeLabel(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+void nodeLabel(const struct bNodeTree *ntree, const struct bNode *node, char *label, int maxlen);
+/**
+ * Get node socket label if it is set.
+ */
const char *nodeSocketLabel(const struct bNodeSocket *sock);
bool nodeGroupPoll(struct bNodeTree *nodetree,
struct bNodeTree *grouptree,
const char **r_disabled_hint);
-/* Init a new node type struct with default values and callbacks */
+/**
+ * Initialize a new node type struct with default values and callbacks.
+ */
void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
void node_type_base_custom(
struct bNodeType *ntype, const char *idname, const char *name, short nclass, short flag);
@@ -872,15 +1011,16 @@ void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwid
void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size);
void node_type_init(struct bNodeType *ntype,
void (*initfunc)(struct bNodeTree *ntree, struct bNode *node));
+/**
+ * \warning Nodes defining a storage type _must_ allocate this for new nodes.
+ * Otherwise nodes will reload as undefined (T46619).
+ */
void node_type_storage(struct bNodeType *ntype,
const char *storagename,
void (*freefunc)(struct bNode *node),
void (*copyfunc)(struct bNodeTree *dest_ntree,
struct bNode *dest_node,
const struct bNode *src_node));
-void node_type_label(
- struct bNodeType *ntype,
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *, char *label, int maxlen));
void node_type_update(struct bNodeType *ntype,
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node));
void node_type_group_update(struct bNodeType *ntype,
@@ -986,6 +1126,7 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
} \
} \
((void)0)
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1121,8 +1262,21 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree);
void ntreeShaderEndExecTree(struct bNodeTreeExec *exec);
+/**
+ Find an output node of the shader tree.
+ *
+ * \note it will only return output which is NOT in the group, which isn't how
+ * render engines works but it's how the GPU shader compilation works. This we
+ * can change in the future and make it a generic function, but for now it stays
+ * private here.
+ */
struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target);
-
+/**
+ * This one needs to work on a local tree.
+ *
+ * TODO: This is *not* part of `blenkernel`, it's defined under "source/blender/nodes/".
+ * This declaration should be moved out of BKE.
+ */
void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
struct GPUMaterial *mat,
bool *has_surface_output,
@@ -1314,7 +1468,25 @@ void ntreeCompositExecTree(struct Scene *scene,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
const char *view_name);
+
+/**
+ * Called from render pipeline, to tag render input and output.
+ * need to do all scenes, to prevent errors when you re-render 1 scene.
+ */
void ntreeCompositTagRender(struct Scene *scene);
+/**
+ * Update the outputs of the render layer nodes.
+ * Since the outputs depend on the render engine, this part is a bit complex:
+ * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
+ * - Each render layer node calls the update function of the
+ * render engine that's used for its scene.
+ * - The render engine calls RE_engine_register_pass for each pass.
+ * - #RE_engine_register_pass calls #ntreeCompositRegisterPass,
+ * which calls #node_cmp_rlayers_register_pass for every render layer node.
+ *
+ * TODO: This is *not* part of `blenkernel`, it's defined under "source/blender/nodes/".
+ * This declaration should be moved out of BKE.
+ */
void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
void ntreeCompositRegisterPass(struct bNodeTree *ntree,
struct Scene *scene,
@@ -1355,8 +1527,10 @@ void ntreeCompositCryptomatteLayerPrefix(const Scene *scene,
const bNode *node,
char *r_prefix,
size_t prefix_len);
-/* Update the runtime layer names with the crypto-matte layer names of the references
- * render layer or image. */
+/**
+ * Update the runtime layer names with the crypto-matte layer names of the references render layer
+ * or image.
+ */
void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node);
struct CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node);
@@ -1413,6 +1587,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
int cfra,
int preview,
struct MTex *mtex);
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1507,7 +1682,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_SAMPLE_CURVE 1085
#define GEO_NODE_INPUT_TANGENT 1086
#define GEO_NODE_STRING_JOIN 1087
-#define GEO_NODE_CURVE_PARAMETER 1088
+#define GEO_NODE_CURVE_SPLINE_PARAMETER 1088
#define GEO_NODE_FILLET_CURVE 1089
#define GEO_NODE_DISTRIBUTE_POINTS_ON_FACES 1090
#define GEO_NODE_STRING_TO_CURVES 1091
@@ -1554,6 +1729,16 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_VOLUME_TO_MESH 1133
#define GEO_NODE_INPUT_ID 1134
#define GEO_NODE_SET_ID 1135
+#define GEO_NODE_ATTRIBUTE_DOMAIN_SIZE 1136
+#define GEO_NODE_DUAL_MESH 1137
+#define GEO_NODE_INPUT_MESH_EDGE_VERTICES 1138
+#define GEO_NODE_INPUT_MESH_FACE_AREA 1139
+#define GEO_NODE_INPUT_MESH_FACE_NEIGHBORS 1140
+#define GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS 1141
+#define GEO_NODE_GEOMETRY_TO_INSTANCE 1142
+#define GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS 1143
+#define GEO_NODE_INPUT_MESH_ISLAND 1144
+#define GEO_NODE_INPUT_SCENE_TIME 1145
/** \} */
@@ -1562,7 +1747,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
* \{ */
#define FN_NODE_BOOLEAN_MATH 1200
-#define FN_NODE_COMPARE_FLOATS 1202
+#define FN_NODE_COMPARE 1202
#define FN_NODE_LEGACY_RANDOM_FLOAT 1206
#define FN_NODE_INPUT_VECTOR 1207
#define FN_NODE_INPUT_STRING 1208
@@ -1599,3 +1784,25 @@ extern struct bNodeSocketType NodeSocketTypeUndefined;
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+namespace blender::bke {
+
+bNodeSocket *node_find_enabled_socket(bNode &node, eNodeSocketInOut in_out, StringRef name);
+bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name);
+bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name);
+
+} // namespace blender::bke
+
+#endif
+
+#define NODE_STORAGE_FUNCS(StorageT) \
+ [[maybe_unused]] static StorageT &node_storage(bNode &node) \
+ { \
+ return *static_cast<StorageT *>(node.storage); \
+ } \
+ [[maybe_unused]] static const StorageT &node_storage(const bNode &node) \
+ { \
+ return *static_cast<const StorageT *>(node.storage); \
+ }
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 4e53af5562f..03565bd3bda 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -52,6 +52,14 @@ struct View3D;
struct ViewLayer;
void BKE_object_workob_clear(struct Object *workob);
+/**
+ * For calculation of the inverse parent transform, only used for editor.
+ *
+ * It assumes the object parent is already in the depsgraph.
+ * Otherwise, after changing ob->parent you need to call:
+ * - #DEG_relations_tag_update(bmain);
+ * - #BKE_scene_graph_update_tagged(depsgraph, bmain);
+ */
void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -67,6 +75,9 @@ void BKE_object_free_particlesystems(struct Object *ob);
void BKE_object_free_softbody(struct Object *ob);
void BKE_object_free_curve_cache(struct Object *ob);
+/**
+ * Free data derived from mesh, called when mesh changes or is freed.
+ */
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
@@ -77,19 +88,55 @@ bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModif
bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *fx);
+/**
+ * \return True if the object's type supports regular modifiers (not grease pencil modifiers).
+ */
bool BKE_object_supports_modifiers(const struct Object *ob);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
/* Active modifier. */
+
+/**
+ * Set the object's active modifier.
+ *
+ * \param md: If nullptr, only clear the active modifier, otherwise
+ * it must be in the #Object.modifiers list.
+ */
void BKE_object_modifier_set_active(struct Object *ob, struct ModifierData *md);
struct ModifierData *BKE_object_active_modifier(const struct Object *ob);
+/**
+ * Copy a single modifier.
+ *
+ * \note *Do not* use this function to copy a whole modifier stack (see note below too). Use
+ * `BKE_object_modifier_stack_copy` instead.
+ *
+ * \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
+ * systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
+ * which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
+ * more than once, this function should preferably be called in stack order.
+ */
bool BKE_object_copy_modifier(struct Main *bmain,
struct Scene *scene,
struct Object *ob_dst,
const struct Object *ob_src,
struct ModifierData *md);
+/**
+ * Copy a single GPencil modifier.
+ *
+ * \note *Do not* use this function to copy a whole modifier stack. Use
+ * `BKE_object_modifier_stack_copy` instead.
+ */
bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, struct GpencilModifierData *gmd_src);
+/**
+ * Copy the whole stack of modifiers from one object into another.
+ *
+ * \warning *Does not* clear modifier stack and related data (particle systems, soft-body,
+ * etc.) in `ob_dst`, if needed calling code must do it.
+ *
+ * \param do_copy_all: If true, even modifiers that should not support copying (like Hook one)
+ * will be duplicated.
+ */
bool BKE_object_modifier_stack_copy(struct Object *ob_dst,
const struct Object *ob_src,
const bool do_copy_all,
@@ -98,6 +145,12 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
void BKE_object_free_modifiers(struct Object *ob, const int flag);
void BKE_object_free_shaderfx(struct Object *ob, const int flag);
+/**
+ * Proxy rule:
+ * - `lib_object->proxy_from` == the one we borrow from, set temporally while object_update.
+ * - `local_object->proxy` == pointer to library object, saved in files and read.
+ * - `local_object->proxy_group` == pointer to collection dupli-object, saved in files and read.
+ */
void BKE_object_make_proxy(struct Main *bmain,
struct Object *ob,
struct Object *target,
@@ -105,6 +158,9 @@ void BKE_object_make_proxy(struct Main *bmain,
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest);
+/**
+ * Actual check for internal data, not context or flags.
+ */
bool BKE_object_is_in_editmode(const struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(const struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(const struct Object *ob);
@@ -115,6 +171,9 @@ bool BKE_object_data_is_in_editmode(const struct ID *id);
char *BKE_object_data_editmode_flush_ptr_get(struct ID *id);
+/**
+ * Updates select_id of all objects in the given \a bmain.
+ */
void BKE_object_update_select_id(struct Main *bmain);
typedef enum eObjectVisibilityResult {
@@ -124,14 +183,33 @@ typedef enum eObjectVisibilityResult {
OB_VISIBLE_ALL = (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES),
} eObjectVisibilityResult;
+/**
+ * Return which parts of the object are visible, as evaluated by depsgraph.
+ */
int BKE_object_visibility(const struct Object *ob, const int dag_eval_mode);
+/**
+ * More general add: creates minimum required data, but without vertices etc.
+ */
struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
+/**
+ * General add: to scene, with layer from area and default name.
+ *
+ * Object is added to the active #Collection.
+ * If there is no linked collection to the active #ViewLayer we create a new one.
+ *
+ * \note Creates minimum required data, but without vertices etc.
+ */
struct Object *BKE_object_add(struct Main *bmain,
struct ViewLayer *view_layer,
int type,
const char *name) ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL;
+/**
+ * Add a new object, using another one as a reference
+ *
+ * \param ob_src: object to use to determine the collections of the new object.
+ */
struct Object *BKE_object_add_from(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -139,6 +217,15 @@ struct Object *BKE_object_add_from(struct Main *bmain,
const char *name,
struct Object *ob_src)
ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL;
+/**
+ * Add a new object, but assign the given data-block as the `ob->data`
+ * for the newly created object.
+ *
+ * \param data: The data-block to assign as `ob->data` for the new object.
+ * This is assumed to be of the correct type.
+ * \param do_id_user: If true, #id_us_plus() will be called on data when
+ * assigning it to the object.
+ */
struct Object *BKE_object_add_for_data(struct Main *bmain,
struct ViewLayer *view_layer,
int type,
@@ -147,16 +234,39 @@ struct Object *BKE_object_add_for_data(struct Main *bmain,
bool do_id_user) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1);
+/**
+ * Return -1 on failure.
+ */
int BKE_object_obdata_to_type(const struct ID *id) ATTR_NONNULL(1);
+/**
+ * Returns true if the Object is from an external blend file (libdata).
+ */
bool BKE_object_is_libdata(const struct Object *ob);
+/**
+ * Returns true if the Object data is from an external blend file (libdata).
+ */
bool BKE_object_obdata_is_libdata(const struct Object *ob);
+/**
+ * Perform deep-copy of object and its 'children' data-blocks (obdata, materials, actions, etc.).
+ *
+ * \param dupflag: Controls which sub-data are also duplicated
+ * (see #eDupli_ID_Flags in DNA_userdef_types.h).
+ *
+ * \note This function does not do any remapping to new IDs, caller must do it
+ * (\a #BKE_libblock_relink_to_newid()).
+ * \note Caller MUST free \a newid pointers itself (#BKE_main_id_newptr_and_tag_clear()) and call
+ * updates of DEG too (#DAG_relations_tag_update()).
+ */
struct Object *BKE_object_duplicate(struct Main *bmain,
struct Object *ob,
uint dupflag,
uint duplicate_options);
+/**
+ * Use with newly created objects to set their size (used to apply scene-scale).
+ */
void BKE_object_obdata_size_init(struct Object *ob, const float size);
void BKE_object_scale_to_mat3(struct Object *ob, float r_mat[3][3]);
@@ -164,15 +274,26 @@ void BKE_object_rot_to_mat3(const struct Object *ob, float r_mat[3][3], bool use
void BKE_object_mat3_to_rot(struct Object *ob, float r_mat[3][3], bool use_compat);
void BKE_object_to_mat3(struct Object *ob, float r_mat[3][3]);
void BKE_object_to_mat4(struct Object *ob, float r_mat[4][4]);
-void BKE_object_apply_mat4(struct Object *ob,
- const float mat[4][4],
- const bool use_compat,
- const bool use_parent);
+/**
+ * Applies the global transformation \a mat to the \a ob using a relative parent space if
+ * supplied.
+ *
+ * \param mat: the global transformation mat that the object should be set object to.
+ * \param parent: the parent space in which this object will be set relative to
+ * (should probably always be parent_eval).
+ * \param use_compat: true to ensure that rotations are set using the
+ * min difference between the old and new orientation.
+ */
void BKE_object_apply_mat4_ex(struct Object *ob,
const float mat[4][4],
struct Object *parent,
const float parentinv[4][4],
const bool use_compat);
+/** See #BKE_object_apply_mat4_ex */
+void BKE_object_apply_mat4(struct Object *ob,
+ const float mat[4][4],
+ const bool use_compat,
+ const bool use_parent);
void BKE_object_matrix_local_get(struct Object *ob, float r_mat[4][4]);
bool BKE_object_pose_context_check(const struct Object *ob);
@@ -181,6 +302,9 @@ struct Object *BKE_object_pose_armature_get_visible(struct Object *ob,
struct ViewLayer *view_layer,
struct View3D *v3d);
+/**
+ * Access pose array with special check to get pose object when in weight paint mode.
+ */
struct Object **BKE_object_pose_array_get_ex(struct ViewLayer *view_layer,
struct View3D *v3d,
unsigned int *r_objects_len,
@@ -205,7 +329,9 @@ struct Base **BKE_object_pose_base_array_get(struct ViewLayer *view_layer,
void BKE_object_get_parent_matrix(struct Object *ob, struct Object *par, float r_parentmat[4][4]);
-/* Compute object world transform and store it in ob->obmat. */
+/**
+ * Compute object world transform and store it in `ob->obmat`.
+ */
void BKE_object_where_is_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_object_where_is_calc_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -216,9 +342,16 @@ void BKE_object_where_is_calc_time(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
float ctime);
+/**
+ * Calculate object transformation matrix without recalculating dependencies and
+ * constraints -- assume dependencies are already solved by depsgraph.
+ * No changes to object and its parent would be done.
+ * Used for bundles orientation in 3d space relative to parented blender camera.
+ */
void BKE_object_where_is_calc_mat4(struct Object *ob, float r_obmat[4][4]);
/* Possibly belong in own module? */
+
struct BoundBox *BKE_boundbox_alloc_unit(void);
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]);
void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]);
@@ -230,6 +363,14 @@ void BKE_boundbox_minmax(const struct BoundBox *bb,
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_dimensions_get(struct Object *ob, float r_vec[3]);
+/**
+ * The original scale and object matrix can be passed in so any difference
+ * of the objects matrix and the final matrix can be accounted for,
+ * typically this caused by parenting, constraints or delta-scale.
+ *
+ * Re-using these values from the object causes a feedback loop
+ * when multiple values are modified at once in some situations. see: T69536.
+ */
void BKE_object_dimensions_set_ex(struct Object *ob,
const float value[3],
int axis_mask,
@@ -238,8 +379,12 @@ void BKE_object_dimensions_set_ex(struct Object *ob,
void BKE_object_dimensions_set(struct Object *ob, const float value[3], int axis_mask);
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
+/**
+ * Use this to temporally disable/enable bound-box.
+ */
void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
void BKE_object_boundbox_calc_from_mesh(struct Object *ob, const struct Mesh *me_eval);
+bool BKE_object_boundbox_calc_from_evaluated_geometry(struct Object *ob);
void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
bool BKE_object_minmax_dupli(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -248,7 +393,9 @@ bool BKE_object_minmax_dupli(struct Depsgraph *depsgraph,
float r_max[3],
const bool use_hidden);
-/* sometimes min-max isn't enough, we need to loop over each point */
+/**
+ * Sometimes min-max isn't enough, we need to loop over each point.
+ */
void BKE_object_foreach_display_point(struct Object *ob,
const float obmat[4][4],
void (*func_cb)(const float[3], void *),
@@ -279,9 +426,18 @@ void BKE_object_tfm_protected_restore(struct Object *ob,
void BKE_object_tfm_copy(struct Object *object_dst, const struct Object *object_src);
+/**
+ * Restore the object->data to a non-modifier evaluated state.
+ *
+ * Some changes done directly in evaluated object require them to be reset
+ * before being re-evaluated.
+ * For example, we need to call this before #BKE_mesh_new_from_object(),
+ * in case we removed/added modifiers in the evaluated object.
+ */
void BKE_object_eval_reset(struct Object *ob_eval);
/* Dependency graph evaluation callbacks. */
+
void BKE_object_eval_local_transform(struct Depsgraph *depsgraph, struct Object *ob);
void BKE_object_eval_parent(struct Depsgraph *depsgraph, struct Object *ob);
void BKE_object_eval_constraints(struct Depsgraph *depsgraph,
@@ -294,6 +450,9 @@ void BKE_object_eval_uber_transform(struct Depsgraph *depsgraph, struct Object *
void BKE_object_eval_uber_data(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * Assign #Object.data after modifier stack evaluation.
+ */
void BKE_object_eval_assign_data(struct Object *object, struct ID *data, bool is_owned);
void BKE_object_sync_to_original(struct Depsgraph *depsgraph, struct Object *object);
@@ -319,7 +478,27 @@ void BKE_object_eval_eval_base_flags(struct Depsgraph *depsgraph,
void BKE_object_handle_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/**
+ * \warning "scene" here may not be the scene object actually resides in.
+ * When dealing with background-sets, "scene" is actually the active scene.
+ * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
+ * rigid bodies depend on their world so use #BKE_object_handle_update_ex()
+ * to also pass along the current rigid body world.
+ */
void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+/**
+ * Proxy rule:
+ * - lib_object->proxy_from == the one we borrow from, only set temporal and cleared here.
+ * - local_object->proxy == pointer to library object, saved in files and read.
+ *
+ * Function below is polluted with proxy exceptions, cleanup will follow!
+ *
+ * The main object update call, for object matrix, constraints, keys and displist (modifiers)
+ * requires flags to be set!
+ *
+ * Ideally we shouldn't have to pass the rigid body world,
+ * but need bigger restructuring to avoid id.
+ */
void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -329,17 +508,32 @@ void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
void BKE_object_sculpt_data_create(struct Object *ob);
bool BKE_object_obdata_texspace_get(struct Object *ob,
- short **r_texflag,
+ char **r_texflag,
float **r_loc,
float **r_size);
+/** Get evaluated mesh for given object. */
struct Mesh *BKE_object_get_evaluated_mesh(const struct Object *object);
+/**
+ * Get mesh which is not affected by modifiers:
+ * - For original objects it will be same as `object->data`, and it is a mesh
+ * which is in the corresponding #Main.
+ * - For copied-on-write objects it will give pointer to a copied-on-write
+ * mesh which corresponds to original object's mesh.
+ */
struct Mesh *BKE_object_get_pre_modified_mesh(const struct Object *object);
+/**
+ * Get a mesh which corresponds to the very original mesh from #Main.
+ * - For original objects it will be object->data.
+ * - For evaluated objects it will be same mesh as corresponding original
+ * object uses as data.
+ */
struct Mesh *BKE_object_get_original_mesh(const struct Object *object);
/* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice,
* whichever is currently in use. */
+
struct Lattice *BKE_object_get_lattice(const struct Object *object);
struct Lattice *BKE_object_get_evaluated_lattice(const struct Object *object);
@@ -356,12 +550,38 @@ bool BKE_object_flag_test_recursive(const struct Object *ob, short flag);
bool BKE_object_is_child_recursive(const struct Object *ob_parent, const struct Object *ob_child);
-/* return ModifierMode flag */
+/**
+ * Most important if this is modified it should _always_ return true, in certain
+ * cases false positives are hard to avoid (shape keys for example).
+ *
+ * \return #ModifierMode flag.
+ */
int BKE_object_is_modified(struct Scene *scene, struct Object *ob);
+/**
+ * Test if object is affected by deforming modifiers (for motion blur). again
+ * most important is to avoid false positives, this is to skip computations
+ * and we can still if there was actual deformation afterwards.
+ */
int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob);
+/**
+ * Check of objects moves in time.
+ *
+ * \note This function is currently optimized for usage in combination
+ * with modifier deformation checks (#eModifierTypeType_OnlyDeform),
+ * so modifiers can quickly check if their target objects moves
+ * (causing deformation motion blur) or not.
+ *
+ * This makes it possible to give some degree of false-positives here,
+ * but it's currently an acceptable tradeoff between complexity and check
+ * speed. In combination with checks of modifier stack and real life usage
+ * percentage of false-positives shouldn't be that high.
+ *
+ * \note This function does not consider physics systems.
+ */
bool BKE_object_moves_in_time(const struct Object *object, bool recurse_parent);
+/** Return the number of scenes using (instantiating) that object in their collections. */
int BKE_object_scenes_users_get(struct Main *bmain, struct Object *ob);
struct MovieClip *BKE_object_movieclip_get(struct Scene *scene,
@@ -369,7 +589,16 @@ struct MovieClip *BKE_object_movieclip_get(struct Scene *scene,
bool use_default);
void BKE_object_runtime_reset(struct Object *object);
+/**
+ * Reset all pointers which we don't want to be shared when copying the object.
+ */
void BKE_object_runtime_reset_on_copy(struct Object *object, const int flag);
+/**
+ * The function frees memory used by the runtime data, but not the runtime field itself.
+ *
+ * All runtime data is cleared to ensure it's not used again,
+ * in keeping with other `_free_data(..)` functions.
+ */
void BKE_object_runtime_free_data(struct Object *object);
void BKE_object_batch_cache_dirty_tag(struct Object *ob);
@@ -393,12 +622,31 @@ typedef enum eObjectSet {
OB_SET_ALL, /* All Objects. */
} eObjectSet;
+/**
+ * Iterates over all objects of the given scene layer.
+ * Depending on the #eObjectSet flag:
+ * collect either #OB_SET_ALL, #OB_SET_VISIBLE or #OB_SET_SELECTED objects.
+ * If #OB_SET_VISIBLE or#OB_SET_SELECTED are collected,
+ * then also add related objects according to the given \a includeFilter.
+ */
struct LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
eObjectSet objectSet,
eObRelationTypes includeFilter);
+/**
+ * \return All groups this object is a part of, caller must free.
+ */
struct LinkNode *BKE_object_groups(struct Main *bmain, struct Scene *scene, struct Object *ob);
void BKE_object_groups_clear(struct Main *bmain, struct Scene *scene, struct Object *object);
+/**
+ * Return a KDTree_3d from the deformed object (in world-space).
+ *
+ * \note Only mesh objects currently support deforming, others are TODO.
+ *
+ * \param ob:
+ * \param r_tot:
+ * \return The KD-tree or nullptr if it can't be created.
+ */
struct KDTree_3d *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
bool BKE_object_modifier_use_time(struct Scene *scene,
@@ -406,6 +654,10 @@ bool BKE_object_modifier_use_time(struct Scene *scene,
struct ModifierData *md,
int dag_eval_mode);
+/**
+ * \note this function should eventually be replaced by depsgraph functionality.
+ * Avoid calling this in new code unless there is a very good reason for it!
+ */
bool BKE_object_modifier_update_subframe(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -419,7 +671,8 @@ bool BKE_object_empty_image_frame_is_visible_in_view3d(const struct Object *ob,
bool BKE_object_empty_image_data_is_visible_in_view3d(const struct Object *ob,
const struct RegionView3D *rv3d);
-/* This is an utility function for Python's object.to_mesh() (the naming is not very clear though).
+/**
+ * This is an utility function for Python's object.to_mesh() (the naming is not very clear though).
* The result is owned by the object.
*
* The mesh will be freed when object is re-evaluated or is destroyed. It is possible to force to
@@ -436,11 +689,12 @@ struct Mesh *BKE_object_to_mesh(struct Depsgraph *depsgraph,
void BKE_object_to_mesh_clear(struct Object *object);
-/* This is an utility function for Python's object.to_curve().
+/**
+ * This is an utility function for Python's `object.to_curve()`.
* The result is owned by the object.
*
* The curve will be freed when object is re-evaluated or is destroyed. It is possible to force
- * clear memory used by this curve by calling BKE_object_to_curve_clear().
+ * clear memory used by this curve by calling #BKE_object_to_curve_clear().
*
* If apply_modifiers is true and the object is a curve one, then spline deform modifiers are
* applied on the curve control points.
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index a10158254c2..ddbf5178ab0 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -31,24 +31,73 @@ struct MDeformVert;
struct Object;
struct bDeformGroup;
-/* General vgroup operations */
+/* General vgroup operations. */
+
+/**
+ * Update users of vgroups from this object, according to given map.
+ *
+ * Use it when you remove or reorder vgroups in the object.
+ *
+ * \param map: an array mapping old indices to new indices.
+ */
void BKE_object_defgroup_remap_update_users(struct Object *ob, const int *map);
+/**
+ * Get #MDeformVert vgroup data from given object. Should only be used in Object mode.
+ *
+ * \return True if the id type supports weights.
+ */
bool BKE_object_defgroup_array_get(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot);
+/**
+ * Add a vgroup of default name to object. *Does not* handle #MDeformVert data at all!
+ */
struct bDeformGroup *BKE_object_defgroup_add(struct Object *ob);
+/**
+ * Add a vgroup of given name to object. *Does not* handle #MDeformVert data at all!
+ */
struct bDeformGroup *BKE_object_defgroup_add_name(struct Object *ob, const char *name);
+/**
+ * Create #MDeformVert data for given ID. Work in Object mode only.
+ */
struct MDeformVert *BKE_object_defgroup_data_create(struct ID *id);
+/**
+ * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
+ *
+ * \param use_selection: Only operate on selection.
+ * \return True if any vertex was removed, false otherwise.
+ */
bool BKE_object_defgroup_clear(struct Object *ob,
struct bDeformGroup *dg,
const bool use_selection);
+/**
+ * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
+ *
+ * \param use_selection: Only operate on selection.
+ * \return True if any vertex was removed, false otherwise.
+ */
bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection);
+/**
+ * Remove given vgroup from object. Work in Object and Edit modes.
+ */
void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ * When only_unlocked=true, locked vertex groups are not removed.
+ */
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked);
+/**
+ * Remove all vgroups from object. Work in Object and Edit modes.
+ */
void BKE_object_defgroup_remove_all(struct Object *ob);
+/**
+ * Compute mapping for vertex groups with matching name, -1 is used for no remapping.
+ * Returns null if no remapping is required.
+ * The returned array has to be freed.
+ */
int *BKE_object_defgroup_index_map_create(struct Object *ob_src,
struct Object *ob_dst,
int *r_map_len);
@@ -57,34 +106,69 @@ void BKE_object_defgroup_index_map_apply(struct MDeformVert *dvert,
const int *map,
int map_len);
-/* Select helpers */
+/* Select helpers. */
+
enum eVGroupSelect;
+/**
+ * Return the subset type of the Vertex Group Selection.
+ */
bool *BKE_object_defgroup_subset_from_select_type(struct Object *ob,
enum eVGroupSelect subset_type,
int *r_defgroup_tot,
int *r_subset_count);
+/**
+ * Store indices from the defgroup_validmap (faster lookups in some cases).
+ */
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
const int defgroup_tot,
int *r_defgroup_subset_map);
/* ********** */
+/**
+ * Gets the status of "flag" for each #bDeformGroup
+ * in the object data's vertex group list and returns an array containing them
+ */
bool *BKE_object_defgroup_lock_flags_get(struct Object *ob, const int defbase_tot);
bool *BKE_object_defgroup_validmap_get(struct Object *ob, const int defbase_tot);
+/**
+ * Returns total selected vgroups,
+ * `wpi.defbase_sel` is assumed malloc'd, all values are set.
+ */
bool *BKE_object_defgroup_selected_get(struct Object *ob,
int defbase_tot,
int *r_dg_flags_sel_tot);
+/**
+ * Checks if the lock relative mode is applicable.
+ *
+ * \return true if an unlocked deform group is active.
+ */
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
const bool *validmap,
int index);
+/**
+ * Additional check for whether the lock relative mode is applicable in multi-paint mode.
+ *
+ * \return true if none of the selected groups are locked.
+ */
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
const bool *lock_flags,
const bool *selected,
int sel_tot);
+/**
+ * Takes a pair of boolean masks of all locked and all deform groups, and computes
+ * a pair of masks for locked deform and unlocked deform groups. Output buffers may
+ * reuse the input ones.
+ */
void BKE_object_defgroup_split_locked_validmap(
int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked);
+/**
+ * Marks mirror vgroups in output and counts them.
+ * Output and counter assumed to be already initialized.
+ * Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
+ */
void BKE_object_defgroup_mirror_selection(struct Object *ob,
int defbase_tot,
const bool *selection,
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 186e0ec174b..4388190221d 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -74,12 +74,21 @@ struct Ocean *BKE_ocean_add(void);
void BKE_ocean_free_data(struct Ocean *oc);
void BKE_ocean_free(struct Ocean *oc);
bool BKE_ocean_ensure(struct OceanModifierData *omd, const int resolution);
+/**
+ * Return true if the ocean data is valid and can be used.
+ */
bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
struct OceanModifierData const *omd,
const int resolution);
+/**
+ * Return true if the ocean is valid and can be used.
+ */
bool BKE_ocean_is_valid(const struct Ocean *o);
+/**
+ * Return true if the ocean data is valid and can be used.
+ */
bool BKE_ocean_init(struct Ocean *o,
int M,
int N,
@@ -104,15 +113,26 @@ bool BKE_ocean_init(struct Ocean *o,
int seed);
void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount);
-/* sampling the ocean surface */
float BKE_ocean_jminus_to_foam(float jminus, float coverage);
+/**
+ * Sampling the ocean surface.
+ */
void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float v);
+/**
+ * Use catmullrom interpolation rather than linear.
+ */
void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v);
void BKE_ocean_eval_xz(struct Ocean *oc, struct OceanResult *ocr, float x, float z);
void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x, float z);
+/**
+ * Note that this doesn't wrap properly for i, j < 0, but its not really meant for that being
+ * just a way to get the raw data out to save in some image format.
+ */
void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j);
-/* ocean cache handling */
+/**
+ * Ocean cache handling.
+ */
struct OceanCache *BKE_ocean_init_cache(const char *bakepath,
const char *relbase,
int start,
@@ -136,8 +156,26 @@ void BKE_ocean_free_cache(struct OceanCache *och);
void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd);
/* ocean_spectrum.c */
+
+/**
+ * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind.
+ * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing
+ * for days over an area that includes hundreds of wavelengths on a side.
+ */
float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, const float kx, const float kz);
+/**
+ * TMA extends the JONSWAP spectrum.
+ * This spectral model is best suited to shallow water.
+ */
float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, const float kx, const float kz);
+/**
+ * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening
+ * function This enhancement is an artificial construct to address the problem that the wave
+ * spectrum is never fully developed.
+ *
+ * The fetch parameter represents the distance from a lee shore,
+ * called the fetch, or the distance over which the wind blows with constant velocity.
+ */
float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, const float kx, const float kz);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h
index 8ddf77e3d49..e3deff9d8fa 100644
--- a/source/blender/blenkernel/BKE_packedFile.h
+++ b/source/blender/blenkernel/BKE_packedFile.h
@@ -57,17 +57,32 @@ enum ePF_FileStatus {
PF_ASK = 10,
};
-/* pack */
+/* Pack. */
+
struct PackedFile *BKE_packedfile_duplicate(const struct PackedFile *pf_src);
struct PackedFile *BKE_packedfile_new(struct ReportList *reports,
const char *filename,
const char *basepath);
struct PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen);
+/**
+ * No libraries for now.
+ */
void BKE_packedfile_pack_all(struct Main *bmain, struct ReportList *reports, bool verbose);
void BKE_packedfile_pack_all_libraries(struct Main *bmain, struct ReportList *reports);
-/* unpack */
+/* Unpack. */
+
+/**
+ * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name)
+ * and a packed file.
+ *
+ * It returns a char *to the existing file name / new file name or NULL when
+ * there was an error or when the user decides to cancel the operation.
+ *
+ * \warning 'abs_name' may be relative still! (use a "//" prefix)
+ * be sure to run #BLI_path_abs on it first.
+ */
char *BKE_packedfile_unpack_to_file(struct ReportList *reports,
const char *ref_file_name,
const char *abs_name,
@@ -107,23 +122,38 @@ int BKE_packedfile_write_to_file(struct ReportList *reports,
struct PackedFile *pf,
const bool guimode);
-/* free */
+/* Free. */
+
void BKE_packedfile_free(struct PackedFile *pf);
-/* info */
+/* Info. */
+
int BKE_packedfile_count_all(struct Main *bmain);
+/**
+ * This function compares a packed file to a 'real' file.
+ * It returns an integer indicating if:
+ *
+ * - #PF_EQUAL: the packed file and original file are identical.
+ * - #PF_DIFFERENT: the packed file and original file differ.
+ * - #PF_NOFILE: the original file doesn't exist.
+ */
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
const char *filename,
struct PackedFile *pf);
-/* read */
+/* Read. */
+
int BKE_packedfile_seek(struct PackedFile *pf, int offset, int whence);
void BKE_packedfile_rewind(struct PackedFile *pf);
int BKE_packedfile_read(struct PackedFile *pf, void *data, int size);
-/* ID should be not NULL, return true if there's a packed file */
+/**
+ * ID should be not NULL, return true if there's a packed file.
+ */
bool BKE_packedfile_id_check(const struct ID *id);
-/* ID should be not NULL, throws error when ID is Library */
+/**
+ * ID should be not NULL, throws error when ID is Library.
+ */
void BKE_packedfile_id_unpack(struct Main *bmain,
struct ID *id,
struct ReportList *reports,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 6fc5ef4d870..40e3ab74fac 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -111,10 +111,11 @@ typedef enum ePaintOverlayControlFlags {
(PAINT_OVERLAY_OVERRIDE_SECONDARY | PAINT_OVERLAY_OVERRIDE_PRIMARY | \
PAINT_OVERLAY_OVERRIDE_CURSOR)
-/* Defines 8 areas resulting of splitting the object space by the XYZ axis planes. This is used to
+/**
+ * Defines 8 areas resulting of splitting the object space by the XYZ axis planes. This is used to
* flip or mirror transform values depending on where the vertex is and where the transform
- * operation started to support XYZ symmetry on those operations in a predictable way. */
-
+ * operation started to support XYZ symmetry on those operations in a predictable way.
+ */
#define PAINT_SYMM_AREA_DEFAULT 0
typedef enum ePaintSymmetryAreas {
@@ -136,10 +137,14 @@ ePaintOverlayControlFlags BKE_paint_get_overlay_flags(void);
void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag);
void BKE_paint_set_overlay_override(enum eOverlayFlags flag);
-/* palettes */
+/* Palettes. */
+
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
+/**
+ * Remove color from palette. Must be certain color is inside the palette!
+ */
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
void BKE_palette_clear(struct Palette *palette);
@@ -152,12 +157,21 @@ bool BKE_palette_from_hash(struct Main *bmain,
const char *name,
const bool linear);
-/* paint curves */
+/* Paint curves. */
+
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
+/**
+ * Call when entering each respective paint mode.
+ */
bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint);
void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
+/**
+ * Called when copying scene settings, so even if 'src' and 'tar' are the same still do a
+ * #id_us_plus(), rather than if we were copying between 2 existing scenes where a matching
+ * value should decrease the existing user count as with #paint_brush_set()
+ */
void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag);
void BKE_paint_runtime_init(const struct ToolSettings *ts, struct Paint *paint);
@@ -181,26 +195,46 @@ void BKE_paint_palette_set(struct Paint *p, struct Palette *palette);
void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc);
void BKE_paint_curve_clamp_endpoint_add_index(struct PaintCurve *pc, const int add_index);
-/* testing face select mode
- * Texture paint could be removed since selected faces are not used
- * however hiding faces is useful */
+/**
+ * Return true when in vertex/weight/texture paint + face-select mode?
+ */
bool BKE_paint_select_face_test(struct Object *ob);
+/**
+ * Return true when in vertex/weight paint + vertex-select mode?
+ */
bool BKE_paint_select_vert_test(struct Object *ob);
+/**
+ * used to check if selection is possible
+ * (when we don't care if its face or vert)
+ */
bool BKE_paint_select_elem_test(struct Object *ob);
-/* partial visibility */
+/* Partial visibility. */
+
+/**
+ * Returns non-zero if any of the face's vertices are hidden, zero otherwise.
+ */
bool paint_is_face_hidden(const struct MLoopTri *lt,
const struct MVert *mvert,
const struct MLoop *mloop);
+/**
+ * Returns non-zero if any of the corners of the grid
+ * face whose inner corner is at (x, y) are hidden, zero otherwise.
+ */
bool paint_is_grid_face_hidden(const unsigned int *grid_hidden, int gridsize, int x, int y);
+/**
+ * Return true if all vertices in the face are visible, false otherwise.
+ */
bool paint_is_bmesh_face_hidden(struct BMFace *f);
-/* paint masks */
+/* Paint masks. */
+
float paint_grid_paint_mask(const struct GridPaintMask *gpm, uint level, uint x, uint y);
void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uchar r_color[4]);
-/* stroke related */
+/* Stroke related. */
+
bool paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups,
struct Brush *brush,
const float mouse_pos[2]);
@@ -211,14 +245,20 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups,
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
/* Tool slot API. */
+
void BKE_paint_toolslots_init_from_main(struct Main *bmain);
void BKE_paint_toolslots_len_ensure(struct Paint *paint, int len);
void BKE_paint_toolslots_brush_update_ex(struct Paint *paint, struct Brush *brush);
void BKE_paint_toolslots_brush_update(struct Paint *paint);
+/**
+ * Run this to ensure brush types are set for each slot on entering modes
+ * (for new scenes for example).
+ */
void BKE_paint_toolslots_brush_validate(struct Main *bmain, struct Paint *paint);
struct Brush *BKE_paint_toolslots_brush_get(struct Paint *paint, int slot_index);
/* .blend I/O */
+
void BKE_paint_blend_write(struct BlendWriter *writer, struct Paint *paint);
void BKE_paint_blend_read_data(struct BlendDataReader *reader,
const struct Scene *scene,
@@ -229,7 +269,7 @@ void BKE_paint_blend_read_lib(struct BlendLibReader *reader,
#define SCULPT_FACE_SET_NONE 0
-/* Used for both vertex color and weight paint */
+/** Used for both vertex color and weight paint. */
struct SculptVertexPaintGeomMap {
int *vert_map_mem;
struct MeshElemMap *vert_to_loop;
@@ -237,7 +277,7 @@ struct SculptVertexPaintGeomMap {
struct MeshElemMap *vert_to_poly;
};
-/* Pose Brush IK Chain */
+/** Pose Brush IK Chain. */
typedef struct SculptPoseIKChainSegment {
float orig[3];
float head[3];
@@ -620,10 +660,15 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
-/* Create new color layer on object if it doesn't have one and if experimental feature set has
- * sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise. */
+/**
+ * Create new color layer on object if it doesn't have one and if experimental feature set has
+ * sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise.
+ */
void BKE_sculpt_color_layer_create_if_needed(struct Object *object);
+/**
+ * \warning Expects a fully evaluated depsgraph.
+ */
void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph,
struct Object *ob_orig,
bool need_pmap,
@@ -632,6 +677,10 @@ void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph,
void BKE_sculpt_update_object_before_eval(struct Object *ob_eval);
void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Object *ob_eval);
+/**
+ * Sculpt mode handles multi-res differently from regular meshes, but only if
+ * it's the last modifier on the stack and it is not on the first level.
+ */
struct MultiresModifierData *BKE_sculpt_multires_active(struct Scene *scene, struct Object *ob);
int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
@@ -640,19 +689,37 @@ struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct O
void BKE_sculpt_bvh_update_from_ccg(struct PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
-/* This ensure that all elements in the mesh (both vertices and grids) have their visibility
- * updated according to the face sets. */
+/**
+ * This ensure that all elements in the mesh (both vertices and grids) have their visibility
+ * updated according to the face sets.
+ */
void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg);
-/* Individual function to sync the Face Set visibility to mesh and grids. */
+/**
+ * Individual function to sync the Face Set visibility to mesh and grids.
+ */
void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(struct Mesh *mesh);
void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh,
struct SubdivCCG *subdiv_ccg);
+/**
+ * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
+ * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
+ * mesh to the Face Sets. */
void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(struct Mesh *mesh);
+/**
+ * Ensures we do have expected mesh data in original mesh for the sculpt mode.
+ *
+ * \note IDs are expected to be original ones here, and calling code should ensure it updates its
+ * depsgraph properly after calling this function if it needs up-to-date evaluated data.
+ */
void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object);
+/**
+ * Test if PBVH can be used directly for drawing, which is faster than
+ * drawing the mesh and all updates that come with it.
+ */
bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d);
enum {
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 78a6e47ec48..972cba2d132 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -286,6 +286,9 @@ BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float ve
/* ----------- functions needed outside particlesystem ---------------- */
/* particle.c */
+
+/* Few helpers for count-all etc. */
+
int count_particles(struct ParticleSystem *psys);
int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
@@ -296,8 +299,13 @@ int psys_get_tot_child(struct Scene *scene,
struct ParticleSystem *psys,
const bool use_render_params);
+/**
+ * Get object's active particle system safely.
+ */
struct ParticleSystem *psys_get_current(struct Object *ob);
-/* for rna */
+
+/* For RNA API. */
+
short psys_get_current_num(struct Object *ob);
void psys_set_current_num(struct Object *ob, int index);
/* UNUSED */
@@ -305,14 +313,17 @@ void psys_set_current_num(struct Object *ob, int index);
struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
-/* For a given evaluated particle system get its original.
+/**
+ * For a given evaluated particle system get its original.
*
- * If this input is an original particle system already, the return value is the
- * same as the input. */
+ * If this input is an original particle system already, the return value is the same as the input.
+ */
struct ParticleSystem *psys_orig_get(struct ParticleSystem *psys);
-/* For a given original object and its particle system, get evaluated particle
- * system within a given dependency graph. */
+/**
+ * For a given original object and its particle system,
+ * get evaluated particle system within a given dependency graph.
+ */
struct ParticleSystem *psys_eval_get(struct Depsgraph *depsgraph,
struct Object *object,
struct ParticleSystem *psys);
@@ -328,11 +339,17 @@ void psys_check_group_weights(struct ParticleSettings *part);
int psys_uses_gravity(struct ParticleSimulationData *sim);
void BKE_particlesettings_fluid_default_settings(struct ParticleSettings *part);
-/* free */
+/**
+ * Free cache path.
+ */
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit);
+/**
+ * Free everything.
+ */
void psys_free(struct Object *ob, struct ParticleSystem *psys);
-
-/* Copy. */
+/**
+ * Copy.
+ */
void psys_copy_particles(struct ParticleSystem *psys_dst, struct ParticleSystem *psys_src);
bool psys_render_simplify_params(struct ParticleSystem *psys,
@@ -379,6 +396,12 @@ void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render
void psys_unique_name(struct Object *object, struct ParticleSystem *psys, const char *defname);
+/**
+ * Calculates paths ready for drawing/rendering
+ * - Useful for making use of opengl vertex arrays for super fast strand drawing.
+ * - Makes child strands possible and creates them too into the cache.
+ * - Cached path data is also used to determine cut position for the edit-mode tool.
+ */
void psys_cache_paths(struct ParticleSimulationData *sim,
float cfra,
const bool use_render_params);
@@ -409,16 +432,24 @@ float psys_get_child_size(struct ParticleSystem *psys,
struct ChildParticle *cpa,
float cfra,
float *pa_time);
+/**
+ * Gets hair (or keyed) particles state at the "path time" specified in `state->time`.
+ */
void psys_get_particle_on_path(struct ParticleSimulationData *sim,
int pa_num,
struct ParticleKey *state,
const bool vel);
-int psys_get_particle_state(struct ParticleSimulationData *sim,
- int p,
- struct ParticleKey *state,
- int always);
+/**
+ * Gets particle's state at a time.
+ * \return true if particle exists and can be seen and false if not.
+ */
+bool psys_get_particle_state(struct ParticleSimulationData *sim,
+ int p,
+ struct ParticleKey *state,
+ const bool always);
+
+/* Child paths. */
-/* child paths */
void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_twist_curve_init(struct ParticleSettings *part);
@@ -434,9 +465,13 @@ void psys_apply_child_modifiers(struct ParticleThreadContext *ctx,
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
void psys_sph_finalize(struct SPHData *sphdata);
+/**
+ * Sample the density field at a point in space.
+ */
void psys_sph_density(struct BVHTree *tree, struct SPHData *data, float co[3], float vars[2]);
-/* for anim.c */
+/* For anim.c */
+
void psys_get_dupli_texture(struct ParticleSystem *psys,
struct ParticleSettings *part,
struct ParticleSystemModifierData *psmd,
@@ -451,6 +486,9 @@ void psys_get_dupli_path_transform(struct ParticleSimulationData *sim,
float mat[4][4],
float *scale);
+/**
+ * Threaded child particle distribution and path caching.
+ */
void psys_thread_context_init(struct ParticleThreadContext *ctx,
struct ParticleSimulationData *sim);
void psys_thread_context_free(struct ParticleThreadContext *ctx);
@@ -467,9 +505,16 @@ void psys_apply_hair_lattice(struct Depsgraph *depsgraph,
struct ParticleSystem *psys);
/* particle_system.c */
+
struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
+/**
+ * Counts valid keyed targets.
+ */
void psys_count_keyed_targets(struct ParticleSimulationData *sim);
void psys_update_particle_tree(struct ParticleSystem *psys, float cfra);
+/**
+ * System type has changed so set sensible defaults and clear non applicable flags.
+ */
void psys_changed_type(struct Object *ob, struct ParticleSystem *psys);
void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys);
@@ -486,13 +531,19 @@ void psys_get_birth_coords(struct ParticleSimulationData *sim,
float dtime,
float cfra);
+/**
+ * Main particle update call, checks that things are ok on the large scale and
+ * then advances in to actual particle calculations depending on particle type.
+ */
void particle_system_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct ParticleSystem *psys,
const bool use_render_params);
-/* Callback format for performing operations on ID-pointers for particle systems */
+/**
+ * Callback format for performing operations on ID-pointers for particle systems.
+ */
typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys,
struct ID **idpoin,
void *userdata,
@@ -502,11 +553,15 @@ void BKE_particlesystem_id_loop(struct ParticleSystem *psys,
ParticleSystemIDFunc func,
void *userdata);
-/* Reset all particle systems in the given object. */
+/**
+ * Reset all particle systems in the given object.
+ */
void BKE_particlesystem_reset_all(struct Object *object);
/* ----------- functions needed only inside particlesystem ------------ */
+
/* particle.c */
+
void psys_disable_all(struct Object *ob);
void psys_enable_all(struct Object *ob);
@@ -544,6 +599,9 @@ void psys_get_texture(struct ParticleSimulationData *sim,
struct ParticleTexture *ptex,
int event,
float cfra);
+/**
+ * Interpolate a location on a face based on face coordinates.
+ */
void psys_interpolate_face(struct MVert *mvert,
struct MFace *mface,
struct MTFace *tface,
@@ -561,11 +619,16 @@ float psys_particle_value_from_verts(struct Mesh *mesh,
void psys_get_from_key(
struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time);
-/* BLI_bvhtree_ray_cast callback */
+/**
+ * Callback for #BVHTree near test.
+ */
void BKE_psys_collision_neartest_cb(void *userdata,
int index,
const struct BVHTreeRay *ray,
struct BVHTreeRayHit *hit);
+/**
+ * Interprets particle data to get a point on a mesh in object space.
+ */
void psys_particle_on_dm(struct Mesh *mesh_final,
int from,
int index,
@@ -579,18 +642,37 @@ void psys_particle_on_dm(struct Mesh *mesh_final,
float orco[3]);
/* particle_system.c */
+
void distribute_particles(struct ParticleSimulationData *sim, int from);
+/**
+ * Set particle parameters that don't change during particle's life.
+ */
void init_particle(struct ParticleSimulationData *sim, struct ParticleData *pa);
void psys_calc_dmcache(struct Object *ob,
struct Mesh *mesh_final,
struct Mesh *mesh_original,
struct ParticleSystem *psys);
+/**
+ * Find the final derived mesh tessface for a particle, from its original tessface index.
+ * This is slow and can be optimized but only for many lookups.
+ *
+ * \param mesh_final: Final mesh, it may not have the same topology as original mesh.
+ * \param mesh_original: Original mesh, use for accessing #MPoly to #MFace mapping.
+ * \param findex_orig: The input tessface index.
+ * \param fw: Face weights (position of the particle inside the \a findex_orig tessface).
+ * \param poly_nodes: May be NULL, otherwise an array of linked list,
+ * one for each final \a mesh_final polygon, containing all its tessfaces indices.
+ * \return The \a mesh_final tessface index.
+ */
int psys_particle_dm_face_lookup(struct Mesh *mesh_final,
struct Mesh *mesh_original,
- int findex,
+ int findex_orig,
const float fw[4],
struct LinkNode **poly_nodes);
+/**
+ * Sets particle to the emitter surface with initial velocity & rotation.
+ */
void reset_particle(struct ParticleSimulationData *sim,
struct ParticleData *pa,
float dtime,
@@ -629,6 +711,7 @@ extern void (*BKE_particle_batch_cache_dirty_tag_cb)(struct ParticleSystem *psys
extern void (*BKE_particle_batch_cache_free_cb)(struct ParticleSystem *psys);
/* .blend file I/O */
+
void BKE_particle_partdeflect_blend_read_data(struct BlendDataReader *reader,
struct PartDeflect *pd);
void BKE_particle_partdeflect_blend_read_lib(struct BlendLibReader *reader,
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 3a0e9d48af7..5e7a9883de6 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -90,7 +90,9 @@ void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
/* Callbacks */
-/* returns 1 if the search should continue from this node, 0 otherwise */
+/**
+ * Returns true if the search should continue from this node, false otherwise.
+ */
typedef bool (*BKE_pbvh_SearchCallback)(PBVHNode *node, void *data);
typedef void (*BKE_pbvh_HitCallback)(PBVHNode *node, void *data);
@@ -101,6 +103,12 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float
/* Building */
PBVH *BKE_pbvh_new(void);
+/**
+ * Do a full rebuild with on Mesh data structure.
+ *
+ * \note Unlike mpoly/mloop/verts, looptri is *totally owned* by PBVH
+ * (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
+ */
void BKE_pbvh_build_mesh(PBVH *pbvh,
const struct Mesh *mesh,
const struct MPoly *mpoly,
@@ -112,6 +120,9 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
struct CustomData *pdata,
const struct MLoopTri *looptri,
int looptri_num);
+/**
+ * Do a full rebuild with on Grids data structure.
+ */
void BKE_pbvh_build_grids(PBVH *pbvh,
struct CCGElem **grids,
int totgrid,
@@ -119,6 +130,9 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
+/**
+ * Build a PBVH from a BMesh.
+ */
void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct BMesh *bm,
bool smooth_shading,
@@ -170,8 +184,10 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
float *depth,
float *r_edge_length);
-/* for orthographic cameras, project the far away ray segment points to the root node so
- * we can have better precision. */
+/**
+ * For orthographic cameras, project the far away ray segment points to the root node so
+ * we can have better precision.
+ */
void BKE_pbvh_raycast_project_ray_root(
PBVH *pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]);
@@ -215,12 +231,19 @@ typedef enum {
PBVHType BKE_pbvh_type(const PBVH *pbvh);
bool BKE_pbvh_has_faces(const PBVH *pbvh);
-/* Get the PBVH root's bounding box */
+/**
+ * Get the PBVH root's bounding box.
+ */
void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]);
-/* multires hidden data, only valid for type == PBVH_GRIDS */
+/**
+ * Multi-res hidden data, only valid for type == PBVH_GRIDS.
+ */
unsigned int **BKE_pbvh_grid_hidden(const PBVH *pbvh);
+/**
+ * Returns the number of visible quads in the nodes' grids.
+ */
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
const int *grid_indices,
int totgrid,
@@ -228,7 +251,9 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh);
-/* multires level, only valid for type == PBVH_GRIDS */
+/**
+ * Multi-res level, only valid for type == #PBVH_GRIDS.
+ */
const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh);
struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh);
@@ -236,7 +261,9 @@ BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh);
int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh);
-/* Only valid for type == PBVH_BMESH */
+/**
+ * Only valid for type == #PBVH_BMESH.
+ */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
@@ -244,6 +271,9 @@ typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
+/**
+ * Collapse short edges, subdivide long edges.
+ */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
@@ -287,18 +317,28 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
float BKE_pbvh_node_get_tmin(PBVHNode *node);
-/* test if AABB is at least partially inside the PBVHFrustumPlanes volume */
+/**
+ * Test if AABB is at least partially inside the #PBVHFrustumPlanes volume.
+ */
bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
-/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
+/**
+ * Test if AABB is at least partially outside the #PBVHFrustumPlanes volume.
+ */
bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
+/**
+ * In order to perform operations on the original node coordinates
+ * (currently just ray-cast), store the node's triangles and vertices.
+ *
+ * Skips triangles that are hidden.
+ */
void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
-/* Update Bounding Box/Redraw and clear flags */
+/* Update Bounding Box/Redraw and clear flags. */
void BKE_pbvh_update_bounds(PBVH *pbvh, int flags);
void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flags);
@@ -318,14 +358,15 @@ void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default);
void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide);
-/* vertex deformer */
+/* Vertex Deformer. */
+
float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3];
void BKE_pbvh_vert_coords_apply(struct PBVH *pbvh, const float (*vertCos)[3], const int totvert);
bool BKE_pbvh_is_deformed(struct PBVH *pbvh);
-/* Vertex Iterator */
+/* Vertex Iterator. */
-/* this iterator has quite a lot of code, but it's designed to:
+/* This iterator has quite a lot of code, but it's designed to:
* - allow the compiler to eliminate dead code and variables
* - spend most of the time in the relatively simple inner loop */
@@ -469,6 +510,11 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int *r_orco_tris_num,
float (**r_orco_coords)[3]);
+/**
+ * \note doing a full search on all vertices here seems expensive,
+ * however this is important to avoid having to recalculate bound-box & sync the buffers to the
+ * GPU (which is far more expensive!) See: T47232.
+ */
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
@@ -480,7 +526,8 @@ void pbvh_show_mask_set(PBVH *pbvh, bool show_mask);
bool pbvh_has_face_sets(PBVH *pbvh);
void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets);
-/* Parallelization */
+/* Parallelization. */
+
void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
bool use_threading,
int totnode);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index c83fca767a1..47d3d83f8bb 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -273,19 +273,28 @@ typedef struct PTCacheEdit {
int totpoint, totframes, totcached, edited;
} PTCacheEdit;
-/* Particle functions */
void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **data, float time);
/**************** Creating ID's ****************************/
+
void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb);
void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys);
void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
+/**
+ * The fluid modifier does not actually use this anymore, but some parts of Blender expect that it
+ * still has a point cache currently. For example, the fluid modifier uses
+ * #DEG_add_collision_relations, which internally creates relations with the point cache.
+ */
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *fmd);
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid,
struct Object *ob,
struct DynamicPaintSurface *surface);
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
+/**
+ * \param ob: Optional, may be NULL.
+ * \param scene: Optional may be NULL.
+ */
PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache);
void BKE_ptcache_ids_from_object(struct ListBase *lb,
struct Object *ob,
@@ -294,12 +303,11 @@ void BKE_ptcache_ids_from_object(struct ListBase *lb,
/****************** Query funcs ****************************/
-/* Check whether object has a point cache. */
+/**
+ * Check whether object has a point cache.
+ */
bool BKE_ptcache_object_has(struct Scene *scene, struct Object *ob, int duplis);
-/***************** Global funcs ****************************/
-void BKE_ptcache_remove(void);
-
/************ ID specific functions ************************/
void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra);
bool BKE_ptcache_id_exist(PTCacheID *id, int cfra);
@@ -316,23 +324,35 @@ void BKE_ptcache_update_info(PTCacheID *pid);
/*********** General cache reading/writing ******************/
-/* Size of cache data type. */
+/**
+ * Size of cache data type.
+ */
int BKE_ptcache_data_size(int data_type);
-/* Is point with index in memory cache */
+/**
+ * Is point with index in memory cache?
+ * Check to see if point number "index" is in `pm` (uses binary search for index data).
+ */
int BKE_ptcache_mem_index_find(struct PTCacheMem *pm, unsigned int index);
/* Memory cache read/write helpers. */
+
void BKE_ptcache_mem_pointers_init(struct PTCacheMem *pm, void *cur[BPHYS_TOT_DATA]);
void BKE_ptcache_mem_pointers_incr(void *cur[BPHYS_TOT_DATA]);
int BKE_ptcache_mem_pointers_seek(int point_index,
struct PTCacheMem *pm,
void *cur[BPHYS_TOT_DATA]);
-/* Main cache reading call. */
+/**
+ * Main cache reading call.
+ * Possible to get old or interpolated result.
+ */
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old);
-/* Main cache writing call. */
+/**
+ * Main cache writing call.
+ * Writes cache to disk or memory.
+ */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra);
/******************* Allocate & free ***************/
@@ -340,41 +360,56 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches);
void BKE_ptcache_free_mem(struct ListBase *mem_cache);
void BKE_ptcache_free(struct PointCache *cache);
void BKE_ptcache_free_list(struct ListBase *ptcaches);
+/* returns first point cache */
struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new,
const struct ListBase *ptcaches_old,
const int flag);
/********************** Baking *********************/
-/* Bakes cache with cache_step sized jumps in time, not accurate but very fast. */
+/**
+ * Bakes cache with cache_step sized jumps in time, not accurate but very fast.
+ */
void BKE_ptcache_quick_cache_all(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Bake cache or simulate to current frame with settings defined in the baker. */
+/**
+ * Bake cache or simulate to current frame with settings defined in the baker.
+ * if bake is not given run simulations to current frame.
+ */
void BKE_ptcache_bake(struct PTCacheBaker *baker);
-/* Convert disk cache to memory cache. */
+/**
+ * Convert disk cache to memory cache.
+ */
void BKE_ptcache_disk_to_mem(struct PTCacheID *pid);
-
-/* Convert memory cache to disk cache. */
+/**
+ * Convert memory cache to disk cache.
+ */
void BKE_ptcache_mem_to_disk(struct PTCacheID *pid);
-
-/* Convert disk cache to memory cache and vice versa. Clears the cache that was converted. */
+/**
+ * Convert disk cache to memory cache and vice versa. Clears the cache that was converted.
+ */
void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid);
-
-/* Rename all disk cache files with a new name. Doesn't touch the actual content of the files. */
+/**
+ * Rename all disk cache files with a new name. Doesn't touch the actual content of the files.
+ */
void BKE_ptcache_disk_cache_rename(struct PTCacheID *pid,
const char *name_src,
const char *name_dst);
-/* Loads simulation from external (disk) cache files. */
+/**
+ * Loads simulation from external (disk) cache files.
+ */
void BKE_ptcache_load_external(struct PTCacheID *pid);
-
-/* Set correct flags after successful simulation step */
+/**
+ * Set correct flags after successful simulation step.
+ */
void BKE_ptcache_validate(struct PointCache *cache, int framenr);
-
-/* Set correct flags after unsuccessful simulation step */
+/**
+ * Set correct flags after unsuccessful simulation step.
+ */
void BKE_ptcache_invalidate(struct PointCache *cache);
/********************** .blend File I/O *********************/
diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h
index d2d390dc786..af8a6ed293d 100644
--- a/source/blender/blenkernel/BKE_pointcloud.h
+++ b/source/blender/blenkernel/BKE_pointcloud.h
@@ -18,7 +18,7 @@
/** \file
* \ingroup bke
- * \brief General operations for point-clouds.
+ * \brief General operations for point clouds.
*/
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/blenkernel/BKE_preferences.h b/source/blender/blenkernel/BKE_preferences.h
index e9cb024f117..6d6c58e5c1e 100644
--- a/source/blender/blenkernel/BKE_preferences.h
+++ b/source/blender/blenkernel/BKE_preferences.h
@@ -35,6 +35,10 @@ struct bUserAssetLibrary;
struct bUserAssetLibrary *BKE_preferences_asset_library_add(struct UserDef *userdef,
const char *name,
const char *path) ATTR_NONNULL(1);
+/**
+ * Unlink and free a library preference member.
+ * \note Free's \a library itself.
+ */
void BKE_preferences_asset_library_remove(struct UserDef *userdef,
struct bUserAssetLibrary *library) ATTR_NONNULL();
@@ -42,6 +46,12 @@ void BKE_preferences_asset_library_name_set(struct UserDef *userdef,
struct bUserAssetLibrary *library,
const char *name) ATTR_NONNULL();
+/**
+ * Set the library path, ensuring it is pointing to a directory.
+ * Single blend files can only act as "Current File" library; libraries on disk
+ * should always be directories. If the path does not exist, that's fine; it can
+ * created as directory if necessary later.
+ */
void BKE_preferences_asset_library_path_set(struct bUserAssetLibrary *library, const char *path)
ATTR_NONNULL();
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index ec2e8d0f875..8b585fd0167 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -35,9 +35,14 @@ extern "C" {
* These functions also accept NULL in case no error reporting
* is needed. */
-/* report structures are stored in DNA */
+/* Report structures are stored in DNA. */
void BKE_reports_init(ReportList *reports, int flag);
+/**
+ * Only frees the list \a reports.
+ * To make displayed reports disappear, either remove window-manager reports
+ * (#wmWindowManager.reports, or #CTX_wm_reports()), or use #WM_report_banners_cancel().
+ */
void BKE_reports_clear(ReportList *reports);
void BKE_report(ReportList *reports, eReportType type, const char *message);
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index e28f668d189..1c9bad7fbe8 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -38,11 +38,21 @@ struct Object;
struct ReportList;
struct Scene;
-/* -------------- */
-/* Memory Management */
+/* -------------------------------------------------------------------- */
+/** \name Memory Management
+ * \{ */
+/**
+ * Free rigid-body world.
+ */
void BKE_rigidbody_free_world(struct Scene *scene);
+/**
+ * Free rigid-body settings and simulation instances.
+ */
void BKE_rigidbody_free_object(struct Object *ob, struct RigidBodyWorld *rbw);
+/**
+ * Free rigid-body constraint and simulation instance.
+ */
void BKE_rigidbody_free_constraint(struct Object *ob);
/* ...... */
@@ -52,7 +62,15 @@ void BKE_rigidbody_object_copy(struct Main *bmain,
const struct Object *ob_src,
const int flag);
-/* Callback format for performing operations on ID-pointers for rigidbody world. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Iterator
+ * \{ */
+
+/**
+ * Callback format for performing operations on ID-pointers for rigid-body world.
+ */
typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw,
struct ID **idpoin,
void *userdata,
@@ -62,43 +80,83 @@ void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw,
RigidbodyWorldIDFunc func,
void *userdata);
-/* -------------- */
-/* Setup */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Setup
+ * \{ */
-/* create Blender-side settings data - physics objects not initialized yet */
+/**
+ * Set up RigidBody world.
+ *
+ * Create Blender-side settings data - physics objects not initialized yet.
+ */
struct RigidBodyWorld *BKE_rigidbody_create_world(struct Scene *scene);
+/**
+ * Add rigid body settings to the specified object.
+ */
struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene,
struct Object *ob,
short type);
+/**
+ * Add rigid body constraint to the specified object.
+ */
struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene,
struct Object *ob,
short type);
-/* Ensure newly set collections' objects all have required data. */
+/**
+ * Ensure newly set collections' objects all have required data.
+ */
void BKE_rigidbody_objects_collection_validate(struct Scene *scene, struct RigidBodyWorld *rbw);
void BKE_rigidbody_constraints_collection_validate(struct Scene *scene,
struct RigidBodyWorld *rbw);
-/* Ensure object added to collection gets RB data if that collection is a RB one. */
+/**
+ * Ensure object added to collection gets RB data if that collection is a RB one.
+ */
void BKE_rigidbody_main_collection_object_add(struct Main *bmain,
struct Collection *collection,
struct Object *object);
-/* copy */
+/**
+ * Copy.
+ */
struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, const int flag);
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
-/* 'validate' (i.e. make new or replace old) Physics-Engine objects */
+/**
+ * 'validate' (i.e. make new or replace old) Physics-Engine objects.
+ */
+/**
+ * Create physics sim world given RigidBody world settings
+ *
+ * \note this does NOT update object references that the scene uses,
+ * in case those aren't ready yet!
+ */
void BKE_rigidbody_validate_sim_world(struct Scene *scene,
struct RigidBodyWorld *rbw,
bool rebuild);
+/**
+ * Helper function to calculate volume of rigid-body object.
+
+ * TODO: allow a parameter to specify method used to calculate this?
+ */
void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol);
void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_center[3]);
-/* -------------- */
-/* Utilities */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/**
+ * Get RigidBody world for the given scene, creating one if needed
+ *
+ * \param scene: Scene to find active Rigid Body world for.
+ */
struct RigidBodyWorld *BKE_rigidbody_get_world(struct Scene *scene);
bool BKE_rigidbody_add_object(struct Main *bmain,
struct Scene *scene,
@@ -115,41 +173,68 @@ void BKE_rigidbody_remove_constraint(struct Main *bmain,
struct Object *ob,
const bool free_us);
-/* -------------- */
-/* Utility Macros */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utility Macros
+ * \{ */
-/* get mass of Rigid Body Object to supply to RigidBody simulators */
+/**
+ * Get mass of Rigid Body Object to supply to RigidBody simulators.
+ */
#define RBO_GET_MASS(rbo) \
(((rbo) && (((rbo)->type == RBO_TYPE_PASSIVE) || ((rbo)->flag & RBO_FLAG_KINEMATIC) || \
((rbo)->flag & RBO_FLAG_DISABLED))) ? \
(0.0f) : \
((rbo)->mass))
-/* Get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin,
- * convex hull always uses custom margin. */
+/**
+ * Get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin,
+ * convex hull always uses custom margin.
+ */
#define RBO_GET_MARGIN(rbo) \
(((rbo)->flag & RBO_FLAG_USE_MARGIN || (rbo)->shape == RB_SHAPE_CONVEXH || \
(rbo)->shape == RB_SHAPE_TRIMESH || (rbo)->shape == RB_SHAPE_CONE) ? \
((rbo)->margin) : \
(0.04f))
-/* -------------- */
-/* Simulation */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simulation
+ * \{ */
+
+/**
+ * Used when canceling transforms - return rigidbody and object to initial states.
+ */
void BKE_rigidbody_aftertrans_update(struct Object *ob,
float loc[3],
float rot[3],
float quat[4],
float rotAxis[3],
float rotAngle);
+/**
+ * Sync rigid body and object transformations.
+ */
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime);
bool BKE_rigidbody_is_affected_by_simulation(struct Object *ob);
void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
+/**
+ * Rebuild rigid body world.
+ *
+ * NOTE: this needs to be called before frame update to work correctly.
+ */
void BKE_rigidbody_rebuild_world(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
+/**
+ * Run RigidBody simulation for the specified physics world.
+ */
void BKE_rigidbody_do_simulation(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
-/* -------------------- */
-/* Depsgraph evaluation */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Depsgraph evaluation
+ * \{ */
void BKE_rigidbody_rebuild_sim(struct Depsgraph *depsgraph, struct Scene *scene);
@@ -159,6 +244,8 @@ void BKE_rigidbody_object_sync_transforms(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index f3edf8e9f64..77cf250471f 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -46,7 +46,7 @@ typedef enum eSceneCopyMethod {
SCE_COPY_FULL = 3,
} eSceneCopyMethod;
-/* Use as the contents of a 'for' loop: for (SETLOOPER(...)) { ... */
+/** Use as the contents of a 'for' loop: `for (SETLOOPER(...)) { ... }`. */
#define SETLOOPER(_sce_basis, _sce_iter, _base) \
_sce_iter = _sce_basis, \
_base = _setlooper_base_step( \
@@ -64,6 +64,12 @@ typedef enum eSceneCopyMethod {
_base; \
_base = _setlooper_base_step(&_sce_iter, NULL, _base)
+/**
+ * Helper function for the #SETLOOPER and #SETLOOPER_VIEW_LAYER macros
+ *
+ * It iterates over the bases of the active layer and then the bases
+ * of the active layer of the background (set) scenes recursively.
+ */
struct Base *_setlooper_base_step(struct Scene **sce_iter,
struct ViewLayer *view_layer,
struct Base *base);
@@ -77,6 +83,9 @@ void BKE_scene_remove_rigidbody_object(struct Main *bmain,
struct Object *ob,
const bool free_us);
+/**
+ * Check if there is any instance of the object in the scene.
+ */
bool BKE_scene_object_find(struct Scene *scene, struct Object *ob);
struct Object *BKE_scene_object_find_by_name(const struct Scene *scene, const char *name);
@@ -91,6 +100,10 @@ typedef struct SceneBaseIter {
int phase;
} SceneBaseIter;
+/**
+ * Used by meta-balls, return *all* objects (including duplis)
+ * existing in the scene (including scene's sets).
+ */
int BKE_scene_base_iter_next(struct Depsgraph *depsgraph,
struct SceneBaseIter *iter,
struct Scene **scene,
@@ -99,11 +112,33 @@ int BKE_scene_base_iter_next(struct Depsgraph *depsgraph,
struct Object **ob);
void BKE_scene_base_flag_to_objects(struct ViewLayer *view_layer);
+/**
+ * Synchronize object base flags
+ *
+ * This is usually handled by the depsgraph.
+ * However, in rare occasions we need to use the latest object flags
+ * before depsgraph is fully updated.
+ *
+ * It should (ideally) only run for copy-on-written objects since this is
+ * runtime data generated per-view-layer.
+ */
void BKE_scene_object_base_flag_sync_from_base(struct Base *base);
+/**
+ * Sets the active scene, mainly used when running in background mode
+ * (`--scene` command line argument).
+ * This is also called to set the scene directly, bypassing windowing code.
+ * Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
+ */
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
+/**
+ * Called from `creator_args.c`.
+ */
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
+/**
+ * \param flag: copying options (see BKE_lib_id.h's `LIB_ID_COPY_...` flags for more).
+ */
struct ToolSettings *BKE_toolsettings_copy(struct ToolSettings *toolsettings, const int flag);
void BKE_toolsettings_free(struct ToolSettings *toolsettings);
@@ -122,23 +157,49 @@ struct Object *BKE_scene_camera_switch_find(struct Scene *scene); /* DURIAN_CAME
bool BKE_scene_camera_switch_update(struct Scene *scene);
const char *BKE_scene_find_marker_name(const struct Scene *scene, int frame);
+/**
+ * Return the current marker for this frame,
+ * we can have more than 1 marker per frame, this just returns the first (unfortunately).
+ */
const char *BKE_scene_find_last_marker_name(const struct Scene *scene, int frame);
int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int frame);
-/* checks for cycle, returns 1 if it's all OK */
+/**
+ * Checks for cycle, returns true if it's all OK.
+ */
bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce);
+/**
+ * Return fractional frame number taking into account sub-frames and time
+ * remapping. This the time value used by animation, modifiers and physics
+ * evaluation. */
float BKE_scene_ctime_get(const struct Scene *scene);
+/**
+ * Convert integer frame number to fractional frame number taking into account
+ * sub-frames and time remapping.
+ */
float BKE_scene_frame_to_ctime(const struct Scene *scene, const int frame);
+/**
+ * Get current fractional frame based on frame and sub-frame.
+ */
float BKE_scene_frame_get(const struct Scene *scene);
+/**
+ * Set current frame and sub-frame based on a fractional frame.
+ */
void BKE_scene_frame_set(struct Scene *scene, float frame);
struct TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(struct Scene *scene,
int flag);
struct TransformOrientationSlot *BKE_scene_orientation_slot_get(struct Scene *scene,
int slot_index);
+/**
+ * Activate a transform orientation in a 3D view based on an enum value.
+ *
+ * \param orientation: If this is #V3D_ORIENT_CUSTOM or greater, the custom transform orientation
+ * with index \a orientation - #V3D_ORIENT_CUSTOM gets activated.
+ */
void BKE_scene_orientation_slot_set_index(struct TransformOrientationSlot *orient_slot,
int orientation);
int BKE_scene_orientation_slot_get_index(const struct TransformOrientationSlot *orient_slot);
@@ -154,16 +215,29 @@ void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, struct Main *bma
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain);
void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph);
+/**
+ * Applies changes right away, does all sets too.
+ */
void BKE_scene_graph_update_for_newframe_ex(struct Depsgraph *depsgraph, const bool clear_recalc);
+/**
+ * Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
+ *
+ * \warning Sets matching depsgraph as active,
+ * so should only be called from the active editing context (usually, from operators).
+ */
void BKE_scene_view_layer_graph_evaluated_ensure(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Return default view.
+ */
struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
-/* render profile */
+/* Render profile. */
+
int get_render_subsurf_level(const struct RenderData *r, int lvl, bool for_render);
int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render);
@@ -174,8 +248,12 @@ bool BKE_scene_uses_blender_eevee(const struct Scene *scene);
bool BKE_scene_uses_blender_workbench(const struct Scene *scene);
bool BKE_scene_uses_cycles(const struct Scene *scene);
-/* Return whether the Cycles experimental feature is enabled. It is invalid to call without first
- * ensuring that Cycles is the active render engine (e.g. with BKE_scene_uses_cycles). */
+/**
+ * Return whether the Cycles experimental feature is enabled. It is invalid to call without first
+ * ensuring that Cycles is the active render engine (e.g. with #BKE_scene_uses_cycles).
+ *
+ * \note We cannot use `const` as RNA_id_pointer_create is not using a const ID.
+ */
bool BKE_scene_uses_cycles_experimental_features(struct Scene *scene);
void BKE_scene_copy_data_eevee(struct Scene *sce_dst, const struct Scene *sce_src);
@@ -191,13 +269,27 @@ int BKE_render_preview_pixel_size(const struct RenderData *r);
/**********************************/
+/**
+ * Apply the needed correction factor to value, based on unit_type
+ * (only length-related are affected currently) and `unit->scale_length`.
+ */
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
-/* multiview */
+/* Multi-view. */
+
bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd);
+/**
+ * Return whether to render this #SceneRenderView.
+ */
bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd,
const struct SceneRenderView *srv);
+/**
+ * \return true if `viewname` is the first or if the name is NULL or not found.
+ */
bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname);
+/**
+ * \return true if `viewname` is the last or if the name is NULL or not found.
+ */
bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname);
int BKE_scene_multiview_num_views_get(const struct RenderData *rd);
struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd,
@@ -208,6 +300,12 @@ int BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *vie
void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv,
const char *filepath,
char *r_filepath);
+/**
+ * When multi-view is not used the `filepath` is as usual (e.g., `Image.jpg`).
+ * When multi-view is on, even if only one view is enabled the view is incorporated
+ * into the file name (e.g., `Image_L.jpg`). That allows for the user to re-render
+ * individual views.
+ */
void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd,
const char *filepath,
const char *view,
@@ -231,10 +329,14 @@ void BKE_scene_ensure_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_depsgraph_hash(struct Scene *scene);
void BKE_scene_free_view_layer_depsgraph(struct Scene *scene, struct ViewLayer *view_layer);
-/* Do not allocate new depsgraph. */
+/**
+ * \note Do not allocate new depsgraph.
+ */
struct Depsgraph *BKE_scene_get_depsgraph(const struct Scene *scene,
const struct ViewLayer *view_layer);
-/* Allocate new depsgraph if necessary. */
+/**
+ * \note Allocate new depsgraph if necessary.
+ */
struct Depsgraph *BKE_scene_ensure_depsgraph(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
@@ -246,6 +348,10 @@ void BKE_scene_transform_orientation_remove(struct Scene *scene,
struct TransformOrientation *orientation);
struct TransformOrientation *BKE_scene_transform_orientation_find(const struct Scene *scene,
const int index);
+/**
+ * \return the index that \a orientation has within \a scene's transform-orientation list
+ * or -1 if not found.
+ */
int BKE_scene_transform_orientation_get_index(const struct Scene *scene,
const struct TransformOrientation *orientation);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 5c913ed851f..fd0682ee8f0 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -396,7 +396,8 @@ typedef struct Menu {
struct uiLayout *layout; /* runtime for drawing */
} Menu;
-/* spacetypes */
+/* Space-types. */
+
struct SpaceType *BKE_spacetype_from_id(int spaceid);
struct ARegionType *BKE_regiontype_from_id_or_first(const struct SpaceType *st, int regionid);
struct ARegionType *BKE_regiontype_from_id(const struct SpaceType *st, int regionid);
@@ -405,11 +406,26 @@ void BKE_spacetype_register(struct SpaceType *st);
bool BKE_spacetype_exists(int spaceid);
void BKE_spacetypes_free(void); /* only for quitting blender */
-/* spacedata */
+/* Space-data. */
+
void BKE_spacedata_freelist(ListBase *lb);
-void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
+/**
+ * \param lb_dst: should be empty (will be cleared).
+ */
+void BKE_spacedata_copylist(ListBase *lb_dst, ListBase *lb_src);
+
+/**
+ * Facility to set locks for drawing to survive (render) threads accessing drawing data.
+ *
+ * \note Lock can become bit-flag too.
+ * \note Should be replaced in future by better local data handling for threads.
+ */
void BKE_spacedata_draw_locks(bool set);
+/**
+ * Version of #BKE_area_find_region_type that also works if \a slink
+ * is not the active space of \a area.
+ */
struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
const struct ScrArea *area,
int region_type) ATTR_WARN_UNUSED_RESULT
@@ -417,21 +433,42 @@ struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
void BKE_spacedata_callback_id_remap_set(void (*func)(
struct ScrArea *area, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id));
+/**
+ * Currently unused!
+ */
void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id);
-/* area/regions */
+/* Area/regions. */
+
struct ARegion *BKE_area_region_copy(const struct SpaceType *st, const struct ARegion *region);
+/**
+ * Doesn't free the region itself.
+ */
void BKE_area_region_free(struct SpaceType *st, struct ARegion *region);
void BKE_area_region_panels_free(struct ListBase *panels);
+/**
+ * Doesn't free the area itself.
+ */
void BKE_screen_area_free(struct ScrArea *area);
-/* Gizmo-maps of a region need to be freed with the region.
- * Uses callback to avoid low-level call. */
+/**
+ * Gizmo-maps of a region need to be freed with the region.
+ * Uses callback to avoid low-level call.
+ */
void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *));
void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *));
+/**
+ * Find a region of type \a region_type in the currently active space of \a area.
+ *
+ * \note This does _not_ work if the region to look up is not in the active space.
+ * Use #BKE_spacedata_find_region_type if that may be the case.
+ */
struct ARegion *BKE_area_find_region_type(const struct ScrArea *area, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *area);
struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y);
+/**
+ * \note This is only for screen level regions (typically menus/popups).
+ */
struct ARegion *BKE_screen_find_region_xy(struct bScreen *screen,
const int regiontype,
int x,
@@ -442,9 +479,17 @@ struct ARegion *BKE_screen_find_main_region_at_xy(struct bScreen *screen,
const int x,
const int y);
+/**
+ * \note Ideally we can get the area from the context,
+ * there are a few places however where this isn't practical.
+ */
struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen,
struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
+/**
+ * \note Using this function is generally a last resort, you really want to be
+ * using the context when you can - campbell
+ */
struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen,
const int spacetype,
const short min);
@@ -462,15 +507,24 @@ bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSE
ATTR_NONNULL();
bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* zoom factor conversion */
+/* Zoom factor conversion. */
+
float BKE_screen_view3d_zoom_to_fac(float camzoom);
float BKE_screen_view3d_zoom_from_fac(float zoomfac);
void BKE_screen_view3d_shading_init(struct View3DShading *shading);
-/* screen */
+/* Screen. */
+
+/**
+ * Callback used by lib_query to walk over all ID usages
+ * (mimics `foreach_id` callback of #IDTypeInfo structure).
+ */
void BKE_screen_foreach_id_screen_area(struct LibraryForeachIDData *data, struct ScrArea *area);
+/**
+ * Free (or release) any data used by this screen (does not free the screen itself).
+ */
void BKE_screen_free_data(struct bScreen *screen);
void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL();
@@ -486,18 +540,28 @@ void BKE_screen_remove_unused_scrverts(struct bScreen *screen);
void BKE_screen_header_alignment_reset(struct bScreen *screen);
/* .blend file I/O */
+
void BKE_screen_view3d_shading_blend_write(struct BlendWriter *writer,
struct View3DShading *shading);
void BKE_screen_view3d_shading_blend_read_data(struct BlendDataReader *reader,
struct View3DShading *shading);
void BKE_screen_area_map_blend_write(struct BlendWriter *writer, struct ScrAreaMap *area_map);
+/**
+ * \return false on error.
+ */
bool BKE_screen_area_map_blend_read_data(struct BlendDataReader *reader,
struct ScrAreaMap *area_map);
+/**
+ * And as patch for 2.48 and older.
+ */
void BKE_screen_view3d_do_versions_250(struct View3D *v3d, ListBase *regions);
void BKE_screen_area_blend_read_lib(struct BlendLibReader *reader,
struct ID *parent_id,
struct ScrArea *area);
+/**
+ * Cannot use #IDTypeInfo callback yet, because of the return value.
+ */
bool BKE_screen_blend_read_data(struct BlendDataReader *reader, struct bScreen *screen);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
index 8d1fe709355..a82112ff967 100644
--- a/source/blender/blenkernel/BKE_shader_fx.h
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -149,17 +149,34 @@ typedef struct ShaderFxTypeInfo {
#define SHADERFX_TYPE_PANEL_PREFIX "FX_PT_"
-/* Initialize global data (type info and some common global storage). */
+/**
+ * Initialize global data (type info and some common global storage).
+ */
void BKE_shaderfx_init(void);
+/**
+ * Get an effect's panel type, which was defined in the #panelRegister callback.
+ *
+ * \note ShaderFx panel types are assumed to be named with the struct name field concatenated to
+ * the defined prefix.
+ */
void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname);
void BKE_shaderfx_panel_expand(struct ShaderFxData *fx);
const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_new(int type);
void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
void BKE_shaderfx_free(struct ShaderFxData *fx);
+/**
+ * Check unique name.
+ */
bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
bool BKE_shaderfx_depends_ontime(struct ShaderFxData *fx);
+/**
+ * Check whether given shaderfx is not local (i.e. from linked data) when the object is a library
+ * override.
+ *
+ * \param shaderfx: May be NULL, in which case we consider it as a non-local shaderfx case.
+ */
bool BKE_shaderfx_is_nonlocal_in_liboverride(const struct Object *ob,
const struct ShaderFxData *shaderfx);
struct ShaderFxData *BKE_shaderfx_findby_type(struct Object *ob, ShaderFxType type);
@@ -172,6 +189,9 @@ void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx,
void BKE_shaderfx_copy(struct ListBase *dst, const struct ListBase *src);
void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+/**
+ * Check if exist grease pencil effects.
+ */
bool BKE_shaderfx_has_gpencil(const struct Object *ob);
void BKE_shaderfx_blend_write(struct BlendWriter *writer, struct ListBase *fxbase);
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 70aeb37d995..088b270bfed 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -34,11 +34,11 @@ extern "C" {
* Shrinkwrap is composed by a set of functions and options that define the type of shrink.
*
* 3 modes are available:
- * - Nearest vertex
- * - Nearest surface
- * - Normal projection
+ * - Nearest vertex.
+ * - Nearest surface.
+ * - Normal projection.
*
- * ShrinkwrapCalcData encapsulates all needed data for shrinkwrap functions.
+ * #ShrinkwrapCalcData encapsulates all needed data for shrink-wrap functions.
* (So that you don't have to pass an enormous amount of arguments to functions)
*/
@@ -48,6 +48,7 @@ struct Mesh;
struct ModifierEvalContext;
struct Object;
struct ShrinkwrapModifierData;
+struct ShrinkwrapGpencilModifierData;
struct SpaceTransform;
/* Information about boundary edges in the mesh. */
@@ -74,6 +75,9 @@ typedef struct ShrinkwrapBoundaryData {
const ShrinkwrapBoundaryVertData *boundary_verts;
} ShrinkwrapBoundaryData;
+/**
+ * Free boundary data for target project.
+ */
void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh);
void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh);
@@ -89,20 +93,28 @@ typedef struct ShrinkwrapTreeData {
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;
-/* Checks if the modifier needs target normals with these settings. */
+/**
+ * Checks if the modifier needs target normals with these settings.
+ */
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode);
-/* Initializes the mesh data structure from the given mesh and settings. */
+/**
+ * Initializes the mesh data structure from the given mesh and settings.
+ */
bool BKE_shrinkwrap_init_tree(struct ShrinkwrapTreeData *data,
Mesh *mesh,
int shrinkType,
int shrinkMode,
bool force_normals);
-/* Frees the tree data if necessary. */
+/**
+ * Frees the tree data if necessary.
+ */
void BKE_shrinkwrap_free_tree(struct ShrinkwrapTreeData *data);
-/* Implementation of the Shrinkwrap modifier */
+/**
+ * Main shrink-wrap function (implementation of the shrink-wrap modifier).
+ */
void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
const struct ModifierEvalContext *ctx,
struct Scene *scene,
@@ -112,27 +124,44 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
const int defgrp_index,
float (*vertexCos)[3],
int numVerts);
-
-/* Used in editmesh_mask_extract.c to shrinkwrap the extracted mesh to the sculpt */
+/* Implementation of the Shrinkwrap Grease Pencil modifier. */
+void shrinkwrapGpencilModifier_deform(struct ShrinkwrapGpencilModifierData *mmd,
+ struct Object *ob,
+ struct MDeformVert *dvert,
+ const int defgrp_index,
+ float (*vertexCos)[3],
+ int numVerts);
+
+/**
+ * Used in `editmesh_mask_extract.c` to shrink-wrap the extracted mesh to the sculpt.
+ */
void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
struct Object *ob_source,
struct Object *ob_target);
-/* Used in object_remesh.cc to preserve the details and volume in the voxel remesher */
+/**
+ * Used in `object_remesh.cc` to preserve the details and volume in the voxel remesher.
+ */
void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me,
struct Mesh *target_me,
struct Object *ob_target);
-/*
- * This function casts a ray in the given BVHTree.
- * but it takes into consideration the space_transform, that is:
+/**
+ * This function ray-cast a single vertex and updates the hit if the "hit" is considered valid.
*
- * if transf was configured with "SPACE_TRANSFORM_SETUP( &transf, ob1, ob2 )"
- * then the input (vert, dir, BVHTreeRayHit) must be defined in ob1 coordinates space
- * and the BVHTree must be built in ob2 coordinate space.
+ * \param options: Opts control whether an hit is valid or not.
+ * Supported options are:
+ * - #MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
+ * - #MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
*
+ * \param transf: Take into consideration the space_transform, that is:
+ * if `transf` was configured with `SPACE_TRANSFORM_SETUP( &transf, ob1, ob2)`
+ * then the input (vert, dir, #BVHTreeRayHit) must be defined in ob1 coordinates space
+ * and the #BVHTree must be built in ob2 coordinate space.
* Thus it provides an easy way to cast the same ray across several trees
- * (where each tree was built on its own coords space)
+ * (where each tree was built on its own coords space).
+ *
+ * \return true if "hit" was updated.
*/
bool BKE_shrinkwrap_project_normal(char options,
const float vert[3],
@@ -142,14 +171,21 @@ bool BKE_shrinkwrap_project_normal(char options,
struct ShrinkwrapTreeData *tree,
BVHTreeRayHit *hit);
-/* Maps the point to the nearest surface, either by simple nearest,
- * or by target normal projection. */
+/**
+ * Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
+ */
void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
struct BVHTreeNearest *nearest,
float co[3],
int type);
-/* Computes a smooth normal of the target (if applicable) at the hit location. */
+/**
+ * Compute a smooth normal of the target (if applicable) at the hit location.
+ *
+ * \param tree: information about the mesh.
+ * \param transform: transform from the hit coordinate space to the object space; may be null.
+ * \param r_no: output in hit coordinate space; may be shared with inputs.
+ */
void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int looptri_idx,
@@ -157,7 +193,13 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const float hit_no[3],
float r_no[3]);
-/* Apply the shrink to surface modes to the given original coordinates and nearest point. */
+/**
+ * Apply the shrink to surface modes to the given original coordinates and nearest point.
+ *
+ * \param tree: mesh data for smooth normals.
+ * \param transform: transform from the hit coordinate space to the object space; may be null.
+ * \param r_point_co: may be the same memory location as `point_co`, `hit_co`, or `hit_no`.
+ */
void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int mode,
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
index 58dc90f62dc..5d010fa2155 100644
--- a/source/blender/blenkernel/BKE_softbody.h
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -46,16 +46,24 @@ typedef struct BodyPoint {
float springweight;
} BodyPoint;
-/* allocates and initializes general main data */
+/**
+ * Allocates and initializes general main data.
+ */
extern struct SoftBody *sbNew(void);
-/* frees internal data and soft-body itself */
+/**
+ * Frees internal data and soft-body itself.
+ */
extern void sbFree(struct Object *ob);
-/* frees simulation data to reset simulation */
+/**
+ * Frees simulation data to reset simulation.
+ */
extern void sbFreeSimulation(struct SoftBody *sb);
-/* do one simul step, reading and writing vertex locs from given array */
+/**
+ * Do one simulation step, reading and writing vertex locs from given array.
+ * */
extern void sbObjectStep(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -63,13 +71,30 @@ extern void sbObjectStep(struct Depsgraph *depsgraph,
float (*vertexCos)[3],
int numVerts);
-/* makes totally fresh start situation, resets time */
+/**
+ * Makes totally fresh start situation, resets time.
+ */
extern void sbObjectToSoftbody(struct Object *ob);
-/* links the soft-body module to a 'test for Interrupt' function */
-/* pass NULL to unlink again */
+/**
+ * Soft-body global visible functions.
+ * Links the soft-body module to a 'test for Interrupt' function, pass NULL to clear the callback.
+ */
extern void sbSetInterruptCallBack(int (*f)(void));
+/**
+ * A precise position vector denoting the motion of the center of mass give a rotation/scale matrix
+ * using averaging method, that's why estimate and not calculate see: this is kind of reverse
+ * engineering: having to states of a point cloud and recover what happened our advantage here we
+ * know the identity of the vertex there are others methods giving other results.
+ *
+ * \param ob: Any object that can do soft-body e.g. mesh, lattice, curve.
+ * \param lloc: Output of the calculated location (or NULL).
+ * \param lrot: Output of the calculated rotation (or NULL).
+ * \param lscale: Output for the calculated scale (or NULL).
+ *
+ * For velocity & 2nd order stuff see: #vcloud_estimate_transform_v3.
+ */
extern void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3]);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index c332e9a8dac..ebdc4a0ca0b 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -40,7 +40,8 @@ using SplinePtr = std::unique_ptr<Spline>;
/**
* A spline is an abstraction of a single branch-less curve section, its evaluation methods,
* and data. The spline data itself is just control points and a set of attributes by the set
- * of "evaluated" data is often used instead.
+ * of "evaluated" data is often used instead. Conceptually, the derived vs. original data is
+ * an essential distinction. Derived data is usually calculated lazily and cached on the spline.
*
* Any derived class of Spline has to manage two things:
* 1. Interpolating arbitrary attribute data from the control points to evaluated points.
@@ -106,8 +107,17 @@ class Spline {
copy_base_settings(other, *this);
}
+ /**
+ * Return a new spline with the same data, settings, and attributes.
+ */
SplinePtr copy() const;
+ /**
+ * Return a new spline with the same type and settings like "cyclic", but without any data.
+ */
SplinePtr copy_only_settings() const;
+ /**
+ * The same as #copy, but skips copying dynamic attributes to the new spline.
+ */
SplinePtr copy_without_attributes() const;
static void copy_base_settings(const Spline &src, Spline &dst);
@@ -147,8 +157,22 @@ class Spline {
virtual blender::Span<blender::float3> evaluated_positions() const = 0;
+ /**
+ * Return non-owning access to the cache of accumulated lengths along the spline. Each item is
+ * the length of the subsequent segment, i.e. the first value is the length of the first segment
+ * rather than 0. This calculation is rather trivial, and only depends on the evaluated
+ * positions. However, the results are used often, and it is necessarily single threaded, so it
+ * is cached.
+ */
blender::Span<float> evaluated_lengths() const;
+ /**
+ * Return non-owning access to the direction of the curve at each evaluated point.
+ */
blender::Span<blender::float3> evaluated_tangents() const;
+ /**
+ * Return non-owning access to the direction vectors perpendicular to the tangents at every
+ * evaluated point. The method used to generate the normal vectors depends on Spline.normal_mode.
+ */
blender::Span<blender::float3> evaluated_normals() const;
void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
@@ -172,12 +196,32 @@ class Spline {
*/
float factor;
};
+ /**
+ * Find the position on the evaluated spline at the given portion of the total length.
+ * The return value is the indices of the two neighboring points at that location and the
+ * factor between them, which can be used to look up any attribute on the evaluated points.
+ * \note This does not support extrapolation.
+ */
LookupResult lookup_evaluated_factor(const float factor) const;
+ /**
+ * The same as #lookup_evaluated_factor, but looks up a length directly instead of
+ * a portion of the total.
+ */
LookupResult lookup_evaluated_length(const float length) const;
+ /**
+ * Return an array of evenly spaced samples along the length of the spline. The samples are
+ * indices and factors to the next index encoded in floats. The logic for converting from the
+ * float values to interpolation data is in #lookup_data_from_index_factor.
+ */
blender::Array<float> sample_uniform_index_factors(const int samples_size) const;
LookupResult lookup_data_from_index_factor(const float index_factor) const;
+ /**
+ * Sample any input data with a value for each evaluated point (already interpolated to evaluated
+ * points) to arbitrary parameters in between the evaluated points. The interpolation is quite
+ * simple, but this handles the cyclic and end point special cases.
+ */
void sample_with_index_factors(const blender::fn::GVArray &src,
blender::Span<float> index_factors,
blender::fn::GMutableSpan dst) const;
@@ -286,6 +330,9 @@ class BezierSpline final : public Spline {
int resolution() const;
void set_resolution(const int value);
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all points.
+ */
void add_point(const blender::float3 position,
const HandleType handle_type_left,
const blender::float3 handle_position_left,
@@ -321,12 +368,24 @@ class BezierSpline final : public Spline {
* uninitialized memory while auto-generating handles.
*/
blender::MutableSpan<blender::float3> handle_positions_right(bool write_only = false);
+ /**
+ * Recalculate all #Auto and #Vector handles with positions automatically
+ * derived from the neighboring control points.
+ */
void ensure_auto_handles() const;
void translate(const blender::float3 &translation) override;
void transform(const blender::float4x4 &matrix) override;
+ /**
+ * Set positions for the right handle of the control point, ensuring that
+ * aligned handles stay aligned. Has no effect for auto and vector type handles.
+ */
void set_handle_position_right(const int index, const blender::float3 &value);
+ /**
+ * Set positions for the left handle of the control point, ensuring that
+ * aligned handles stay aligned. Has no effect for auto and vector type handles.
+ */
void set_handle_position_left(const int index, const blender::float3 &value);
bool point_is_sharp(const int index) const;
@@ -334,7 +393,22 @@ class BezierSpline final : public Spline {
void mark_cache_invalid() final;
int evaluated_points_size() const final;
+ /**
+ * Returns access to a cache of offsets into the evaluated point array for each control point.
+ * While most control point edges generate the number of edges specified by the resolution,
+ * vector segments only generate one edge.
+ *
+ * \note The length of the result is one greater than the number of points, so that the last item
+ * is the total number of evaluated points. This is useful to avoid recalculating the size of the
+ * last segment everywhere.
+ */
blender::Span<int> control_point_offsets() const;
+ /**
+ * Returns non-owning access to an array of values containing the information necessary to
+ * interpolate values from the original control points to evaluated points. The control point
+ * index is the integer part of each value, and the factor used for interpolating to the next
+ * control point is the remaining factional part.
+ */
blender::Span<float> evaluated_mappings() const;
blender::Span<blender::float3> evaluated_positions() const final;
struct InterpolationData {
@@ -346,6 +420,11 @@ class BezierSpline final : public Spline {
*/
float factor;
};
+ /**
+ * Convert the data encoded in #evaulated_mappings into its parts-- the information necessary
+ * to interpolate data from control points to evaluated points between them. The next control
+ * point index result will not overflow the size of the control point vectors.
+ */
InterpolationData interpolation_data_from_index_factor(const float index_factor) const;
virtual blender::fn::GVArray interpolate_to_evaluated(
@@ -354,6 +433,9 @@ class BezierSpline final : public Spline {
void evaluate_segment(const int index,
const int next_index,
blender::MutableSpan<blender::float3> positions) const;
+ /**
+ * \warning This functional assumes that the spline has more than one point.
+ */
bool segment_is_vector(const int start_index) const;
/** See comment and diagram for #calculate_segment_insertion. */
@@ -364,11 +446,36 @@ class BezierSpline final : public Spline {
blender::float3 right_handle;
blender::float3 handle_next;
};
+ /**
+ * De Casteljau Bezier subdivision.
+ * \param index: The index of the segment's start control point.
+ * \param next_index: The index of the control point at the end of the segment. Could be 0,
+ * if the spline is cyclic.
+ * \param parameter: The factor along the segment, between 0 and 1. Note that this is used
+ * directly by the calculation, it doesn't correspond to a portion of the evaluated length.
+ *
+ * <pre>
+ * handle_prev handle_next
+ * x----------------x
+ * / \
+ * / x---O---x \
+ * / result \
+ * / \
+ * O O
+ * point_prev point_next
+ * </pre>
+ */
InsertResult calculate_segment_insertion(const int index,
const int next_index,
const float parameter);
private:
+ /**
+ * If the spline is not cyclic, the direction for the first and last points is just the
+ * direction formed by the corresponding handles and control points. In the unlikely situation
+ * that the handles define a zero direction, fallback to using the direction defined by the
+ * first and last evaluated segments already calculated in #Spline::evaluated_tangents().
+ */
void correct_end_tangents() const final;
void copy_settings(Spline &dst) const final;
void copy_data(Spline &dst) const final;
@@ -460,6 +567,9 @@ class NURBSpline final : public Spline {
uint8_t order() const;
void set_order(const uint8_t value);
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all points.
+ */
void add_point(const blender::float3 position,
const float radius,
const float tilt,
@@ -498,9 +608,12 @@ class NURBSpline final : public Spline {
};
/**
- * A Poly spline is like a bezier spline with a resolution of one. The main reason to distinguish
+ * A Poly spline is like a Bézier spline with a resolution of one. The main reason to distinguish
* the two is for reduced complexity and increased performance, since interpolating data to control
* points does not change it.
+ *
+ * Poly spline code is very simple, since it doesn't do anything that the base #Spline doesn't
+ * handle. Mostly it just worries about storing the data used by the base class.
*/
class PolySpline final : public Spline {
blender::Vector<blender::float3> positions_;
@@ -521,6 +634,9 @@ class PolySpline final : public Spline {
int size() const final;
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all points.
+ */
void add_point(const blender::float3 position, const float radius, const float tilt);
void resize(const int size) final;
@@ -536,6 +652,12 @@ class PolySpline final : public Spline {
blender::Span<blender::float3> evaluated_positions() const final;
+ /**
+ * Poly spline interpolation from control points to evaluated points is a special case, since
+ * the result data is the same as the input data. This function returns a #GVArray that points to
+ * the original data. Therefore the lifetime of the returned virtual array must not be longer
+ * than the source data.
+ */
blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
protected:
@@ -546,8 +668,12 @@ class PolySpline final : public Spline {
};
/**
- * A #CurveEval corresponds to the #Curve object data. The name is different for clarity, since
- * more of the data is stored in the splines, but also just to be different than the name in DNA.
+ * A collection of #Spline objects with the same attribute types and names. Most data and
+ * functionality is in splines, but this contains some helpers for working with them as a group.
+ *
+ * \note A #CurveEval corresponds to the #Curve object data. The name is different for clarity,
+ * since more of the data is stored in the splines, but also just to be different than the name in
+ * DNA.
*/
struct CurveEval {
private:
@@ -566,22 +692,56 @@ struct CurveEval {
blender::Span<SplinePtr> splines() const;
blender::MutableSpan<SplinePtr> splines();
+ /**
+ * \return True if the curve contains a spline with the given type.
+ *
+ * \note If you are looping over all of the splines in the same scope anyway,
+ * it's better to avoid calling this function, in case there are many splines.
+ */
bool has_spline_with_type(const Spline::Type type) const;
void resize(const int size);
+ /**
+ * \warning Call #reallocate on the spline's attributes after adding all splines.
+ */
void add_spline(SplinePtr spline);
+ void add_splines(blender::MutableSpan<SplinePtr> splines);
void remove_splines(blender::IndexMask mask);
void translate(const blender::float3 &translation);
void transform(const blender::float4x4 &matrix);
void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
+ /**
+ * Return the start indices for each of the curve spline's control points, if they were part
+ * of a flattened array. This can be used to facilitate parallelism by avoiding the need to
+ * accumulate an offset while doing more complex calculations.
+ *
+ * \note The result is one longer than the spline count; the last element is the total size.
+ */
blender::Array<int> control_point_offsets() const;
+ /**
+ * Exactly like #control_point_offsets, but uses the number of evaluated points instead.
+ */
blender::Array<int> evaluated_point_offsets() const;
+ /**
+ * Return the accumulated length at the start of every spline in the curve.
+ * \note The result is one longer than the spline count; the last element is the total length.
+ */
blender::Array<float> accumulated_spline_lengths() const;
+ float total_length() const;
+ int total_control_point_size() const;
+
void mark_cache_invalid();
+ /**
+ * Check the invariants that curve control point attributes should always uphold, necessary
+ * because attributes are stored on splines rather than in a flat array on the curve:
+ * - The same set of attributes exists on every spline.
+ * - Attributes with the same name have the same type on every spline.
+ * - Attributes are in the same order on every spline.
+ */
void assert_valid_point_attributes() const;
};
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index 59b1c2b28d9..792186dd260 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -143,6 +143,8 @@ typedef struct StudioLight {
void *free_function_data;
} StudioLight;
+/* API */
+
void BKE_studiolight_init(void);
void BKE_studiolight_free(void);
void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3]);
@@ -151,12 +153,18 @@ struct StudioLight *BKE_studiolight_findindex(int index, int flag);
struct StudioLight *BKE_studiolight_find_default(int flag);
void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type);
struct ListBase *BKE_studiolight_listbase(void);
+/**
+ * Ensure state of studio-lights.
+ */
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag);
void BKE_studiolight_refresh(void);
StudioLight *BKE_studiolight_load(const char *path, int type);
StudioLight *BKE_studiolight_create(const char *path,
const SolidLight light[4],
const float light_ambient[3]);
+/**
+ * Only useful for workbench while editing the user-preferences.
+ */
StudioLight *BKE_studiolight_studio_edit_get(void);
void BKE_studiolight_remove(StudioLight *sl);
void BKE_studiolight_set_free_function(StudioLight *sl,
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 3816a822279..db57076082c 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -66,18 +66,30 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
void subsurf_calculate_limit_positions(struct Mesh *me, float (*r_positions)[3]);
-/* get gridsize from 'level', level must be greater than zero */
+/**
+ * Get grid-size from 'level', level must be greater than zero.
+ */
int BKE_ccg_gridsize(int level);
-/* x/y grid coordinates at 'low_level' can be multiplied by the result
- * of this function to convert to grid coordinates at 'high_level' */
+/**
+ * X/Y grid coordinates at 'low_level' can be multiplied by the result
+ * of this function to convert to grid coordinates at 'high_level'.
+ */
int BKE_ccg_factor(int low_level, int high_level);
+/**
+ * Translate #GridHidden into the #ME_HIDE flag for MVerts. Assumes
+ * vertices are in the order output by #ccgDM_copyFinalVertArray.
+ */
void subsurf_copy_grid_hidden(struct DerivedMesh *dm,
const struct MPoly *mpoly,
struct MVert *mvert,
const struct MDisps *mdisps);
+/**
+ * Translate #GridPaintMask into vertex paint masks. Assumes vertices
+ * are in the order output by #ccgDM_copyFinalVertArray.
+ */
void subsurf_copy_grid_paint_mask(struct DerivedMesh *dm,
const struct MPoly *mpoly,
float *paint_mask,
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index c7120c60020..a979ba6d2cc 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -30,17 +30,44 @@ struct Main;
struct Text;
struct TextLine;
+/**
+ * \note caller must handle `compiled` member.
+ */
void BKE_text_free_lines(struct Text *text);
struct Text *BKE_text_add(struct Main *bmain, const char *name);
+/**
+ * Use to a valid UTF-8 sequences.
+ * this function replaces extended ascii characters.
+ */
int txt_extended_ascii_as_utf8(char **str);
bool BKE_text_reload(struct Text *text);
+/**
+ * Load a text file.
+ *
+ * \param is_internal: If \a true, this text data-block only exists in memory,
+ * not as a file on disk.
+ *
+ * \note text data-blocks have no real user but have 'fake user' enabled by default
+ */
struct Text *BKE_text_load_ex(struct Main *bmain,
const char *file,
const char *relpath,
const bool is_internal);
+/**
+ * Load a text file.
+ *
+ * \note Text data-blocks have no user by default, only the 'real user' flag.
+ */
struct Text *BKE_text_load(struct Main *bmain, const char *file, const char *relpath);
void BKE_text_clear(struct Text *text);
void BKE_text_write(struct Text *text, const char *str);
+/**
+ * \return codes:
+ * - 0 if file on disk is the same or Text is in memory only.
+ * - 1 if file has been modified on disk since last local edit.
+ * - 2 if file on disk has been deleted.
+ * - -1 is returned if an error occurs.
+ */
int BKE_text_file_modified_check(struct Text *text);
void BKE_text_file_modified_ignore(struct Text *text);
@@ -61,12 +88,20 @@ void txt_move_eof(struct Text *text, const bool sel);
void txt_move_bol(struct Text *text, const bool sel);
void txt_move_eol(struct Text *text, const bool sel);
void txt_move_toline(struct Text *text, unsigned int line, const bool sel);
+/**
+ * Moves to a certain byte in a line, not a certain utf8-character.
+ */
void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, const bool sel);
void txt_pop_sel(struct Text *text);
void txt_delete_char(struct Text *text);
void txt_delete_word(struct Text *text);
void txt_delete_selected(struct Text *text);
void txt_sel_all(struct Text *text);
+/**
+ * Reverse of #txt_pop_sel
+ * Clears the selection and ensures the cursor is located
+ * at the selection (where the cursor is visually while editing).
+ */
void txt_sel_clear(struct Text *text);
void txt_sel_line(struct Text *text);
void txt_sel_set(struct Text *text, int startl, int startc, int endl, int endc);
@@ -91,7 +126,9 @@ bool txt_cursor_is_line_end(const struct Text *text);
int txt_calc_tab_left(struct TextLine *tl, int ch);
int txt_calc_tab_right(struct TextLine *tl, int ch);
-/* Utility functions, could be moved somewhere more generic but are python/text related. */
+/**
+ * Utility functions, could be moved somewhere more generic but are python/text related.
+ */
int text_check_bracket(const char ch);
bool text_check_delim(const char ch);
bool text_check_digit(const char ch);
@@ -100,7 +137,7 @@ bool text_check_identifier_nodigit(const char ch);
bool text_check_whitespace(const char ch);
int text_find_identifier_start(const char *str, int i);
-/* defined in bpy_interface.c */
+/* EVIL: defined in `bpy_interface.c`. */
extern int text_check_identifier_unicode(const unsigned int ch);
extern int text_check_identifier_nodigit_unicode(const unsigned int ch);
@@ -110,7 +147,14 @@ enum {
};
/* Fast non-validating buffer conversion for undo. */
+
+/**
+ * Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it.
+ */
char *txt_to_buf_for_undo(struct Text *text, int *r_buf_len);
+/**
+ * Decode a buffer from #txt_to_buf_for_undo.
+ */
void txt_from_buf_for_undo(struct Text *text, const char *buf, int buf_len);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index ef322d0cd31..380b5cf035c 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -42,6 +42,9 @@ struct TexResult;
/** #ColorBand.data length. */
#define MAXCOLORBAND 32
+/**
+ * Utility for all IDs using those texture slots.
+ */
void BKE_texture_mtex_foreach_id(struct LibraryForeachIDData *data, struct MTex *mtex);
void BKE_texture_default(struct Tex *tex);
@@ -50,6 +53,9 @@ void BKE_texture_type_set(struct Tex *tex, int type);
void BKE_texture_mtex_default(struct MTex *mtex);
struct MTex *BKE_texture_mtex_add(void);
+/**
+ * Slot -1 for first free ID.
+ */
struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot);
/* UNUSED */
// void autotexname(struct Tex *tex);
@@ -79,6 +85,9 @@ struct PointDensity *BKE_texture_pointdensity_add(void);
struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag);
bool BKE_texture_dependsOnTime(const struct Tex *texture);
+/**
+ * \returns true if this texture can use its #Texture.ima (even if its NULL).
+ */
bool BKE_texture_is_image_user(const struct Tex *tex);
void BKE_texture_get_value_ex(const struct Scene *scene,
@@ -94,6 +103,9 @@ void BKE_texture_get_value(const struct Scene *scene,
struct TexResult *texres,
bool use_color_management);
+/**
+ * Make sure all images used by texture are loaded into pool.
+ */
void BKE_texture_fetch_images_for_pool(struct Tex *texture, struct ImagePool *pool);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 47145a7d6bd..9caf5d31765 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -46,20 +46,53 @@ struct rcti;
/* **** Common functions **** */
+/**
+ * Free tracking structure, only frees structure contents
+ * (if structure is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside structure becomes invalid after this call.
+ */
void BKE_tracking_free(struct MovieTracking *tracking);
+/**
+ * Copy tracking structure content.
+ */
void BKE_tracking_copy(struct MovieTracking *tracking_dst,
const struct MovieTracking *tracking_src,
const int flag);
+/**
+ * Initialize motion tracking settings to default values,
+ * used when new movie clip data-block is created.
+ */
void BKE_tracking_settings_init(struct MovieTracking *tracking);
+/**
+ * Get list base of active object's tracks.
+ */
struct ListBase *BKE_tracking_get_active_tracks(struct MovieTracking *tracking);
+/**
+ * Get list base of active object's plane tracks.
+ */
struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *tracking);
+/**
+ * Get reconstruction data of active object.
+ */
struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(
struct MovieTracking *tracking);
-/* matrices for constraints and drawing */
+/* Matrices for constraints and drawing. */
+
+/**
+ * Get transformation matrix for a given object which is used
+ * for parenting motion tracker reconstruction to 3D world.
+ */
void BKE_tracking_get_camera_object_matrix(struct Object *camera_object, float mat[4][4]);
+/**
+ * Get projection matrix for camera specified by given tracking object
+ * and frame number.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
int framenr,
@@ -68,16 +101,45 @@ void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking,
float mat[4][4]);
/* **** Clipboard **** */
+/**
+ * Free clipboard by freeing memory used by all tracks in it.
+ */
void BKE_tracking_clipboard_free(void);
+/**
+ * Copy selected tracks from specified object to the clipboard.
+ */
void BKE_tracking_clipboard_copy_tracks(struct MovieTracking *tracking,
struct MovieTrackingObject *object);
+/**
+ * Check whether there are any tracks in the clipboard.
+ */
bool BKE_tracking_clipboard_has_tracks(void);
+/**
+ * Paste tracks from clipboard to specified object.
+ *
+ * Names of new tracks in object are guaranteed to be unique here.
+ */
void BKE_tracking_clipboard_paste_tracks(struct MovieTracking *tracking,
struct MovieTrackingObject *object);
/* **** Track **** */
+
+/**
+ * Add new empty track to the given list of tracks.
+ *
+ * It is required that caller will append at least one marker to avoid degenerate tracks.
+ */
struct MovieTrackingTrack *BKE_tracking_track_add_empty(struct MovieTracking *tracking,
struct ListBase *tracks_list);
+/**
+ * Add new track to a specified tracks base.
+ *
+ * Coordinates are expected to be in normalized 0..1 space,
+ * frame number is expected to be in clip space.
+ *
+ * Width and height are clip's dimension used to scale track's
+ * pattern and search regions.
+ */
struct MovieTrackingTrack *BKE_tracking_track_add(struct MovieTracking *tracking,
struct ListBase *tracksbase,
float x,
@@ -85,14 +147,35 @@ struct MovieTrackingTrack *BKE_tracking_track_add(struct MovieTracking *tracking
int framenr,
int width,
int height);
+/**
+ * Duplicate the specified track, result will no belong to any list.
+ */
struct MovieTrackingTrack *BKE_tracking_track_duplicate(struct MovieTrackingTrack *track);
+/**
+ * Ensure specified track has got unique name,
+ * if it's not name of specified track will be changed
+ * keeping names of all other tracks unchanged.
+ */
void BKE_tracking_track_unique_name(struct ListBase *tracksbase, struct MovieTrackingTrack *track);
+/**
+ * Free specified track, only frees contents of a structure
+ * (if track is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside track becomes invalid after this call.
+ */
void BKE_tracking_track_free(struct MovieTrackingTrack *track);
+/**
+ * Get frame numbers of the very first and last markers.
+ * There is no check on whether the marker is enabled or not.
+ */
void BKE_tracking_track_first_last_frame_get(const struct MovieTrackingTrack *track,
int *r_first_frame,
int *r_last_frame);
+/**
+ * Find the minimum starting frame and maximum ending frame within given set of tracks.
+ */
void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ struct MovieTrackingTrack **tracks,
const int num_tracks,
int *r_first_frame,
@@ -101,17 +184,50 @@ void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ struct MovieTrackingT
int BKE_tracking_count_selected_tracks_in_list(const struct ListBase *tracks_list);
int BKE_tracking_count_selected_tracks_in_active_object(/*const*/ struct MovieTracking *tracking);
-/* Get array of selected tracks from the current active object in the tracking structure.
- * If nothing is selected then the result is nullptr and `r_num_tracks` is set to 0. */
+/**
+ * Get array of selected tracks from the current active object in the tracking structure.
+ * If nothing is selected then the result is nullptr and `r_num_tracks` is set to 0.
+ */
struct MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(
struct MovieTracking *tracking, int *r_num_tracks);
+/**
+ * Set flag for all specified track's areas.
+ *
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ * \param flag: flag to be set for areas.
+ */
void BKE_tracking_track_flag_set(struct MovieTrackingTrack *track, int area, int flag);
+/**
+ * Clear flag from all specified track's areas.
+ *
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ * \param flag: flag to be cleared for areas.
+ */
void BKE_tracking_track_flag_clear(struct MovieTrackingTrack *track, int area, int flag);
+/**
+ * Check whether track has got marker at specified frame.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
bool BKE_tracking_track_has_marker_at_frame(struct MovieTrackingTrack *track, int framenr);
+/**
+ * Check whether track has got enabled marker at specified frame.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr);
+/**
+ * Clear track's path:
+ *
+ * - If action is #TRACK_CLEAR_REMAINED path from `ref_frame+1` up to end will be clear.
+ * - If action is #TRACK_CLEAR_UPTO path from the beginning up to `ref_frame-1` will be clear.
+ * - If action is #TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
+ *
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_track_path_clear(struct MovieTrackingTrack *track, int ref_frame, int action);
void BKE_tracking_tracks_join(struct MovieTracking *tracking,
@@ -140,7 +256,11 @@ float BKE_tracking_track_get_weight_for_marker(struct MovieClip *clip,
struct MovieTrackingTrack *track,
struct MovieTrackingMarker *marker);
-/* selection */
+/* Selection */
+
+/**
+ * \param area: which part of marker should be selected. see TRACK_AREA_* constants.
+ */
void BKE_tracking_track_select(struct ListBase *tracksbase,
struct MovieTrackingTrack *track,
int area,
@@ -155,19 +275,31 @@ void BKE_tracking_marker_delete(struct MovieTrackingTrack *track, int framenr);
void BKE_tracking_marker_clamp(struct MovieTrackingMarker *marker, int event);
+/**
+ * Get marker closest to the given frame number.
+ *
+ * If there is maker with exact frame number it returned.
+ * Otherwise, marker with highest frame number but lower than the requested
+ * frame is returned if such marker exists. Otherwise, the marker with lowest
+ * frame number greater than the requested frame number is returned.
+ *
+ * This function has complexity of `O(log number_of_markers)`.
+ */
struct MovieTrackingMarker *BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr);
struct MovieTrackingMarker *BKE_tracking_marker_get_exact(struct MovieTrackingTrack *track,
int framenr);
struct MovieTrackingMarker *BKE_tracking_marker_ensure(struct MovieTrackingTrack *track,
int framenr);
-/* Get marker position, possibly interpolating gap between key-framed/tracked markers.
+/**
+ * Get marker position, possibly interpolating gap between key-framed/tracked markers.
*
* The result marker frame number is set to the requested frame number. Its flags are 0 if the
* marker is interpolated, and is set to original marker flag if there were no interpolation
* involved.
*
- * Returns truth if the result is usable. */
+ * \returns truth if the result is usable.
+ */
bool BKE_tracking_marker_get_interpolated(struct MovieTrackingTrack *track,
const int framenr,
struct MovieTrackingMarker *r_marker);
@@ -181,12 +313,21 @@ void BKE_tracking_marker_get_subframe_position(struct MovieTrackingTrack *track,
float pos[2]);
/* **** Plane Track **** */
+/**
+ * Creates new plane track out of selected point tracks.
+ */
struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(struct MovieTracking *tracking,
struct ListBase *plane_tracks_base,
struct ListBase *tracks,
int framenr);
void BKE_tracking_plane_track_unique_name(struct ListBase *plane_tracks_base,
struct MovieTrackingPlaneTrack *plane_track);
+/**
+ * Free specified plane track, only frees contents of a structure
+ * (if track is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside track becomes invalid after this call.
+ */
void BKE_tracking_plane_track_free(struct MovieTrackingPlaneTrack *plane_track);
bool BKE_tracking_plane_track_has_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track,
@@ -222,10 +363,21 @@ struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(
struct MovieTrackingPlaneTrack *plane_track, struct MovieTrackingPlaneMarker *plane_marker);
void BKE_tracking_plane_marker_delete(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Get a plane marker at given frame,
+ * If there's no such marker, closest one from the left side will be returned.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Get a plane marker at exact given frame, if there's no marker at the frame,
+ * NULL will be returned.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
+/**
+ * Ensure there's a marker for the given frame.
+ */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(
struct MovieTrackingPlaneTrack *plane_track, int framenr);
void BKE_tracking_plane_marker_get_subframe_corners(struct MovieTrackingPlaneTrack *plane_track,
@@ -255,6 +407,9 @@ struct MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(
struct MovieTracking *tracking, struct MovieTrackingObject *object);
/* **** Camera **** */
+/**
+ * Converts principal offset from center to offset of blender's camera.
+ */
void BKE_tracking_camera_shift_get(
struct MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty);
void BKE_tracking_camera_to_blender(struct MovieTracking *tracking,
@@ -346,10 +501,21 @@ struct ImBuf *BKE_tracking_get_search_imbuf(struct ImBuf *ibuf,
bool anchored,
bool disable_channels);
+/**
+ * Zap channels from the imbuf that are disabled by the user. this can lead to
+ * better tracks sometimes. however, instead of simply zeroing the channels
+ * out, do a partial gray-scale conversion so the display is better.
+ */
void BKE_tracking_disable_channels(
struct ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale);
/* **** 2D tracking **** */
+
+/**
+ * Refine marker's position using previously known keyframe.
+ * Direction of searching for a keyframe depends on backwards flag,
+ * which means if backwards is false, previous keyframe will be as reference.
+ */
void BKE_tracking_refine_marker(struct MovieClip *clip,
struct MovieTrackingTrack *track,
struct MovieTrackingMarker *marker,
@@ -368,6 +534,9 @@ void BKE_autotrack_context_free(struct AutoTrackContext *context);
/* **** Plane tracking **** */
+/**
+ * \note frame number should be in clip space, not scene space.
+ */
void BKE_tracking_track_plane_from_existing_motion(struct MovieTrackingPlaneTrack *plane_track,
int start_frame);
void BKE_tracking_retrack_plane_from_existing_motion_at_segment(
@@ -377,11 +546,20 @@ void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners
float H[3][3]);
/* **** Camera solving **** */
+
+/**
+ * Perform early check on whether everything is fine to start reconstruction.
+ */
bool BKE_tracking_reconstruction_check(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
char *error_msg,
int error_size);
+/**
+ * Create context for camera/object motion reconstruction.
+ * Copies all data needed for reconstruction from movie clip datablock,
+ * so editing this clip is safe during reconstruction job is in progress.
+ */
struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(
struct MovieClip *clip,
struct MovieTrackingObject *object,
@@ -389,13 +567,29 @@ struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(
int keyframe2,
int width,
int height);
+/**
+ * Free memory used by a reconstruction process.
+ */
void BKE_tracking_reconstruction_context_free(struct MovieReconstructContext *context);
+/**
+ * Solve camera/object motion and reconstruct 3D markers position
+ * from a prepared reconstruction context.
+ *
+ * stop is not actually used at this moment, so reconstruction
+ * job could not be stopped.
+ *
+ * do_update, progress and stat_message are set by reconstruction
+ * callback in libmv side and passing to an interface.
+ */
void BKE_tracking_reconstruction_solve(struct MovieReconstructContext *context,
short *stop,
short *do_update,
float *progress,
char *stats_message,
int message_size);
+/**
+ * Finish reconstruction process by copying reconstructed data to an actual movie clip data-block.
+ */
bool BKE_tracking_reconstruction_finish(struct MovieReconstructContext *context,
struct MovieTracking *tracking);
@@ -405,9 +599,16 @@ void BKE_tracking_reconstruction_report_error_message(struct MovieReconstructCon
const char *BKE_tracking_reconstruction_error_message_get(
const struct MovieReconstructContext *context);
+/**
+ * Apply scale on all reconstructed cameras and bundles, used by camera scale apply operator.
+ */
void BKE_tracking_reconstruction_scale(struct MovieTracking *tracking, float scale[3]);
/* **** Feature detection **** */
+
+/**
+ * Detect features using FAST detector.
+ */
void BKE_tracking_detect_fast(struct MovieTracking *tracking,
struct ListBase *tracksbase,
struct ImBuf *ibuf,
@@ -418,6 +619,9 @@ void BKE_tracking_detect_fast(struct MovieTracking *tracking,
struct bGPDlayer *layer,
bool place_outside_layer);
+/**
+ * Detect features using Harris detector.
+ */
void BKE_tracking_detect_harris(struct MovieTracking *tracking,
struct ListBase *tracksbase,
struct ImBuf *ibuf,
@@ -429,6 +633,24 @@ void BKE_tracking_detect_harris(struct MovieTracking *tracking,
bool place_outside_layer);
/* **** 2D stabilization **** */
+
+/**
+ * Get stabilization data (translation, scaling and angle) for a given frame.
+ * Returned data describes how to compensate the detected movement, but with any
+ * chosen scale factor already applied and any target frame position already compensated.
+ * In case stabilization fails or is disabled, neutral values are returned.
+ *
+ * \param framenr: is a frame number, relative to the clip (not relative to the scene timeline).
+ * \param width: is an effective width of the canvas (square pixels), used to scale the
+ * determined translation.
+ *
+ * Outputs:
+ * \param translation: of the lateral shift, absolute canvas coordinates (square pixels).
+ * \param scale: of the scaling to apply.
+ * \param angle: of the rotation angle, relative to the frame center.
+ *
+ * TODO(sergey): Use `r_` prefix for output parameters here.
+ */
void BKE_tracking_stabilization_data_get(struct MovieClip *clip,
int framenr,
int width,
@@ -436,12 +658,30 @@ void BKE_tracking_stabilization_data_get(struct MovieClip *clip,
float translation[2],
float *scale,
float *angle);
+/**
+ * Stabilize given image buffer using stabilization data for a specified frame number.
+ *
+ * \note frame number should be in clip space, not scene space.
+ *
+ * TODO(sergey): Use `r_` prefix for output parameters here.
+ */
struct ImBuf *BKE_tracking_stabilize_frame(struct MovieClip *clip,
int framenr,
struct ImBuf *ibuf,
float translation[2],
float *scale,
float *angle);
+/**
+ * Build a 4x4 transformation matrix based on the given 2D stabilization data.
+ * mat is a 4x4 matrix in homogeneous coordinates, adapted to the
+ * final image buffer size and compensated for pixel aspect ratio,
+ * ready for direct OpenGL drawing.
+ *
+ * TODO(sergey): The signature of this function should be changed. we actually
+ * don't need the dimensions of the image buffer. Instead we
+ * should consider to provide the pivot point of the rotation as a
+ * further stabilization data parameter.
+ */
void BKE_tracking_stabilization_data_to_mat4(int width,
int height,
float aspect,
@@ -450,17 +690,30 @@ void BKE_tracking_stabilization_data_to_mat4(int width,
float angle,
float mat[4][4]);
-/* Dopesheet */
+/* Dope-sheet */
+
+/**
+ * Tag dope-sheet for update, actual update will happen later when it'll be actually needed.
+ */
void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking);
+/**
+ * Do dope-sheet update, if update is not needed nothing will happen.
+ */
void BKE_tracking_dopesheet_update(struct MovieTracking *tracking);
/* **** Query/search **** */
+/**
+ * \note Returns NULL if the track comes from camera object,.
+ */
struct MovieTrackingObject *BKE_tracking_find_object_for_track(
const struct MovieTracking *tracking, const struct MovieTrackingTrack *track);
struct ListBase *BKE_tracking_find_tracks_list_for_track(struct MovieTracking *tracking,
const struct MovieTrackingTrack *track);
+/**
+ * \note Returns NULL if the track comes from camera object,.
+ */
struct MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
const struct MovieTracking *tracking, const struct MovieTrackingPlaneTrack *plane_track);
struct ListBase *BKE_tracking_find_tracks_list_for_plane_track(
diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/blenkernel/BKE_type_conversions.hh
index c8b24fd1260..ebfb13cd08f 100644
--- a/source/blender/nodes/NOD_type_conversions.hh
+++ b/source/blender/blenkernel/BKE_type_conversions.hh
@@ -18,7 +18,7 @@
#include "FN_multi_function.hh"
-namespace blender::nodes {
+namespace blender::bke {
using fn::CPPType;
@@ -72,6 +72,8 @@ class DataTypeConversions {
const void *from_value,
void *to_value) const;
+ void convert_to_initialized_n(fn::GSpan from_span, fn::GMutableSpan to_span) const;
+
fn::GVArray try_convert(fn::GVArray varray, const CPPType &to_type) const;
fn::GVMutableArray try_convert(fn::GVMutableArray varray, const CPPType &to_type) const;
@@ -79,4 +81,4 @@ class DataTypeConversions {
const DataTypeConversions &get_implicit_type_conversions();
-} // namespace blender::nodes
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index 2a90211f8e0..6e1f9468ce4 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -171,7 +171,12 @@ typedef enum eUndoTypeFlags {
UNDOTYPE_FLAG_DECODE_ACTIVE_STEP = 1 << 1,
} eUndoTypeFlags;
-/* Expose since we need to perform operations on specific undo types (rarely). */
+/* -------------------------------------------------------------------- */
+/** \name Public Undo Types
+ *
+ * Expose since we need to perform operations on specific undo types (rarely).
+ * \{ */
+
extern const UndoType *BKE_UNDOSYS_TYPE_IMAGE;
extern const UndoType *BKE_UNDOSYS_TYPE_MEMFILE;
extern const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE;
@@ -179,17 +184,25 @@ extern const UndoType *BKE_UNDOSYS_TYPE_PARTICLE;
extern const UndoType *BKE_UNDOSYS_TYPE_SCULPT;
extern const UndoType *BKE_UNDOSYS_TYPE_TEXT;
+/** \} */
+
#define BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(ty) ELEM(ty, BKE_UNDOSYS_TYPE_IMAGE)
UndoStack *BKE_undosys_stack_create(void);
void BKE_undosys_stack_destroy(UndoStack *ustack);
void BKE_undosys_stack_clear(UndoStack *ustack);
void BKE_undosys_stack_clear_active(UndoStack *ustack);
+/* name optional */
bool BKE_undosys_stack_has_undo(const UndoStack *ustack, const char *name);
void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain);
+/* called after 'BKE_undosys_stack_init_from_main' */
void BKE_undosys_stack_init_from_context(UndoStack *ustack, struct bContext *C);
UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut);
UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut);
+/**
+ * \param steps: Limit the number of undo steps.
+ * \param memory_limit: Limit the amount of memory used by the undo stack.
+ */
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit);
#define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack) \
BKE_undosys_stack_limit_steps_and_memory(ustack, U.undosteps, (size_t)U.undomemory * 1024 * 1024)
@@ -197,13 +210,18 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
void BKE_undosys_stack_group_begin(UndoStack *ustack);
void BKE_undosys_stack_group_end(UndoStack *ustack);
-/* Only some UndoType's require init. */
+/**
+ * Only some UndoType's require init.
+ */
UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
struct bContext *C,
const char *name,
const UndoType *ut);
UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, struct bContext *C, const char *name);
+/**
+ * \param C: Can be NULL from some callers if their encoding function doesn't need it
+ */
eUndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
struct bContext *C,
const char *name,
@@ -216,40 +234,117 @@ UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack,
UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut);
UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name);
+/**
+ * Return direction of the undo/redo from `us_reference` (or `ustack->step_active` if NULL), and
+ * `us_target`.
+ *
+ * \note If `us_reference` and `us_target` are the same, we consider this is an undo.
+ *
+ * \return -1 for undo, 1 for redo, 0 in case of error.
+ */
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack,
const UndoStep *us_target,
const UndoStep *us_reference);
+/**
+ * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target`
+ * will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **beyond** the given one
+ * (if the given one has to be skipped).
+ *
+ * \param us_reference: If NULL, will be set to current active step in the undo stack. Otherwise,
+ * it is assumed to match the current state, and will be used as basis for the undo/redo process
+ * (i.e. all steps in-between `us_reference` and `us_target` will be processed).
+ */
bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us_target,
UndoStep *us_reference,
const bool use_skip);
+/**
+ * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
+ */
bool BKE_undosys_step_load_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
+/**
+ * Undo/Redo until the step matching given `index` in the undo stack becomes the active
+ * (currently loaded) one.
+ */
void BKE_undosys_step_load_from_index(UndoStack *ustack, struct bContext *C, const int index);
+/**
+ * Undo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \warning This function assumes that the given target step is _before_ current active one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true,
+ * `us_target` will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **before** the given one
+ * (if the given one has to be skipped).
+ */
bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us,
bool use_skip);
+/**
+ * Undo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note See #BKE_undosys_step_undo_with_data_ex for details.
+ */
bool BKE_undosys_step_undo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
+/**
+ * Undo one step from current active (currently loaded) one.
+ */
bool BKE_undosys_step_undo(UndoStack *ustack, struct bContext *C);
+/**
+ * Redo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \warning This function assumes that the given target step is _after_ current active one.
+ *
+ * \note Unless `us_target` is a 'skipped' one and `use_skip` is true,
+ * `us_target` will become the active step.
+ *
+ * \note In case `use_skip` is true, the final target will always be **after** the given one
+ * (if the given one has to be skipped).
+ */
bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us,
bool use_skip);
+/**
+ * Redo until `us_target` step becomes the active (currently loaded) one.
+ *
+ * \note See #BKE_undosys_step_redo_with_data_ex for details.
+ */
bool BKE_undosys_step_redo_with_data(UndoStack *ustack, struct bContext *C, UndoStep *us_target);
+/**
+ * Redo one step from current active one.
+ */
bool BKE_undosys_step_redo(UndoStack *ustack, struct bContext *C);
+/**
+ * Useful when we want to diff against previous undo data but can't be sure the types match.
+ */
UndoStep *BKE_undosys_step_same_type_next(UndoStep *us);
+/**
+ * Useful when we want to diff against previous undo data but can't be sure the types match.
+ */
UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us);
-/* Type System */
+/* Type System. */
+
+/**
+ * Similar to #WM_operatortype_append
+ */
UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *));
void BKE_undosys_type_free_all(void);
-/* ID Accessor */
+/* ID Accessor. */
+
#if 0 /* functionality is only used internally for now. */
void BKE_undosys_foreach_ID_ref(UndoStack *ustack,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index b28215a72d1..505cfee3adf 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -26,9 +26,11 @@ extern "C" {
struct UnitSettings;
-/* in all cases the value is assumed to be scaled by the user preference */
+/* In all cases the value is assumed to be scaled by the user-preference. */
-/* humanly readable representation of a value in units (used for button drawing) */
+/**
+ * Humanly readable representation of a value in units (used for button drawing).
+ */
size_t BKE_unit_value_as_string_adaptive(
char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
size_t BKE_unit_value_as_string(char *str,
@@ -39,29 +41,59 @@ size_t BKE_unit_value_as_string(char *str,
const struct UnitSettings *settings,
bool pad);
-/* replace units with values, used before python button evaluation */
+/**
+ * Replace units with values, used before python button evaluation.
+ *
+ * Make a copy of the string that replaces the units with numbers.
+ * This is only used when evaluating user input and can afford to be a bit slower
+ *
+ * This is to be used before python evaluation so:
+ * `10.1km -> 10.1*1000.0`
+ * ...will be resolved by Python.
+ *
+ * Values will be split by an add sign:
+ * `5'2" -> 5*0.3048 + 2*0.0254`
+ *
+ * \param str_prev: is optional, when valid it is used to get a base unit when none is set.
+ *
+ * \return True of a change was made.
+ */
bool BKE_unit_replace_string(
char *str, int len_max, const char *str_prev, double scale_pref, int system, int type);
-/* return true if the string contains any valid unit for the given type */
+/**
+ * \return true if the string contains any valid unit for the given type.
+ */
bool BKE_unit_string_contains_unit(const char *str, int type);
-/* If user does not specify a unit, this converts it to the unit from the settings. */
+/**
+ * If user does not specify a unit, this converts it to the unit from the settings.
+ */
double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int type, double value);
-/* make string keyboard-friendly: 10µm --> 10um */
+/**
+ * Make string keyboard-friendly, e.g: `10µm -> 10um`.
+ */
void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type);
-/* the size of the unit used for this value (used for calculating the ckickstep) */
+/**
+ * The size of the unit used for this value (used for calculating the click-step).
+ */
double BKE_unit_closest_scalar(double value, int system, int type);
-/* base scale for these units */
+/**
+ * Base scale for these units.
+ */
double BKE_unit_base_scalar(int system, int type);
-/* return true is the unit system exists */
+/**
+ * \return true is the unit system exists.
+ */
bool BKE_unit_is_valid(int system, int type);
-/* loop over scales, could add names later */
+/**
+ * Loop over scales, could add names later.
+ */
// double bUnit_Iter(void **unit, char **name, int system, int type);
void BKE_unit_system_get(int system, int type, const void **r_usys_pt, int *r_len);
@@ -73,7 +105,7 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index);
double BKE_unit_scalar_get(const void *usys_pt, int index);
bool BKE_unit_is_suppressed(const void *usys_pt, int index);
-/* aligned with PropertyUnit */
+/** Aligned with #PropertyUnit. */
enum {
B_UNIT_NONE = 0,
B_UNIT_LENGTH = 1,
diff --git a/source/blender/blenkernel/BKE_vfont.h b/source/blender/blenkernel/BKE_vfont.h
index 827ae1b6a0f..cd1b30b9358 100644
--- a/source/blender/blenkernel/BKE_vfont.h
+++ b/source/blender/blenkernel/BKE_vfont.h
@@ -84,6 +84,9 @@ bool BKE_vfont_to_curve_ex(struct Object *ob,
bool *r_text_free,
struct CharTrans **r_chartransdata);
bool BKE_vfont_to_curve_nubase(struct Object *ob, int mode, struct ListBase *r_nubase);
+/**
+ * \warning Expects to have access to evaluated data (i.e. passed object should be evaluated one).
+ */
bool BKE_vfont_to_curve(struct Object *ob, int mode);
void BKE_vfont_build_char(struct Curve *cu,
struct ListBase *nubase,
diff --git a/source/blender/blenkernel/BKE_vfontdata.h b/source/blender/blenkernel/BKE_vfontdata.h
index b6e57dad934..692857b0458 100644
--- a/source/blender/blenkernel/BKE_vfontdata.h
+++ b/source/blender/blenkernel/BKE_vfontdata.h
@@ -49,6 +49,12 @@ typedef struct VChar {
float width;
} VChar;
+/**
+ * Construct a new #VFontData structure from free-type font data in `pf`.
+ *
+ * \param pf: The font data.
+ * \retval A new #VFontData structure, or NULL if unable to load.
+ */
VFontData *BKE_vfontdata_from_freetypefont(struct PackedFile *pf);
VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, const int flag);
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 601e0cf26a9..f4f00844b8d 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -88,6 +88,7 @@ const char *BKE_volume_grids_frame_filepath(const struct Volume *volume);
const VolumeGrid *BKE_volume_grid_get_for_read(const struct Volume *volume, int grid_index);
VolumeGrid *BKE_volume_grid_get_for_write(struct Volume *volume, int grid_index);
const VolumeGrid *BKE_volume_grid_active_get_for_read(const struct Volume *volume);
+/* Tries to find a grid with the given name. Make sure that the volume has been loaded. */
const VolumeGrid *BKE_volume_grid_find_for_read(const struct Volume *volume, const char *name);
/* Grid
@@ -115,9 +116,13 @@ void BKE_volume_grid_unload(const struct Volume *volume, const struct VolumeGrid
bool BKE_volume_grid_is_loaded(const struct VolumeGrid *grid);
/* Metadata */
+
const char *BKE_volume_grid_name(const struct VolumeGrid *grid);
VolumeGridType BKE_volume_grid_type(const struct VolumeGrid *grid);
int BKE_volume_grid_channels(const struct VolumeGrid *grid);
+/**
+ * Transformation from index space to object space.
+ */
void BKE_volume_grid_transform_matrix(const struct VolumeGrid *grid, float mat[4][4]);
/* Volume Editing
diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh
index 9532da8c23c..dd8ae7ea554 100644
--- a/source/blender/blenkernel/BKE_volume_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#pragma once
+
#include "BLI_span.hh"
#include "DNA_modifier_types.h"
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
index 82a4e5fe08e..ff4e21732c4 100644
--- a/source/blender/blenkernel/BKE_workspace.h
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -31,9 +31,17 @@ struct bScreen;
struct bToolRef;
/* -------------------------------------------------------------------- */
-/* Create, delete, init */
+/** \name Create, Delete, Initialize
+ * \{ */
struct WorkSpace *BKE_workspace_add(struct Main *bmain, const char *name);
+/**
+ * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
+ * calls #workspace_free_data (through #BKE_id_free) to free the workspace data, and frees
+ * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
+ *
+ * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
+ */
void BKE_workspace_remove(struct Main *bmain, struct WorkSpace *workspace);
struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Main *bmain,
@@ -41,6 +49,9 @@ struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Ma
void BKE_workspace_instance_hook_free(const struct Main *bmain,
struct WorkSpaceInstanceHook *hook);
+/**
+ * Add a new layout to \a workspace for \a screen.
+ */
struct WorkSpaceLayout *BKE_workspace_layout_add(struct Main *bmain,
struct WorkSpace *workspace,
struct bScreen *screen,
@@ -51,17 +62,36 @@ void BKE_workspace_layout_remove(struct Main *bmain,
void BKE_workspace_relations_free(ListBase *relation_list);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* General Utils */
+/** \name General Utilities
+ * \{ */
struct WorkSpaceLayout *BKE_workspace_layout_find(const struct WorkSpace *workspace,
const struct bScreen *screen)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Find the layout for \a screen without knowing which workspace to look in.
+ * Can also be used to find the workspace that contains \a screen.
+ *
+ * \param r_workspace: Optionally return the workspace that contains the
+ * looked up layout (if found).
+ */
struct WorkSpaceLayout *BKE_workspace_layout_find_global(const struct Main *bmain,
const struct bScreen *screen,
struct WorkSpace **r_workspace)
ATTR_NONNULL(1, 2);
+/**
+ * Circular workspace layout iterator.
+ *
+ * \param callback: Custom function which gets executed for each layout.
+ * Can return false to stop iterating.
+ * \param arg: Custom data passed to each \a callback call.
+ *
+ * \return the layout at which \a callback returned false.
+ */
struct WorkSpaceLayout *BKE_workspace_layout_iter_circular(
const struct WorkSpace *workspace,
struct WorkSpaceLayout *start,
@@ -72,8 +102,11 @@ struct WorkSpaceLayout *BKE_workspace_layout_iter_circular(
void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tref)
ATTR_NONNULL(1, 2);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Getters/Setters */
+/** \name Getters/Setters
+ * \{ */
#define GETTER_ATTRS ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
#define SETTER_ATTRS ATTR_NONNULL(1)
@@ -81,8 +114,23 @@ void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tre
struct WorkSpace *BKE_workspace_active_get(struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook,
struct WorkSpace *workspace) SETTER_ATTRS;
+/**
+ * Get the layout that is active for \a hook (which is the visible layout for the active workspace
+ * in \a hook).
+ */
struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
+/**
+ * \brief Activate a layout
+ *
+ * Sets \a layout as active for \a workspace when activated through or already active in \a hook.
+ * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of
+ * \a hook too. See #BKE_workspace_active_set().
+ *
+ * \a workspace does not need to be active for this.
+ *
+ * #WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer.
+ */
void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook,
const int winid,
struct WorkSpace *workspace,
@@ -100,6 +148,9 @@ void BKE_workspace_layout_name_set(struct WorkSpace *workspace,
const char *new_name) ATTR_NONNULL();
struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
+/**
+ * Get the layout to be activated should \a workspace become or be the active workspace in \a hook.
+ */
struct WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(
const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS;
@@ -111,6 +162,8 @@ void BKE_workspace_id_tag_all_visible(struct Main *bmain, int tag) ATTR_NONNULL(
#undef GETTER_ATTRS
#undef SETTER_ATTRS
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index 97f998cc1c1..d2a5100ffad 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -64,6 +64,10 @@ typedef struct bMovieHandle {
} bMovieHandle;
bMovieHandle *BKE_movie_handle_get(const char imtype);
+
+/**
+ * \note Similar to #BKE_image_path_from_imformat()
+ */
void BKE_movie_filepath_get(char *string,
const struct RenderData *rd,
bool preview,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index b2418d0539c..f6e7f1c2473 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -100,6 +100,7 @@ set(SRC
intern/blender_undo.c
intern/blender_user_menu.c
intern/blendfile.c
+ intern/blendfile_link_append.c
intern/boids.c
intern/bpath.c
intern/brush.c
@@ -117,7 +118,7 @@ set(SRC
intern/context.c
intern/crazyspace.c
intern/cryptomatte.cc
- intern/curve.c
+ intern/curve.cc
intern/curve_bevel.c
intern/curve_convert.c
intern/curve_decimate.c
@@ -138,7 +139,6 @@ set(SRC
intern/editmesh_cache.c
intern/editmesh_tangent.c
intern/effect.c
- intern/extern_implementations.cc
intern/fcurve.c
intern/fcurve_cache.c
intern/fcurve_driver.c
@@ -164,7 +164,7 @@ set(SRC
intern/idtype.c
intern/image.c
intern/image_gen.c
- intern/image_gpu.c
+ intern/image_gpu.cc
intern/image_save.c
intern/ipo.c
intern/kelvinlet.c
@@ -226,6 +226,7 @@ set(SRC
intern/multires_versioning.c
intern/nla.c
intern/node.cc
+ intern/type_conversions.cc
intern/object.cc
intern/object_deform.c
intern/object_dupli.cc
@@ -326,6 +327,7 @@ set(SRC
BKE_blender_user_menu.h
BKE_blender_version.h
BKE_blendfile.h
+ BKE_blendfile_link_append.h
BKE_boids.h
BKE_bpath.h
BKE_brush.h
@@ -455,6 +457,7 @@ set(SRC
BKE_text_suggestions.h
BKE_texture.h
BKE_tracking.h
+ BKE_type_conversions.hh
BKE_undo_system.h
BKE_unit.h
BKE_vfont.h
@@ -806,6 +809,7 @@ if(WITH_GTESTS)
intern/asset_library_service_test.cc
intern/asset_library_test.cc
intern/asset_test.cc
+ intern/bpath_test.cc
intern/cryptomatte_test.cc
intern/fcurve_test.cc
intern/lattice_deform_test.cc
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 67e7b890548..74f848ac580 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -939,7 +939,6 @@ void ccgSubSurf__effectedFaceNeighbors(CCGSubSurf *ss,
*numEdges = numE;
}
-/* copy face grid coordinates to other places */
CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
@@ -986,7 +985,6 @@ CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF
return eCCGError_None;
}
-/* copy other places to face grid coordinates */
CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
@@ -1035,8 +1033,6 @@ CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF,
return eCCGError_None;
}
-/* stitch together face grids, averaging coordinates at edges
- * and vertices, for multires displacements */
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index a9e0d6882c1..9349c33d72a 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -100,13 +100,30 @@ CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL);
CCGError ccgSubSurf_processSync(CCGSubSurf *ss);
+/**
+ * Copy face grid coordinates to other places.
+ */
CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss,
int lvl,
CCGFace **effectedF,
int numEffectedF);
+/**
+ * Copy other places to face grid coordinates.
+ */
CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
+/**
+ * Update normals for specified faces.
+ */
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF);
+/**
+ * Compute subdivision levels from a given starting point, used by multi-res subdivide/propagate,
+ * by filling in coordinates at a certain level, and then subdividing that up to the highest level.
+ */
CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
+/**
+ * Stitch together face grids, averaging coordinates at edges and vertices, for multi-res
+ * displacements.
+ */
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF);
CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels);
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
index 99ea1fb9607..e19e01ec034 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
@@ -1309,7 +1309,6 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss)
/* ** Public API exposed to other areas which depends on old CCG code. ** */
-/* Update normals for specified faces. */
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
@@ -1344,9 +1343,6 @@ CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEf
return eCCGError_None;
}
-/* compute subdivision levels from a given starting point, used by
- * multires subdivide/propagate, by filling in coordinates at a
- * certain level, and then subdividing that up to the highest level */
CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
CCGVert **effectedV;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index ced9076bbfd..6c9c5490ca0 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -295,10 +295,6 @@ static CustomData *dm_getPolyCData(DerivedMesh *dm)
return &dm->polyData;
}
-/**
- * Utility function to initialize a DerivedMesh's function pointers to
- * the default implementation (for those functions which have a default)
- */
void DM_init_funcs(DerivedMesh *dm)
{
/* default function implementations */
@@ -335,11 +331,6 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getLoopDataArray = DM_get_loop_data_layer;
}
-/**
- * Utility function to initialize a DerivedMesh for the desired number
- * of vertices, edges and faces (doesn't allocate memory for them, just
- * sets up the custom data layers)
- */
void DM_init(DerivedMesh *dm,
DerivedMeshType type,
int numVerts,
@@ -368,10 +359,6 @@ void DM_init(DerivedMesh *dm,
copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
}
-/**
- * Utility function to initialize a DerivedMesh for the desired number
- * of vertices, edges and faces, with a layer setup copied from source
- */
void DM_from_template_ex(DerivedMesh *dm,
DerivedMesh *source,
DerivedMeshType type,
@@ -485,12 +472,6 @@ void DM_ensure_normals(DerivedMesh *dm)
BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
}
-/**
- * Ensure the array is large enough
- *
- * \note This function must always be thread-protected by caller.
- * It should only be used by internal code.
- */
void DM_ensure_looptri_data(DerivedMesh *dm)
{
const unsigned int totpoly = dm->numPolyData;
@@ -519,11 +500,11 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
}
}
-/** Utility function to convert an (evaluated) Mesh to a shape key block. */
-/* Just a shallow wrapper around BKE_keyblock_convert_from_mesh,
- * that ensures both evaluated mesh and original one has same number of vertices. */
void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
{
+ /* Just a shallow wrapper around #BKE_keyblock_convert_from_mesh,
+ * that ensures both evaluated mesh and original one has same number of vertices. */
+
const int totvert = me_deformed->totvert;
if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
@@ -533,11 +514,6 @@ void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
}
-/**
- * set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
- * zero for the layer type, so only layer types specified by the mask
- * will be copied
- */
void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask)
{
CustomData_set_only_copy(&dm->vertData, mask->vmask);
@@ -658,11 +634,6 @@ void DM_copy_vert_data(
CustomData_copy_data(&source->vertData, &dest->vertData, source_index, dest_index, count);
}
-/**
- * interpolates vertex data from the vertices indexed by src_indices in the
- * source mesh using the given weights and stores the result in the vertex
- * indexed by dest_index in the dest mesh
- */
void DM_interp_vert_data(DerivedMesh *source,
DerivedMesh *dest,
int *src_indices,
@@ -2097,12 +2068,10 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, true, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, true, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph,
@@ -2111,12 +2080,10 @@ Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph,
const CustomData_MeshMasks *dataMask,
int index)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, true, false, dataMask, index, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, true, false, dataMask, index, false, false, nullptr, &result, nullptr);
+ return result;
}
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
@@ -2124,12 +2091,10 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
@@ -2137,12 +2102,10 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
-
+ Mesh *result;
mesh_calc_modifiers(
- depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &final, nullptr);
-
- return final;
+ depsgraph, scene, ob, false, false, dataMask, -1, false, false, nullptr, &result, nullptr);
+ return result;
}
/***/
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 2cc1cba99cd..ddba726ba83 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -289,7 +289,7 @@ static void action_blend_read_expand(BlendExpander *expander, ID *id)
static IDProperty *action_asset_type_property(const bAction *action)
{
- const bool is_single_frame = !BKE_action_has_single_frame(action);
+ const bool is_single_frame = BKE_action_has_single_frame(action);
IDPropertyTemplate idprop = {0};
idprop.i = is_single_frame;
@@ -320,6 +320,7 @@ IDTypeInfo IDType_ID_AC = {
.name_plural = "actions",
.translation_context = BLT_I18NCONTEXT_ID_ACTION,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = &AssetType_AC,
.init_data = NULL,
.copy_data = action_copy_data,
@@ -327,6 +328,7 @@ IDTypeInfo IDType_ID_AC = {
.make_local = NULL,
.foreach_id = action_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = action_blend_write,
@@ -337,8 +339,6 @@ IDTypeInfo IDType_ID_AC = {
.blend_read_undo_preserve = NULL,
.lib_override_apply_post = NULL,
-
- .asset_type_info = &AssetType_AC,
};
/* ***************** Library data level operations on action ************** */
@@ -356,7 +356,6 @@ bAction *BKE_action_add(Main *bmain, const char name[])
/* *************** Action Groups *************** */
-/* Get the active action-group for an Action */
bActionGroup *get_active_actiongroup(bAction *act)
{
bActionGroup *agrp = NULL;
@@ -372,7 +371,6 @@ bActionGroup *get_active_actiongroup(bAction *act)
return agrp;
}
-/* Make the given Action-Group the active one */
void set_active_action_group(bAction *act, bActionGroup *agrp, short select)
{
bActionGroup *grp;
@@ -393,7 +391,6 @@ void set_active_action_group(bAction *act, bActionGroup *agrp, short select)
}
}
-/* Sync colors used for action/bone group with theme settings */
void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
{
/* Only do color copying if using a custom color (i.e. not default color). */
@@ -424,7 +421,6 @@ void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
}
}
-/* Add a new action group with the given name to the action */
bActionGroup *action_groups_add_new(bAction *act, const char name[])
{
bActionGroup *agrp;
@@ -450,10 +446,6 @@ bActionGroup *action_groups_add_new(bAction *act, const char name[])
return agrp;
}
-/* Add given channel into (active) group
- * - assumes that channel is not linked to anything anymore
- * - always adds at the end of the group
- */
void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
{
/* sanity checks */
@@ -522,10 +514,6 @@ void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
fcurve->grp = agrp;
}
-/* Reconstruct group channel pointers.
- * Assumes that the groups referred to by the FCurves are already in act->groups.
- * Reorders the main channel list to match group order.
- */
void BKE_action_groups_reconstruct(bAction *act)
{
/* Sanity check. */
@@ -565,7 +553,6 @@ void BKE_action_groups_reconstruct(bAction *act)
BLI_movelisttolist(&act->curves, &ungrouped);
}
-/* Remove the given channel from all groups */
void action_groups_remove_channel(bAction *act, FCurve *fcu)
{
/* sanity checks */
@@ -606,7 +593,6 @@ void action_groups_remove_channel(bAction *act, FCurve *fcu)
BLI_remlink(&act->curves, fcu);
}
-/* Find a group with the given name */
bActionGroup *BKE_action_group_find_name(bAction *act, const char name[])
{
/* sanity checks */
@@ -618,7 +604,6 @@ bActionGroup *BKE_action_group_find_name(bAction *act, const char name[])
return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name));
}
-/* Clear all 'temp' flags on all groups */
void action_groups_clear_tempflags(bAction *act)
{
bActionGroup *agrp;
@@ -641,10 +626,6 @@ void BKE_pose_channel_session_uuid_generate(bPoseChannel *pchan)
pchan->runtime.session_uuid = BLI_session_uuid_generate();
}
-/**
- * Return a pointer to the pose channel of the given name
- * from this pose.
- */
bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
{
if (ELEM(NULL, pose, name) || (name[0] == '\0')) {
@@ -658,14 +639,6 @@ bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
return BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
}
-/**
- * Looks to see if the channel with the given name
- * already exists in this pose - if not a new one is
- * allocated and initialized.
- *
- * \note Use with care, not on Armature poses but for temporal ones.
- * \note (currently used for action constraints and in rebuild_pose).
- */
bPoseChannel *BKE_pose_channel_ensure(bPose *pose, const char *name)
{
bPoseChannel *chan;
@@ -732,12 +705,6 @@ bool BKE_pose_channels_is_valid(const bPose *pose)
#endif
-/**
- * Find the active pose-channel for an object
- * (we can't just use pose, as layer info is in armature)
- *
- * \note #Object, not #bPose is used here, as we need layer info from Armature.
- */
bPoseChannel *BKE_pose_channel_active(Object *ob)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -757,15 +724,6 @@ bPoseChannel *BKE_pose_channel_active(Object *ob)
return NULL;
}
-/**
- * Use this when detecting the "other selected bone",
- * when we have multiple armatures in pose mode.
- *
- * In this case the active-selected is an obvious choice when finding the target for a
- * constraint for eg. however from the users perspective the active pose bone of the
- * active object is the _real_ active bone, so any other non-active selected bone
- * is a candidate for being the other selected bone, see: T58447.
- */
bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -789,9 +747,6 @@ bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
return NULL;
}
-/**
- * \see #ED_armature_ebone_get_mirrored (edit-mode, matching function)
- */
bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name)
{
char name_flip[MAXBONENAME];
@@ -818,12 +773,6 @@ const char *BKE_pose_ikparam_get_name(bPose *pose)
return NULL;
}
-/**
- * Allocate a new pose on the heap, and copy the src pose and its channels
- * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
- *
- * \param dst: Should be freed already, makes entire duplicate.
- */
void BKE_pose_copy_data_ex(bPose **dst,
const bPose *src,
const int flag,
@@ -975,10 +924,6 @@ bool BKE_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
return pose_channel_in_IK_chain(ob, pchan, 0);
}
-/**
- * Removes the hash for quick lookup of channels, must
- * be done when adding/removing channels.
- */
void BKE_pose_channels_hash_ensure(bPose *pose)
{
if (!pose->chanhash) {
@@ -1014,9 +959,6 @@ static void pose_channels_remove_internal_links(Object *ob, bPoseChannel *unlink
}
}
-/**
- * Selectively remove pose channels.
- */
void BKE_pose_channels_remove(Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data),
void *user_data)
@@ -1086,10 +1028,6 @@ void BKE_pose_channels_remove(Object *ob,
}
}
-/**
- * Deallocates a pose channel.
- * Does not free the pose channel itself.
- */
void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
{
if (pchan->custom) {
@@ -1118,13 +1056,11 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
BKE_pose_channel_runtime_free(&pchan->runtime);
}
-/** Clears the runtime cache of a pose channel without free. */
void BKE_pose_channel_runtime_reset(bPoseChannel_Runtime *runtime)
{
memset(runtime, 0, sizeof(*runtime));
}
-/* Reset all non-persistent fields. */
void BKE_pose_channel_runtime_reset_on_copy(bPoseChannel_Runtime *runtime)
{
const SessionUUID uuid = runtime->session_uuid;
@@ -1132,13 +1068,11 @@ void BKE_pose_channel_runtime_reset_on_copy(bPoseChannel_Runtime *runtime)
runtime->session_uuid = uuid;
}
-/** Deallocates runtime cache of a pose channel */
void BKE_pose_channel_runtime_free(bPoseChannel_Runtime *runtime)
{
BKE_pose_channel_free_bbone_cache(runtime);
}
-/** Deallocates runtime cache of a pose channel's B-Bone shape. */
void BKE_pose_channel_free_bbone_cache(bPoseChannel_Runtime *runtime)
{
runtime->bbone_segments = 0;
@@ -1153,10 +1087,6 @@ void BKE_pose_channel_free(bPoseChannel *pchan)
BKE_pose_channel_free_ex(pchan, true);
}
-/**
- * Removes and deallocates all channels from a pose.
- * Does not free the pose itself.
- */
void BKE_pose_channels_free_ex(bPose *pose, bool do_id_user)
{
bPoseChannel *pchan;
@@ -1203,9 +1133,6 @@ void BKE_pose_free_data(bPose *pose)
BKE_pose_free_data_ex(pose, true);
}
-/**
- * Removes and deallocates all data from a pose, and also frees the pose.
- */
void BKE_pose_free_ex(bPose *pose, bool do_id_user)
{
if (pose) {
@@ -1220,13 +1147,6 @@ void BKE_pose_free(bPose *pose)
BKE_pose_free_ex(pose, true);
}
-/**
- * Copy the internal members of each pose channel including constraints
- * and ID-Props, used when duplicating bones in editmode.
- * (unlike copy_pose_channel_data which only does posing-related stuff).
- *
- * \note use when copying bones in editmode (on returned value from #BKE_pose_channel_ensure)
- */
void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_from)
{
/* copy transform locks */
@@ -1276,10 +1196,6 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->drawflag = pchan_from->drawflag;
}
-/* checks for IK constraint, Spline IK, and also for Follow-Path constraint.
- * can do more constraints flags later
- */
-/* pose should be entirely OK */
void BKE_pose_update_constraint_flags(bPose *pose)
{
bPoseChannel *pchan, *parchan;
@@ -1354,7 +1270,6 @@ void BKE_pose_tag_update_constraint_flags(bPose *pose)
/* ************************** Bone Groups ************************** */
-/* Adds a new bone-group (name may be NULL) */
bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
{
bActionGroup *grp;
@@ -1373,8 +1288,6 @@ bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
return grp;
}
-/* Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
- * index might be invalid ( < 1), in which case it will be find from grp. */
void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
{
bPoseChannel *pchan;
@@ -1413,7 +1326,6 @@ void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
}
}
-/* Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)) */
void BKE_pose_remove_group_index(bPose *pose, const int index)
{
bActionGroup *grp = NULL;
@@ -1427,7 +1339,6 @@ void BKE_pose_remove_group_index(bPose *pose, const int index)
/* ************** F-Curve Utilities for Actions ****************** */
-/* Check if the given action has any keyframes */
bool action_has_motion(const bAction *act)
{
FCurve *fcu;
@@ -1486,7 +1397,6 @@ bool BKE_action_has_single_frame(const struct bAction *act)
return found_key;
}
-/* Calculate the extents of given action */
void calc_action_range(const bAction *act, float *start, float *end, short incl_modifiers)
{
FCurve *fcu;
@@ -1574,9 +1484,27 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
}
}
-/* Return flags indicating which transforms the given object/posechannel has
- * - if 'curves' is provided, a list of links to these curves are also returned
- */
+void BKE_action_get_frame_range(const struct bAction *act, float *r_start, float *r_end)
+{
+ if (act && (act->flag & ACT_FRAME_RANGE)) {
+ *r_start = act->frame_start;
+ *r_end = act->frame_end;
+ }
+ else {
+ calc_action_range(act, r_start, r_end, false);
+ }
+
+ /* Ensure that action is at least 1 frame long (for NLA strips to have a valid length). */
+ if (*r_start >= *r_end) {
+ *r_end = *r_start + 1.0f;
+ }
+}
+
+bool BKE_action_is_cyclic(const struct bAction *act)
+{
+ return act && (act->flag & ACT_FRAME_RANGE) && (act->flag & ACT_CYCLIC);
+}
+
short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan, ListBase *curves)
{
PointerRNA ptr;
@@ -1707,9 +1635,6 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
/* ************** Pose Management Tools ****************** */
-/**
- * Zero the pose transforms for the entire pose or only for selected bones.
- */
void BKE_pose_rest(bPose *pose, bool selected_bones_only)
{
bPoseChannel *pchan;
@@ -1774,7 +1699,6 @@ void BKE_pose_copy_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchan
pchanto->protectflag = pchanfrom->protectflag;
}
-/* both poses should be in sync */
bool BKE_pose_copy_result(bPose *to, bPose *from)
{
bPoseChannel *pchanto, *pchanfrom;
@@ -1799,7 +1723,6 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
return true;
}
-/* Tag pose for recalc. Also tag all related data to be recalc. */
void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
{
pose->flag |= POSE_RECALC;
@@ -1809,9 +1732,6 @@ void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
DEG_relations_tag_update(bmain);
}
-/* For the calculation of the effects of an Action at the given frame on an object
- * This is currently only used for the Action Constraint
- */
void what_does_obaction(Object *ob,
Object *workob,
bPose *pose,
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index 21887d514d9..d93d5c456d8 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -69,7 +69,6 @@ static CLG_LogRef LOG = {"bke.anim_sys"};
/* Getter/Setter -------------------------------------------- */
-/* Check if ID can have AnimData */
bool id_type_can_have_animdata(const short id_type)
{
const IDTypeInfo *typeinfo = BKE_idtype_get_info_from_idcode(id_type);
@@ -89,9 +88,6 @@ bool id_can_have_animdata(const ID *id)
return id_type_can_have_animdata(GS(id->name));
}
-/**
- * Get #AnimData from the given ID-block.
- */
AnimData *BKE_animdata_from_id(ID *id)
{
/* In order for this to work, we assume that the #AnimData pointer is stored
@@ -106,9 +102,6 @@ AnimData *BKE_animdata_from_id(ID *id)
return NULL;
}
-/**
- * Ensure #AnimData exists in the given ID-block (when supported).
- */
AnimData *BKE_animdata_ensure_id(ID *id)
{
/* In order for this to work, we assume that the #AnimData pointer is stored
@@ -137,16 +130,6 @@ AnimData *BKE_animdata_ensure_id(ID *id)
/* Action Setter --------------------------------------- */
-/**
- * Called when user tries to change the active action of an #AnimData block
- * (via RNA, Outliner, etc.)
- *
- * \param reports: Can be NULL.
- * \param id: The owner of the animation data
- * \param act: The Action to set, or NULL to clear.
- *
- * \return true when the action was successfully updated, false otherwise.
- */
bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
{
AnimData *adt = BKE_animdata_from_id(id);
@@ -226,7 +209,6 @@ bool BKE_animdata_action_ensure_idroot(const ID *owner, bAction *action)
/* Freeing -------------------------------------------- */
-/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
void BKE_animdata_free(ID *id, const bool do_id_user)
{
/* Only some ID-blocks have this info for now, so we cast the
@@ -287,10 +269,6 @@ bool BKE_animdata_id_is_animated(const struct ID *id)
!BLI_listbase_is_empty(&adt->overrides);
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
{
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
@@ -309,12 +287,6 @@ void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
/* Copying -------------------------------------------- */
-/**
- * Make a copy of the given AnimData - to be used when copying data-blocks.
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return The copied animdata.
- */
AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
{
AnimData *dadt;
@@ -367,11 +339,6 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
return dadt;
}
-/**
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return true is successfully copied.
- */
bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
{
AnimData *adt;
@@ -432,7 +399,6 @@ void BKE_animdata_duplicate_id_action(struct Main *bmain,
}
}
-/* Merge copies of the data from the src AnimData into the destination AnimData */
void BKE_animdata_merge_copy(
Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
{
@@ -647,12 +613,6 @@ static void animdata_move_drivers_by_basepath(AnimData *srcAdt,
}
}
-/* Transfer the animation data from srcID to dstID where the srcID
- * animation data is based off "basepath", creating new AnimData and
- * associated data as necessary.
- *
- * basepaths is a list of AnimationBasePathChange.
- */
void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
{
AnimData *srcAdt = NULL, *dstAdt = NULL;
@@ -716,17 +676,6 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
}
}
-/**
- * Temporary wrapper for driver operators for buttons to make it easier to create
- * such drivers by rerouting all paths through the active object instead so that
- * they will get picked up by the dependency system.
- *
- * \param C: Context pointer - for getting active data
- * \param[in,out] ptr: RNA pointer for property's data-block.
- * May be modified as result of path remapping.
- * \param prop: RNA definition of property to add for
- * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
- */
char *BKE_animdata_driver_path_hack(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -956,14 +905,6 @@ static bool nlastrips_path_rename_fix(ID *owner_id,
/* Rename Sub-ID Entities in RNA Paths ----------------------- */
-/* Fix up the given RNA-Path
- *
- * This is just an external wrapper for the RNA-Path fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
char *old_path,
const char *prefix,
@@ -1019,14 +960,6 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
return result;
}
-/* Fix all RNA_Paths in the given Action, relative to the given ID block
- *
- * This is just an external wrapper for the F-Curve fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_action_fix_paths_rename(ID *owner_id,
bAction *act,
const char *prefix,
@@ -1070,10 +1003,6 @@ void BKE_action_fix_paths_rename(ID *owner_id,
MEM_freeN(newN);
}
-/* Fix all RNA-Paths in the AnimData block used by the given ID block
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_animdata_fix_paths_rename(ID *owner_id,
AnimData *adt,
ID *ref_id,
@@ -1282,7 +1211,6 @@ void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
}
}
-/* apply the given callback function on all F-Curves attached to data in main database */
void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_data)
{
/* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
@@ -1294,7 +1222,6 @@ void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_d
/* Whole Database Ops -------------------------------------------- */
-/* apply the given callback function on all data in main database */
void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
{
ID *id;
@@ -1405,10 +1332,6 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
ANIMDATA_IDS_CB(bmain->simulations.first);
}
-/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
void BKE_animdata_fix_paths_rename_all(ID *ref_id,
const char *prefix,
const char *oldName,
@@ -1418,11 +1341,6 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id,
BKE_animdata_fix_paths_rename_all_ex(bmain, ref_id, prefix, oldName, newName, 0, 0, 1);
}
-/* Fix all RNA-Paths throughout the database
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-/* TODO: use BKE_animdata_main_cb for looping over all data. */
void BKE_animdata_fix_paths_rename_all_ex(Main *bmain,
ID *ref_id,
const char *prefix,
@@ -1432,6 +1350,7 @@ void BKE_animdata_fix_paths_rename_all_ex(Main *bmain,
const int newSubscript,
const bool verify_paths)
{
+ /* TODO: use BKE_animdata_main_cb for looping over all data. */
ID *id;
diff --git a/source/blender/blenkernel/intern/anim_path.c b/source/blender/blenkernel/intern/anim_path.c
index de470a15041..43af55e9b6b 100644
--- a/source/blender/blenkernel/intern/anim_path.c
+++ b/source/blender/blenkernel/intern/anim_path.c
@@ -230,14 +230,6 @@ static bool binary_search_anim_path(const float *accum_len_arr,
}
}
-/**
- * Calculate the deformation implied by the curve path at a given parametric position,
- * and returns whether this operation succeeded.
- *
- * \param ctime: Time is normalized range <0-1>.
- *
- * \return success.
- */
bool BKE_where_on_path(const Object *ob,
float ctime,
float r_vec[4],
@@ -254,6 +246,10 @@ bool BKE_where_on_path(const Object *ob,
CLOG_WARN(&LOG, "No curve cache!");
return false;
}
+ if (ob->runtime.curve_cache->anim_path_accum_length == NULL) {
+ CLOG_WARN(&LOG, "No anim path!");
+ return false;
+ }
/* We only use the first curve. */
BevList *bl = ob->runtime.curve_cache->bev.first;
if (bl == NULL || !bl->nr) {
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index cbdcf43c039..b5ea68aaadc 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -84,8 +84,6 @@ static CLG_LogRef LOG = {"bke.anim_sys"};
/* Finding Tools --------------------------- */
-/* Find the first path that matches the given criteria */
-/* TODO: do we want some method to perform partial matches too? */
KS_Path *BKE_keyingset_find_path(KeyingSet *ks,
ID *id,
const char group_name[],
@@ -138,8 +136,6 @@ KS_Path *BKE_keyingset_find_path(KeyingSet *ks,
/* Defining Tools --------------------------- */
-/* Used to create a new 'custom' KeyingSet for the user,
- * that will be automatically added to the stack */
KeyingSet *BKE_keyingset_add(
ListBase *list, const char idname[], const char name[], short flag, short keyingflag)
{
@@ -174,9 +170,6 @@ KeyingSet *BKE_keyingset_add(
return ks;
}
-/* Add a path to a KeyingSet. Nothing is returned for now...
- * Checks are performed to ensure that destination is appropriate for the KeyingSet in question
- */
KS_Path *BKE_keyingset_add_path(KeyingSet *ks,
ID *id,
const char group_name[],
@@ -240,7 +233,6 @@ KS_Path *BKE_keyingset_add_path(KeyingSet *ks,
return ksp;
}
-/* Free the given Keying Set path */
void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp)
{
/* sanity check */
@@ -257,7 +249,6 @@ void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp)
BLI_freelinkN(&ks->paths, ksp);
}
-/* Copy all KeyingSets in the given list */
void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
{
KeyingSet *ksn;
@@ -276,7 +267,6 @@ void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
/* Freeing Tools --------------------------- */
-/* Free data for KeyingSet but not set itself */
void BKE_keyingset_free(KeyingSet *ks)
{
KS_Path *ksp, *kspn;
@@ -293,7 +283,6 @@ void BKE_keyingset_free(KeyingSet *ks)
}
}
-/* Free all the KeyingSets in the given list */
void BKE_keyingsets_free(ListBase *list)
{
KeyingSet *ks, *ksn;
@@ -490,7 +479,6 @@ bool BKE_animsys_read_from_rna_path(PathResolvedRNA *anim_rna, float *r_value)
return true;
}
-/* Write the given value to a setting using RNA, and return success */
bool BKE_animsys_write_to_rna_path(PathResolvedRNA *anim_rna, const float value)
{
PropertyRNA *prop = anim_rna->prop;
@@ -831,7 +819,6 @@ static void action_idcode_patch_check(ID *id, bAction *act)
/* ----------------------------------------- */
-/* Evaluate Action Group */
void animsys_evaluate_action_group(PointerRNA *ptr,
bAction *act,
bActionGroup *agrp,
@@ -864,7 +851,6 @@ void animsys_evaluate_action_group(PointerRNA *ptr,
}
}
-/* Evaluate Action (F-Curve Bag) */
void animsys_evaluate_action(PointerRNA *ptr,
bAction *act,
const AnimationEvalContext *anim_eval_context,
@@ -881,7 +867,6 @@ void animsys_evaluate_action(PointerRNA *ptr,
animsys_evaluate_fcurves(ptr, &act->curves, anim_eval_context, flush_to_original);
}
-/* Evaluate Action and blend it into the current values of the animated properties. */
void animsys_blend_in_action(PointerRNA *ptr,
bAction *act,
const AnimationEvalContext *anim_eval_context,
@@ -960,7 +945,6 @@ static void nlastrip_evaluate_controls(NlaStrip *strip,
}
}
-/* gets the strip active at the current time for a list of strips for evaluation purposes */
NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
ListBase *strips,
short index,
@@ -2402,7 +2386,6 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr,
nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
}
-/* evaluates the given evaluation strip */
void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalData *channels,
ListBase *modifiers,
@@ -2447,7 +2430,6 @@ void nlastrip_evaluate(PointerRNA *ptr,
strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED;
}
-/* write the accumulated settings to */
void nladata_flush_channels(PointerRNA *ptr,
NlaEvalData *channels,
NlaEvalSnapshot *snapshot,
@@ -2977,14 +2959,6 @@ void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapsh
}
}
-/**
- * Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
- * to the given \a upper_blendmode and \a upper_influence.
- *
- * For \a upper_snapshot, blending limited to values in the \a blend_domain.
- * For Replace blend-mode, this allows the upper snapshot to have a location XYZ channel
- * where only a subset of values are blended.
- */
void nlasnapshot_blend(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *upper_snapshot,
@@ -3012,14 +2986,6 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
}
}
-/**
- * Using \a blended_snapshot and \a lower_snapshot, we can solve for the \a r_upper_snapshot.
- *
- * Only channels that exist within \a blended_snapshot are inverted.
- *
- * For \a r_upper_snapshot, disables \a NlaEvalChannelSnapshot->remap_domain for failed inversions.
- * Only values within the \a remap_domain are processed.
- */
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
@@ -3050,15 +3016,6 @@ void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
/* ---------------------- */
-/**
- * Prepare data necessary to compute correct keyframe values for NLA strips
- * with non-Replace mode or influence different from 1.
- *
- * \param cache: List used to cache contexts for reuse when keying
- * multiple channels in one operation.
- * \param ptr: RNA pointer to the Object with the animation.
- * \return Keyframing context, or NULL if not necessary.
- */
NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
@@ -3095,18 +3052,6 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
return ctx;
}
-/**
- * Apply correction from the NLA context to the values about to be keyframed.
- *
- * \param context: Context to use (may be NULL).
- * \param prop_ptr: Property about to be keyframed.
- * \param[in,out] values: Array of property values to adjust.
- * \param count: Number of values in the array.
- * \param index: Index of the element about to be updated, or -1.
- * \param[out] r_force_all: Set to true if all channels must be inserted. May be NULL.
- * \return False if correction fails due to a division by zero,
- * or null r_force_all when all channels are required.
- */
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,
@@ -3202,9 +3147,6 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
return successful_remap;
}
-/**
- * Free all cached contexts from the list.
- */
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
{
LISTBASE_FOREACH (NlaKeyframingContext *, ctx, cache) {
@@ -3270,12 +3212,6 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* However, the code for this is relatively harmless, so is left in the code for now.
*/
-/* Evaluation loop for evaluation animation data
- *
- * This assumes that the animation-data provided belongs to the ID block in question,
- * and that the flags for which parts of the anim-data settings need to be recalculated
- * have been set already by the depsgraph. Now, we use the recalc
- */
void BKE_animsys_evaluate_animdata(ID *id,
AnimData *adt,
const AnimationEvalContext *anim_eval_context,
@@ -3329,13 +3265,6 @@ void BKE_animsys_evaluate_animdata(ID *id,
animsys_evaluate_overrides(&id_ptr, adt);
}
-/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
- *
- * This will evaluate only the animation info available in the animation data-blocks
- * encountered. In order to enforce the system by which some settings controlled by a
- * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
- * standard 'root') block are overridden by a larger 'user'
- */
void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float ctime)
{
ID *id;
diff --git a/source/blender/blenkernel/intern/anim_visualization.c b/source/blender/blenkernel/intern/anim_visualization.c
index 56bd8e769bc..fdea52bcd64 100644
--- a/source/blender/blenkernel/intern/anim_visualization.c
+++ b/source/blender/blenkernel/intern/anim_visualization.c
@@ -39,7 +39,6 @@
/* ******************************************************************** */
/* Animation Visualization */
-/* Initialize the default settings for animation visualization */
void animviz_settings_init(bAnimVizSettings *avs)
{
/* sanity check */
@@ -62,7 +61,6 @@ void animviz_settings_init(bAnimVizSettings *avs)
/* ------------------- */
-/* Free the given motion path's cache */
void animviz_free_motionpath_cache(bMotionPath *mpath)
{
/* sanity check */
@@ -84,9 +82,6 @@ void animviz_free_motionpath_cache(bMotionPath *mpath)
mpath->length = 0;
}
-/* Free the given motion path instance and its data
- * NOTE: this frees the motion path given!
- */
void animviz_free_motionpath(bMotionPath *mpath)
{
/* sanity check */
@@ -103,7 +98,6 @@ void animviz_free_motionpath(bMotionPath *mpath)
/* ------------------- */
-/* Make a copy of motionpath data, so that viewing with copy on write works */
bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
{
bMotionPath *mpath_dst;
@@ -125,14 +119,6 @@ bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
/* ------------------- */
-/**
- * Setup motion paths for the given data.
- * \note Only used when explicitly calculating paths on bones which may/may not be consider already
- *
- * \param scene: Current scene (for frame ranges, etc.)
- * \param ob: Object to add paths for (must be provided)
- * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
- */
bMotionPath *animviz_verify_motionpaths(ReportList *reports,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index d872dc67dcb..9dd4c7e503a 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -99,15 +99,6 @@ static bool is_appdir_init = false;
# define ASSERT_IS_INIT() ((void)0)
#endif
-/**
- * Sanity check to ensure correct API use in debug mode.
- *
- * Run this once the first level of arguments has been passed so we can be sure
- * `--env-system-datafiles`, and other `--env-*` arguments has been passed.
- *
- * Without this any callers to this module that run early on,
- * will miss out on changes from parsing arguments.
- */
void BKE_appdir_init(void)
{
#ifndef NDEBUG
@@ -147,14 +138,6 @@ static char *blender_version_decimal(const int version)
/** \name Default Directories
* \{ */
-/**
- * Get the folder that's the "natural" starting point for browsing files on an OS.
- * - Unix: `$HOME`
- * - Windows: `%userprofile%/Documents`
- *
- * \note On Windows `Users/{MyUserName}/Documents` is used as it's the default location to save
- * documents.
- */
const char *BKE_appdir_folder_default(void)
{
#ifndef WIN32
@@ -190,29 +173,17 @@ const char *BKE_appdir_folder_default_or_root(void)
return path;
}
-/**
- * Get the user's home directory, i.e.
- * - Unix: `$HOME`
- * - Windows: `%userprofile%`
- */
const char *BKE_appdir_folder_home(void)
{
-#ifndef WIN32
- return BLI_getenv("HOME");
-#else /* Windows */
+#ifdef WIN32
return BLI_getenv("userprofile");
+#elif defined(__APPLE__)
+ return BLI_expand_tilde("~/");
+#else
+ return BLI_getenv("HOME");
#endif
}
-/**
- * Get the user's document directory, i.e.
- * - Linux: `$HOME/Documents`
- * - Windows: `%userprofile%/Documents`
- *
- * If this can't be found using OS queries (via Ghost), try manually finding it.
- *
- * \returns True if the path is valid and points to an existing directory.
- */
bool BKE_appdir_folder_documents(char *dir)
{
dir[0] = '\0';
@@ -243,15 +214,6 @@ bool BKE_appdir_folder_documents(char *dir)
return true;
}
-/**
- * Get the user's cache directory, i.e.
- * - Linux: `$HOME/.cache/blender/`
- * - Windows: `%USERPROFILE%\AppData\Local\Blender Foundation\Blender\`
- * - MacOS: `/Library/Caches/Blender`
- *
- * \returns True if the path is valid. It doesn't create or checks format
- * if the `blender` folder exists. It does check if the parent of the path exists.
- */
bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
{
r_path[0] = '\0';
@@ -276,9 +238,6 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
return true;
}
-/**
- * Gets a good default directory for fonts.
- */
bool BKE_appdir_font_folder_default(char *dir)
{
char test_dir[FILE_MAXDIR];
@@ -291,10 +250,8 @@ bool BKE_appdir_font_folder_default(char *dir)
BLI_strncpy_wchar_as_utf8(test_dir, wpath, sizeof(test_dir));
}
#elif defined(__APPLE__)
- const char *home = BLI_getenv("HOME");
- if (home) {
- BLI_path_join(test_dir, sizeof(test_dir), home, "Library", "Fonts", NULL);
- }
+ STRNCPY(test_dir, BLI_expand_tilde("~/Library/Fonts/"));
+ BLI_path_slash_ensure(test_dir);
#else
STRNCPY(test_dir, "/usr/share/fonts");
#endif
@@ -458,10 +415,6 @@ static bool get_path_local(char *targetpath,
targetpath, targetpath_len, folder_name, subfolder_name, version, check_is_dir);
}
-/**
- * Check if this is an install with user files kept together
- * with the Blender executable and its installation files.
- */
bool BKE_appdir_app_is_portable_install(void)
{
/* Detect portable install by the existence of `config` folder. */
@@ -626,13 +579,6 @@ static bool get_path_system(char *targetpath,
/** \name Path Presets API
* \{ */
-/**
- * Get a folder out of the \a folder_id presets for paths.
- *
- * \param subfolder: The name of a directory to check for,
- * this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
- * \return The path if found, NULL string if not.
- */
bool BKE_appdir_folder_id_ex(const int folder_id,
const char *subfolder,
char *path,
@@ -746,9 +692,6 @@ const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
return NULL;
}
-/**
- * Returns the path to a folder in the user area without checking that it actually exists first.
- */
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder)
{
const int version = BLENDER_VERSION;
@@ -795,9 +738,6 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
return path;
}
-/**
- * Returns the path to a folder in the user area, creating it if it doesn't exist.
- */
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
{
const char *path;
@@ -823,10 +763,6 @@ const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfold
return path;
}
-/**
- * Returns the path of the top-level version-specific local, user or system directory.
- * If check_is_dir, then the result will be NULL if the directory doesn't exist.
- */
const char *BKE_appdir_folder_id_version(const int folder_id,
const int version,
const bool check_is_dir)
@@ -942,18 +878,12 @@ void BKE_appdir_program_path_init(const char *argv0)
BLI_split_dir_part(g_app.program_filename, g_app.program_dirname, sizeof(g_app.program_dirname));
}
-/**
- * Path to executable
- */
const char *BKE_appdir_program_path(void)
{
BLI_assert(g_app.program_filename[0]);
return g_app.program_filename;
}
-/**
- * Path to directory of executable
- */
const char *BKE_appdir_program_dir(void)
{
BLI_assert(g_app.program_dirname[0]);
@@ -1047,9 +977,6 @@ static const int app_template_directory_id[2] = {
BLENDER_SYSTEM_SCRIPTS,
};
-/**
- * Return true if templates exist
- */
bool BKE_appdir_app_template_any(void)
{
char temp_dir[FILE_MAX];
@@ -1217,14 +1144,13 @@ static void tempdir_session_create(char *tempdir_session,
BLI_strncpy(tempdir_session, tempdir, tempdir_session_len);
}
-/**
- * Sets #g_app.temp_dirname_base to \a userdir if specified and is a valid directory,
- * otherwise chooses a suitable OS-specific temporary directory.
- * Sets #g_app.temp_dirname_session to a #mkdtemp
- * generated sub-dir of #g_app.temp_dirname_base.
- */
void BKE_tempdir_init(const char *userdir)
{
+ /* Sets #g_app.temp_dirname_base to \a userdir if specified and is a valid directory,
+ * otherwise chooses a suitable OS-specific temporary directory.
+ * Sets #g_app.temp_dirname_session to a #mkdtemp
+ * generated sub-dir of #g_app.temp_dirname_base. */
+
where_is_temp(g_app.temp_dirname_base, sizeof(g_app.temp_dirname_base), userdir);
/* Clear existing temp dir, if needed. */
@@ -1234,25 +1160,16 @@ void BKE_tempdir_init(const char *userdir)
g_app.temp_dirname_session, sizeof(g_app.temp_dirname_session), g_app.temp_dirname_base);
}
-/**
- * Path to temporary directory (with trailing slash)
- */
const char *BKE_tempdir_session(void)
{
return g_app.temp_dirname_session[0] ? g_app.temp_dirname_session : BKE_tempdir_base();
}
-/**
- * Path to persistent temporary directory (with trailing slash)
- */
const char *BKE_tempdir_base(void)
{
return g_app.temp_dirname_base;
}
-/**
- * Delete content of this instance's temp dir.
- */
void BKE_tempdir_session_purge(void)
{
if (g_app.temp_dirname_session[0] && BLI_is_dir(g_app.temp_dirname_session)) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index b830c9de5f5..0a91d662c1b 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -322,6 +322,7 @@ IDTypeInfo IDType_ID_AR = {
.name_plural = "armatures",
.translation_context = BLT_I18NCONTEXT_ID_ARMATURE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = armature_init_data,
.copy_data = armature_copy_data,
@@ -329,6 +330,7 @@ IDTypeInfo IDType_ID_AR = {
.make_local = NULL,
.foreach_id = armature_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = armature_blend_write,
@@ -607,10 +609,6 @@ static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name)
return NULL;
}
-/**
- * Walk the list until the bone is found (slow!),
- * use #BKE_armature_bone_from_name_map for multiple lookups.
- */
Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name)
{
if (!arm) {
@@ -715,10 +713,6 @@ void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmatu
/** \name Armature Layer Refresh Used
* \{ */
-/* Finds the best possible extension to the name on a particular axis. (For renaming, check for
- * unique names afterwards) strip_number: removes number extensions (TODO: not used)
- * axis: the axis to name on
- * head/tail: the head/tail co-ordinate of the bone on the specified axis */
bool bone_autoside_name(
char name[MAXBONENAME], int UNUSED(strip_number), short axis, float head, float tail)
{
@@ -930,7 +924,6 @@ static void evaluate_cubic_bezier(const float control[4][3],
madd_v3_v3v3fl(r_pos, layer2[0], r_tangent, t);
}
-/* Get "next" and "prev" bones - these are used for handle calculations. */
void BKE_pchan_bbone_handles_get(bPoseChannel *pchan, bPoseChannel **r_prev, bPoseChannel **r_next)
{
if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO) {
@@ -957,7 +950,6 @@ void BKE_pchan_bbone_handles_get(bPoseChannel *pchan, bPoseChannel **r_prev, bPo
}
}
-/* Compute B-Bone spline parameters for the given channel. */
void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
const bool rest,
struct BBoneSplineParameters *param)
@@ -1203,8 +1195,6 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
}
}
-/* Fills the array with the desired amount of bone->segments elements.
- * This calculation is done within unit bone space. */
void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan,
const bool rest,
const bool for_deform,
@@ -1217,7 +1207,6 @@ void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan,
pchan->bone->segments = BKE_pchan_bbone_spline_compute(&param, for_deform, result_array);
}
-/* Computes the bezier handle vectors and rolls coming from custom handles. */
void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
float h1[3],
float *r_roll1,
@@ -1375,8 +1364,6 @@ static void ease_handle_axis(const float deriv1[3], const float deriv2[3], float
}
}
-/* Fills the array with the desired amount of bone->segments elements.
- * This calculation is done within unit bone space. */
int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
const bool for_deform,
Mat4 *result_array)
@@ -1511,7 +1498,6 @@ static void allocate_bbone_cache(bPoseChannel *pchan, int segments)
}
}
-/** Compute and cache the B-Bone shape in the channel runtime struct. */
void BKE_pchan_bbone_segments_cache_compute(bPoseChannel *pchan)
{
bPoseChannel_Runtime *runtime = &pchan->runtime;
@@ -1563,7 +1549,6 @@ void BKE_pchan_bbone_segments_cache_compute(bPoseChannel *pchan)
}
}
-/** Copy cached B-Bone segments from one channel to another */
void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pchan_from)
{
bPoseChannel_Runtime *runtime = &pchan->runtime;
@@ -1587,10 +1572,6 @@ void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pcha
}
}
-/**
- * Calculate index and blend factor for the two B-Bone segment nodes
- * affecting the point at 0 <= pos <= 1.
- */
void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
float pos,
int *r_index,
@@ -1622,7 +1603,6 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
/** \name Bone Space to Space Conversion API
* \{ */
-/* Convert World-Space Matrix to Pose-Space Matrix */
void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float outmat[4][4])
{
float obmat[4][4];
@@ -1639,9 +1619,6 @@ void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float o
mul_m4_m4m4(outmat, inmat, obmat);
}
-/* Convert World-Space Location to Pose-Space Location
- * NOTE: this cannot be used to convert to pose-space location of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outloc[3])
{
float xLocMat[4][4];
@@ -1662,8 +1639,6 @@ void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outl
/** \name Bone Matrix Calculation API
* \{ */
-/* Simple helper, computes the offset bone matrix.
- * offs_bone = yoffs(b-1) + root(b) + bonemat(b). */
void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
{
BLI_assert(bone->parent != NULL);
@@ -1678,24 +1653,6 @@ void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
offs_bone[3][1] += bone->parent->length;
}
-/* Construct the matrices (rot/scale and loc)
- * to apply the PoseChannels into the armature (object) space.
- * I.e. (roughly) the "pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)" in the
- * pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b)
- * ...function.
- *
- * This allows to get the transformations of a bone in its object space,
- * *before* constraints (and IK) get applied (used by pose evaluation code).
- * And reverse: to find pchan transformations needed to place a bone at a given loc/rot/scale
- * in object space (used by interactive transform, and snapping code).
- *
- * Note that, with the HINGE/NO_SCALE/NO_LOCAL_LOCATION options, the location matrix
- * will differ from the rotation/scale matrix...
- *
- * NOTE: This cannot be used to convert to pose-space transforms of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing).
- * (note: I don't understand that, so I keep it :p --mont29).
- */
void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
BoneParentTransform *r_bpt)
{
@@ -1725,12 +1682,6 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
}
}
-/* Compute the parent transform using data decoupled from specific data structures.
- *
- * bone_flag: Bone->flag containing settings
- * offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent)
- * parent_arm_mat, parent_pose_mat: arm_mat and pose_mat of parent, or NULL
- * r_bpt: OUTPUT parent transform */
void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
int inherit_scale_mode,
const float offs_bone[4][4],
@@ -1912,9 +1863,6 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
rescale_m4(outmat, bpt->post_scale);
}
-/* Convert Pose-Space Matrix to Bone-Space Matrix.
- * NOTE: this cannot be used to convert to pose-space transforms of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4])
@@ -1926,7 +1874,6 @@ void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan,
BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
}
-/* Convert Bone-Space Matrix to Pose-Space Matrix. */
void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan,
const float inmat[4][4],
float outmat[4][4])
@@ -1937,9 +1884,6 @@ void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan,
BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
}
-/* Convert Pose-Space Location to Bone-Space Location
- * NOTE: this cannot be used to convert to pose-space location of the supplied
- * pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], float outloc[3])
{
float xLocMat[4][4];
@@ -1982,9 +1926,6 @@ void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph,
BKE_armature_mat_pose_to_bone(&work_pchan, inmat, outmat);
}
-/**
- * Same as #BKE_object_mat3_to_rot().
- */
void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, const float mat[3][3], bool use_compat)
{
BLI_ASSERT_UNIT_M3(mat);
@@ -2007,9 +1948,6 @@ void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, const float mat[3][3], bool use_
}
}
-/**
- * Same as #BKE_object_rot_to_mat3().
- */
void BKE_pchan_rot_to_mat3(const bPoseChannel *pchan, float r_mat[3][3])
{
/* rotations may either be quats, eulers (with various rotation orders), or axis-angle */
@@ -2034,10 +1972,6 @@ void BKE_pchan_rot_to_mat3(const bPoseChannel *pchan, float r_mat[3][3])
}
}
-/**
- * Apply a 4x4 matrix to the pose bone,
- * similar to #BKE_object_apply_mat4().
- */
void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_compat)
{
float rot[3][3];
@@ -2045,11 +1979,6 @@ void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_c
BKE_pchan_mat3_to_rot(pchan, rot, use_compat);
}
-/**
- * Remove rest-position effects from pose-transform for obtaining
- * 'visual' transformation of pose-channel.
- * (used by the Visual-Keyframing stuff).
- */
void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
float pose_mat[4][4],
float arm_mat[4][4])
@@ -2068,11 +1997,6 @@ void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
* Used for Objects and Pose Channels, since both can have multiple rotation representations.
* \{ */
-/**
- * Called from RNA when rotation mode changes
- * - the result should be that the rotations given in the provided pointers have had conversions
- * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed.
- */
void BKE_rotMode_change_values(
float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode)
{
@@ -2146,8 +2070,6 @@ void BKE_rotMode_change_values(
*
* \{ */
-/* Computes vector and roll based on a rotation.
- * "mat" must contain only a rotation, and no scaling. */
void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
{
if (r_vec) {
@@ -2159,8 +2081,6 @@ void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
}
}
-/* Computes roll around the vector that best approximates the matrix.
- * If vec is the Y vector from purely rotational mat, result should be exact. */
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
{
float vecmat[3][3], vecmatinv[3][3], rollmat[3][3], q[4];
@@ -2176,79 +2096,6 @@ void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
*r_roll = quat_split_swing_and_twist(q, 1, NULL, NULL);
}
-/* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */
-/**
- * Given `v = (v.x, v.y, v.z)` our (normalized) bone vector, we want the rotation matrix M
- * from the Y axis (so that `M * (0, 1, 0) = v`).
- * - The rotation axis a lays on XZ plane, and it is orthonormal to v,
- * hence to the projection of v onto XZ plane.
- * - `a = (v.z, 0, -v.x)`
- *
- * We know a is eigenvector of M (so M * a = a).
- * Finally, we have w, such that M * w = (0, 1, 0)
- * (i.e. the vector that will be aligned with Y axis once transformed).
- * We know w is symmetric to v by the Y axis.
- * - `w = (-v.x, v.y, -v.z)`
- *
- * Solving this, we get (x, y and z being the components of v):
- * <pre>
- * ┌ (x^2 * y + z^2) / (x^2 + z^2), x, x * z * (y - 1) / (x^2 + z^2) ┐
- * M = │ x * (y^2 - 1) / (x^2 + z^2), y, z * (y^2 - 1) / (x^2 + z^2) │
- * └ x * z * (y - 1) / (x^2 + z^2), z, (x^2 + z^2 * y) / (x^2 + z^2) ┘
- * </pre>
- *
- * This is stable as long as v (the bone) is not too much aligned with +/-Y
- * (i.e. x and z components are not too close to 0).
- *
- * Since v is normalized, we have `x^2 + y^2 + z^2 = 1`,
- * hence `x^2 + z^2 = 1 - y^2 = (1 - y)(1 + y)`.
- *
- * This allows to simplifies M like this:
- * <pre>
- * ┌ 1 - x^2 / (1 + y), x, -x * z / (1 + y) ┐
- * M = │ -x, y, -z │
- * └ -x * z / (1 + y), z, 1 - z^2 / (1 + y) ┘
- * </pre>
- *
- * Written this way, we see the case v = +Y is no more a singularity.
- * The only one
- * remaining is the bone being aligned with -Y.
- *
- * Let's handle
- * the asymptotic behavior when bone vector is reaching the limit of y = -1.
- * Each of the four corner elements can vary from -1 to 1,
- * depending on the axis a chosen for doing the rotation.
- * And the "rotation" here is in fact established by mirroring XZ plane by that given axis,
- * then inversing the Y-axis.
- * For sufficiently small x and z, and with y approaching -1,
- * all elements but the four corner ones of M will degenerate.
- * So let's now focus on these corner elements.
- *
- * We rewrite M so that it only contains its four corner elements,
- * and combine the `1 / (1 + y)` factor:
- * <pre>
- * ┌ 1 + y - x^2, -x * z ┐
- * M* = 1 / (1 + y) * │ │
- * └ -x * z, 1 + y - z^2 ┘
- * </pre>
- *
- * When y is close to -1, computing 1 / (1 + y) will cause severe numerical instability,
- * so we use a different approach based on x and z as inputs.
- * We know `y^2 = 1 - (x^2 + z^2)`, and `y < 0`, hence `y = -sqrt(1 - (x^2 + z^2))`.
- *
- * Since x and z are both close to 0, we apply the binomial expansion to the second order:
- * `y = -sqrt(1 - (x^2 + z^2)) = -1 + (x^2 + z^2) / 2 + (x^2 + z^2)^2 / 8`, which allows
- * eliminating the problematic `1` constant.
- *
- * A first order expansion allows simplifying to this, but second order is more precise:
- * <pre>
- * ┌ z^2 - x^2, -2 * x * z ┐
- * M* = 1 / (x^2 + z^2) * │ │
- * └ -2 * x * z, x^2 - z^2 ┘
- * </pre>
- *
- * P.S. In the end, this basically is a heavily optimized version of Damped Track +Y.
- */
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3])
{
const float SAFE_THRESHOLD = 6.1e-3f; /* Theta above this value has good enough precision. */
@@ -2319,10 +2166,6 @@ void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3])
/** \name Armature Bone Matrix Calculation (Recursive)
* \{ */
-/**
- * Recursive part, calculates rest-position of entire tree of children.
- * \note Used when exiting edit-mode too.
- */
void BKE_armature_where_is_bone(Bone *bone, const Bone *bone_parent, const bool use_recursion)
{
float vec[3];
@@ -2361,8 +2204,6 @@ void BKE_armature_where_is_bone(Bone *bone, const Bone *bone_parent, const bool
}
}
-/* updates vectors and matrices on rest-position level, only needed
- * after editing armature itself, now only on reading file */
void BKE_armature_where_is(bArmature *arm)
{
Bone *bone;
@@ -2579,10 +2420,6 @@ static int rebuild_pose_bone(
return counter;
}
-/**
- * Clear pointers of object's pose
- * (needed in remap case, since we cannot always wait for a complete pose rebuild).
- */
void BKE_pose_clear_pointers(bPose *pose)
{
LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
@@ -2604,7 +2441,6 @@ static bPoseChannel *pose_channel_find_bone(bPose *pose, Bone *bone)
return (bone != NULL) ? BKE_pose_channel_find_name(pose, bone->name) : NULL;
}
-/** Update the links for the B-Bone handles from Bone data. */
void BKE_pchan_rebuild_bbone_handles(bPose *pose, bPoseChannel *pchan)
{
pchan->bbone_prev = pose_channel_find_bone(pose, pchan->bone->bbone_prev);
@@ -2622,13 +2458,6 @@ void BKE_pose_channels_clear_with_null_bone(bPose *pose, const bool do_id_user)
}
}
-/**
- * Only after leave editmode, duplicating, validating older files, library syncing.
- *
- * \note pose->flag is set for it.
- *
- * \param bmain: May be NULL, only used to tag depsgraph as being dirty...
- */
void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
Bone *bone;
@@ -2696,11 +2525,6 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_
}
}
-/**
- * Ensures object's pose is rebuilt if needed.
- *
- * \param bmain: May be NULL, only used to tag depsgraph as being dirty...
- */
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
BLI_assert(!ELEM(NULL, arm, ob));
@@ -2716,9 +2540,6 @@ void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, const bool do_id_u
/** \name Pose Solver
* \{ */
-/**
- * Convert the loc/rot/size to \a r_chanmat (typically #bPoseChannel.chan_mat).
- */
void BKE_pchan_to_mat4(const bPoseChannel *pchan, float r_chanmat[4][4])
{
float smat[3][3];
@@ -2742,8 +2563,6 @@ void BKE_pchan_to_mat4(const bPoseChannel *pchan, float r_chanmat[4][4])
}
}
-/* loc/rot/size to mat4 */
-/* used in constraint.c too */
void BKE_pchan_calc_mat(bPoseChannel *pchan)
{
/* this is just a wrapper around the copy of this function which calculates the matrix
@@ -2752,7 +2571,6 @@ void BKE_pchan_calc_mat(bPoseChannel *pchan)
BKE_pchan_to_mat4(pchan, pchan->chan_mat);
}
-/* calculate tail of posechannel */
void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
{
float vec[3];
@@ -2762,10 +2580,6 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
}
-/* The main armature solver, does all constraints excluding IK */
-/* pchan is validated, as having bone and parent pointer
- * 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers.
- */
void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -2830,8 +2644,6 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
BKE_pose_where_is_bone_tail(pchan);
}
-/* This only reads anim data from channels, and writes to channels */
-/* This is the only function adding poses */
void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bArmature *arm;
diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c
index 5f721b49361..a8e74f6b4c3 100644
--- a/source/blender/blenkernel/intern/armature_deform.c
+++ b/source/blender/blenkernel/intern/armature_deform.c
@@ -121,7 +121,6 @@ static void b_bone_deform(const bPoseChannel *pchan,
&quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat);
}
-/* using vec with dist to bone b1 - b2 */
float distfactor_to_bone(
const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
{
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 35ae2d2dbef..05c318663e9 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -277,46 +277,59 @@ static void apply_curve_transform(
*r_radius = (radius + *r_radius) / 2;
}
+static float dist_to_sphere_shell(const float sphere_origin[3],
+ const float sphere_radius,
+ const float point[3])
+{
+ float vec[3];
+ sub_v3_v3v3(vec, sphere_origin, point);
+ return sphere_radius - len_v3(vec);
+}
+
/* This function positions the tail of the bone so that it preserves the length of it.
* The length of the bone can be seen as a sphere radius.
*/
static int position_tail_on_spline(bSplineIKConstraint *ik_data,
const float head_pos[3],
const float sphere_radius,
- const int prev_seg_idx,
+ int prev_seg_idx,
float r_tail_pos[3],
float *r_new_curve_pos,
float *r_radius)
{
/* This is using the tessellated curve data.
* So we are working with piece-wise linear curve segments.
- * The same method is use in #BKE_where_on_path to get curve location data. */
+ * The same method is used in #BKE_where_on_path to get curve location data. */
const CurveCache *cache = ik_data->tar->runtime.curve_cache;
- const BevList *bl = cache->bev.first;
- BevPoint *bp = bl->bevpoints;
- const float spline_len = BKE_anim_path_get_length(cache);
const float *seg_accum_len = cache->anim_path_accum_length;
int max_seg_idx = BKE_anim_path_get_array_size(cache) - 1;
- /* Convert our initial intersection point guess to a point index.
- * If the curve was a straight line, then pointEnd would be the correct location.
+ /* Make an initial guess of where our intersection point will be.
+ * If the curve was a straight line, then the faction passed in r_new_curve_pos
+ * would be the correct location.
* So make it our first initial guess.
*/
+ const float spline_len = BKE_anim_path_get_length(cache);
const float guessed_len = *r_new_curve_pos * spline_len;
BLI_assert(prev_seg_idx >= 0);
-
int cur_seg_idx = prev_seg_idx;
while (cur_seg_idx < max_seg_idx && guessed_len > seg_accum_len[cur_seg_idx]) {
cur_seg_idx++;
}
+ /* Convert the segment to bev points.
+ * For example, the segment with index 0 will have bev points 0 and 1.
+ */
int bp_idx = cur_seg_idx + 1;
- bp = bp + bp_idx;
+ const BevList *bl = cache->bev.first;
bool is_cyclic = bl->poly >= 0;
- BevPoint *prev_bp = bp - 1;
+ BevPoint *bp = bl->bevpoints;
+ BevPoint *prev_bp;
+ bp = bp + bp_idx;
+ prev_bp = bp - 1;
/* Go to the next tessellated curve point until we cross to outside of the sphere. */
while (len_v3v3(head_pos, bp->vec) < sphere_radius) {
@@ -337,35 +350,53 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
bp_idx++;
}
- float isect_1[3], isect_2[3];
-
- /* Calculate the intersection point. */
- int ret = isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
+ /* Calculate the intersection point using the secant root finding method */
+ float x0 = 0.0f, x1 = 1.0f, x2 = 0.5f;
+ float x0_point[3], x1_point[3], start_p[3];
+ float epsilon = max_fff(1.0f, len_v3(head_pos), len_v3(bp->vec)) * FLT_EPSILON;
- if (ret > 0) {
- /* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
- * intersection point we want. And it will always intersect as we go from inside to outside
- * of the sphere.
+ if (prev_seg_idx == bp_idx - 1) {
+ /* The intersection lies inside the same segment as the last point.
+ * Set the last point to be the start search point so we minimize the risks of going backwards
+ * on the curve.
*/
- copy_v3_v3(r_tail_pos, isect_1);
+ copy_v3_v3(start_p, head_pos);
}
else {
- /* Couldn't find an intersection point. This means that the floating point
- * values are too small and thus the intersection check fails.
- * So assume that the distance is so small that tail_pos == head_pos.
- */
- copy_v3_v3(r_tail_pos, head_pos);
+ copy_v3_v3(start_p, prev_bp->vec);
}
- cur_seg_idx = bp_idx - 2;
+ for (int i = 0; i < 10; i++) {
+ interp_v3_v3v3(x0_point, start_p, bp->vec, x0);
+ interp_v3_v3v3(x1_point, start_p, bp->vec, x1);
+
+ float f_x0 = dist_to_sphere_shell(head_pos, sphere_radius, x0_point);
+ float f_x1 = dist_to_sphere_shell(head_pos, sphere_radius, x1_point);
+
+ if (fabsf(f_x1) <= epsilon || f_x0 == f_x1) {
+ break;
+ }
+
+ x2 = x1 - f_x1 * (x1 - x0) / (f_x1 - f_x0);
+ x0 = x1;
+ x1 = x2;
+ }
+ /* Found the bone tail position! */
+ copy_v3_v3(r_tail_pos, x1_point);
+
+ /* Because our intersection point lies inside the current segment,
+ * Convert our bevpoint index back to the previous segment index (-2 instead of -1).
+ * This is because our actual location is prev_seg_len + isect_seg_len.
+ */
+ prev_seg_idx = bp_idx - 2;
float prev_seg_len = 0;
- if (cur_seg_idx < 0) {
- cur_seg_idx = 0;
+ if (prev_seg_idx < 0) {
+ prev_seg_idx = 0;
prev_seg_len = 0;
}
else {
- prev_seg_len = seg_accum_len[cur_seg_idx];
+ prev_seg_len = seg_accum_len[prev_seg_idx];
}
/* Convert the point back into the 0-1 interpolation range. */
@@ -380,7 +411,8 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
*r_radius = (1.0f - frac) * prev_bp->radius + frac * bp->radius;
}
- return cur_seg_idx;
+ /* Return the current segment. */
+ return bp_idx - 1;
}
/* Evaluate spline IK for a given bone. */
diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc
index 59e402b6680..e5509b09e20 100644
--- a/source/blender/blenkernel/intern/asset.cc
+++ b/source/blender/blenkernel/intern/asset.cc
@@ -39,7 +39,7 @@
using namespace blender;
-AssetMetaData *BKE_asset_metadata_create(void)
+AssetMetaData *BKE_asset_metadata_create()
{
AssetMetaData *asset_data = (AssetMetaData *)MEM_callocN(sizeof(*asset_data), __func__);
memcpy(asset_data, DNA_struct_default_get(AssetMetaData), sizeof(*asset_data));
@@ -78,9 +78,6 @@ AssetTag *BKE_asset_metadata_tag_add(AssetMetaData *asset_data, const char *name
return tag;
}
-/**
- * Make sure there is a tag with name \a name, create one if needed.
- */
struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(AssetMetaData *asset_data,
const char *name)
{
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index 03043f3b784..aec622bb71f 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -36,12 +36,7 @@ namespace blender::bke {
const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt";
-/* For now this is the only version of the catalog definition files that is supported.
- * Later versioning code may be added to handle older files. */
const int AssetCatalogDefinitionFile::SUPPORTED_VERSION = 1;
-/* String that's matched in the catalog definition file to know that the line is the version
- * declaration. It has to start with a space to ensure it won't match any hypothetical future field
- * that starts with "VERSION". */
const std::string AssetCatalogDefinitionFile::VERSION_MARKER = "VERSION ";
const std::string AssetCatalogDefinitionFile::HEADER =
@@ -98,6 +93,14 @@ bool AssetCatalogService::has_unsaved_changes() const
return catalog_collection_->has_unsaved_changes_;
}
+void AssetCatalogService::tag_all_catalogs_as_unsaved_changes()
+{
+ for (auto &catalog : catalog_collection_->catalogs_.values()) {
+ catalog->flags.has_unsaved_changes = true;
+ }
+ catalog_collection_->has_unsaved_changes_ = true;
+}
+
bool AssetCatalogService::is_empty() const
{
BLI_assert(catalog_collection_);
@@ -486,6 +489,24 @@ bool AssetCatalogService::write_to_disk_ex(const CatalogFilePath &blend_file_pat
return catalog_collection_->catalog_definition_file_->write_to_disk();
}
+void AssetCatalogService::prepare_to_merge_on_write()
+{
+ /* TODO(Sybren): expand to support multiple CDFs. */
+
+ if (!catalog_collection_->catalog_definition_file_) {
+ /* There is no CDF connected, so it's a no-op. */
+ return;
+ }
+
+ /* Remove any association with the CDF, so that a new location will be chosen
+ * when the blend file is saved. */
+ catalog_collection_->catalog_definition_file_.reset();
+
+ /* Mark all in-memory catalogs as "dirty", to force them to be kept around on
+ * the next "load-merge-write" cycle. */
+ tag_all_catalogs_as_unsaved_changes();
+}
+
CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
const CatalogFilePath &blend_file_path)
{
diff --git a/source/blender/blenkernel/intern/asset_catalog_path.cc b/source/blender/blenkernel/intern/asset_catalog_path.cc
index 20cac76b40b..d789150dba5 100644
--- a/source/blender/blenkernel/intern/asset_catalog_path.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_path.cc
@@ -74,8 +74,6 @@ StringRefNull AssetCatalogPath::name() const
return StringRefNull(this->path_.c_str() + last_sep_index + 1);
}
-/* In-class operators, because of the implicit `AssetCatalogPath(StringRef)` constructor.
- * Otherwise `string == string` could cast both sides to `AssetCatalogPath`. */
bool AssetCatalogPath::operator==(const AssetCatalogPath &other_path) const
{
return this->path_ == other_path.path_;
diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc
index 68e43852a21..74de9b93c25 100644
--- a/source/blender/blenkernel/intern/asset_library.cc
+++ b/source/blender/blenkernel/intern/asset_library.cc
@@ -71,7 +71,7 @@ bool BKE_asset_library_find_suitable_root_path_from_path(const char *input_path,
bool BKE_asset_library_find_suitable_root_path_from_main(const Main *bmain, char *r_library_path)
{
- return BKE_asset_library_find_suitable_root_path_from_path(bmain->name, r_library_path);
+ return BKE_asset_library_find_suitable_root_path_from_path(bmain->filepath, r_library_path);
}
blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service(
@@ -168,7 +168,7 @@ void AssetLibrary::on_blend_save_post(struct Main *main,
}
if (save_catalogs_when_file_is_saved) {
- this->catalog_service->write_to_disk(main->name);
+ this->catalog_service->write_to_disk(main->filepath);
}
}
diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc
index d202d6462cf..6b3f1fa3408 100644
--- a/source/blender/blenkernel/intern/asset_library_service.cc
+++ b/source/blender/blenkernel/intern/asset_library_service.cc
@@ -125,9 +125,6 @@ static void on_blendfile_load(struct Main * /*bMain*/,
AssetLibraryService::destroy();
}
-/**
- * Ensure the AssetLibraryService instance is destroyed before a new blend file is loaded.
- * This makes memory management simple, and ensures a fresh start for every blend file. */
void AssetLibraryService::app_handler_register()
{
/* The callback system doesn't own `on_load_callback_store_`. */
diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc
index ee910cab945..9fa6d100a53 100644
--- a/source/blender/blenkernel/intern/asset_library_service_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_service_test.cc
@@ -97,7 +97,7 @@ TEST_F(AssetLibraryServiceTest, get_destroy)
AssetLibraryService::destroy();
AssetLibraryService::destroy();
- /* Note: there used to be a test for the opposite here, that after a call to
+ /* NOTE: there used to be a test for the opposite here, that after a call to
* AssetLibraryService::destroy() the above calls should return freshly allocated objects. This
* cannot be reliably tested by just pointer comparison, though. */
}
@@ -113,7 +113,7 @@ TEST_F(AssetLibraryServiceTest, library_pointers)
EXPECT_EQ(curfile_lib, service->get_asset_library_current_file())
<< "Calling twice without destroying in between should return the same instance.";
- /* Note: there used to be a test for the opposite here, that after a call to
+ /* NOTE: there used to be a test for the opposite here, that after a call to
* AssetLibraryService::destroy() the above calls should return freshly allocated objects. This
* cannot be reliably tested by just pointer comparison, though. */
}
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 3f2c1f13337..1a4265d936b 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -23,6 +23,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
+#include "BKE_type_conversions.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -36,8 +37,6 @@
#include "CLG_log.h"
-#include "NOD_type_conversions.hh"
-
#include "attribute_access_intern.hh"
static CLG_LogRef LOG = {"bke.attribute_access"};
@@ -50,7 +49,7 @@ using blender::bke::AttributeIDRef;
using blender::bke::OutputAttribute;
using blender::fn::GMutableSpan;
using blender::fn::GSpan;
-using blender::fn::GVMutableArrayImpl_For_GMutableSpan;
+using blender::fn::GVArrayImpl_For_GSpan;
namespace blender::bke {
@@ -183,10 +182,6 @@ static int attribute_domain_priority(const AttributeDomain domain)
}
}
-/**
- * Domains with a higher "information density" have a higher priority, in order
- * to choose a domain that will not lose data through domain conversion.
- */
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
{
int highest_priority = INT_MIN;
@@ -288,7 +283,7 @@ static void *add_generic_custom_data_layer(CustomData &custom_data,
char attribute_name_c[MAX_NAME];
attribute_id.name().copy(attribute_name_c);
return CustomData_add_layer_named(
- &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
+ &custom_data, data_type, alloctype, layer_data, domain_size, attribute_name_c);
}
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
return CustomData_add_layer_anonymous(
@@ -400,7 +395,9 @@ WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
}
if (data != new_data) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
data = new_data;
}
@@ -441,7 +438,9 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
const bool delete_success = CustomData_free_layer(
custom_data, stored_type_, domain_size, layer_index);
if (delete_success) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
}
return delete_success;
}
@@ -476,7 +475,9 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
*custom_data, stored_type_, domain_size, initializer);
}
if (success) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
}
return success;
}
@@ -644,7 +645,9 @@ WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
void *data_new = CustomData_duplicate_referenced_layer_named(
custom_data, stored_type_, layer.name, domain_size);
if (data_old != data_new) {
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
}
return {as_write_attribute_(layer.data, domain_size), domain_};
}
@@ -666,7 +669,9 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const int domain_size = component.attribute_domain_size(domain_);
CustomData_free_layer(custom_data, stored_type_, domain_size, i);
- custom_data_access_.update_custom_data_pointers(component);
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(component);
+ }
return true;
}
}
@@ -734,7 +739,6 @@ CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes
std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id) const
{
- BLI_assert(size_ != 0);
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
@@ -745,11 +749,6 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at
return {};
}
-/**
- * Return a virtual array for a stored attribute, or a single value virtual array with the default
- * value if the attribute doesn't exist. If no default value is provided, the default value for the
- * type will be used.
- */
GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
const CustomDataType data_type,
const void *default_value) const
@@ -766,15 +765,13 @@ GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
if (attribute->type() == *type) {
return GVArray::ForSpan(*attribute);
}
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
return conversions.try_convert(GVArray::ForSpan(*attribute), *type);
}
std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id)
{
- /* If this assert hits, it most likely means that #reallocate was not called at some point. */
- BLI_assert(size_ != 0);
for (CustomDataLayer &layer : MutableSpan(data.layers, data.totlayer)) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
@@ -821,6 +818,12 @@ void CustomDataAttributes::reallocate(const int size)
CustomData_realloc(&data, size);
}
+void CustomDataAttributes::clear()
+{
+ CustomData_free(&data, size_);
+ size_ = 0;
+}
+
bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback callback,
const AttributeDomain domain) const
{
@@ -1044,10 +1047,6 @@ Set<AttributeIDRef> GeometryComponent::attribute_ids() const
return attributes;
}
-/**
- * \return False if the callback explicitly returned false at any point, otherwise true,
- * meaning the callback made it all the way through.
- */
bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const
{
using namespace blender::bke;
@@ -1112,8 +1111,8 @@ std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray,
const blender::fn::CPPType &to_type)
{
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
return conversions.try_convert(std::move(varray), to_type);
}
@@ -1178,8 +1177,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
if (attribute.varray.type() == *type) {
return attribute;
}
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
+ const blender::bke::DataTypeConversions &conversions =
+ blender::bke::get_implicit_type_conversions();
return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
}
@@ -1200,8 +1199,7 @@ blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeID
return blender::fn::GVArray::ForSingle(*type, domain_size, default_value);
}
-class GVMutableAttribute_For_OutputAttribute
- : public blender::fn::GVMutableArrayImpl_For_GMutableSpan {
+class GVMutableAttribute_For_OutputAttribute : public blender::fn::GVArrayImpl_For_GSpan {
public:
GeometryComponent *component;
std::string attribute_name;
@@ -1210,7 +1208,7 @@ class GVMutableAttribute_For_OutputAttribute
GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
GeometryComponent &component,
const AttributeIDRef &attribute_id)
- : blender::fn::GVMutableArrayImpl_For_GMutableSpan(data), component(&component)
+ : blender::fn::GVArrayImpl_For_GSpan(data), component(&component)
{
if (attribute_id.is_named()) {
this->attribute_name = attribute_id.name();
@@ -1300,7 +1298,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component,
const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
- const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
+ const DataTypeConversions &conversions = get_implicit_type_conversions();
if (component.attribute_is_builtin(attribute_id)) {
const StringRef attribute_name = attribute_id.name();
@@ -1409,23 +1407,27 @@ OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
namespace blender::bke {
-GVArray AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &UNUSED(scope)) const
+GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &UNUSED(scope)) const
{
if (const GeometryComponentFieldContext *geometry_context =
dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
const GeometryComponent &component = geometry_context->geometry_component();
const AttributeDomain domain = geometry_context->domain();
- const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- GVArray attribute = component.attribute_try_get_for_read(name_, domain, data_type);
- if (attribute) {
- return attribute;
- }
+ return this->get_varray_for_context(component, domain, mask);
}
return {};
}
+GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const
+{
+ const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ return component.attribute_try_get_for_read(name_, domain, data_type);
+}
+
std::string AttributeFieldInput::socket_inspection_name() const
{
std::stringstream ss;
@@ -1457,25 +1459,20 @@ static StringRef get_random_id_attribute_name(const AttributeDomain domain)
}
}
-GVArray IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const
+GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- const StringRef name = get_random_id_attribute_name(domain);
- GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32);
- if (attribute) {
- BLI_assert(attribute.size() == component.attribute_domain_size(domain));
- return attribute;
- }
- /* Use the index as the fallback if no random ID attribute exists. */
- return fn::IndexFieldInput::get_index_varray(mask, scope);
+ const StringRef name = get_random_id_attribute_name(domain);
+ GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32);
+ if (attribute) {
+ BLI_assert(attribute.size() == component.attribute_domain_size(domain));
+ return attribute;
}
- return {};
+
+ /* Use the index as the fallback if no random ID attribute exists. */
+ return fn::IndexFieldInput::get_index_varray(mask);
}
std::string IDAttributeFieldInput::socket_inspection_name() const
@@ -1495,20 +1492,12 @@ bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr;
}
-GVArray AnonymousAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &UNUSED(scope)) const
+GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- GVArray attribute = component.attribute_try_get_for_read(
- anonymous_id_.get(), domain, data_type);
- return attribute;
- }
- return {};
+ const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ return component.attribute_try_get_for_read(anonymous_id_.get(), domain, data_type);
}
std::string AnonymousAttributeFieldInput::socket_inspection_name() const
@@ -1533,3 +1522,5 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
}
} // namespace blender::bke
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/autoexec.c b/source/blender/blenkernel/intern/autoexec.c
index 3aec646b024..ed2b4e4ab1b 100644
--- a/source/blender/blenkernel/intern/autoexec.c
+++ b/source/blender/blenkernel/intern/autoexec.c
@@ -36,10 +36,6 @@
#include "BKE_autoexec.h" /* own include */
-/**
- * \param path: The path to check against.
- * \return Success
- */
bool BKE_autoexec_match(const char *path)
{
bPathCompare *path_cmp;
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index fb65a9bec7e..b914b0cdf66 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -71,7 +71,6 @@ UserDef U;
/** \name Blender Free on Exit
* \{ */
-/* only to be called on exit blender */
void BKE_blender_free(void)
{
/* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
@@ -272,10 +271,6 @@ static void userdef_free_addons(UserDef *userdef)
BLI_listbase_clear(&userdef->addons);
}
-/**
- * When loading a new userdef from file,
- * or when exiting Blender.
- */
void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
{
#define U BLI_STATIC_ASSERT(false, "Global 'U' not allowed, only use arguments passed in!")
@@ -310,10 +305,6 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
/** \name Blender Preferences (Application Templates)
* \{ */
-/**
- * Write U from userdef.
- * This function defines which settings a template will override for the user preferences.
- */
void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *userdef_b)
{
/* TODO:
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index f8b943d3479..211d7f693d4 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -38,6 +38,7 @@
#include "BKE_blender_copybuffer.h" /* own include */
#include "BKE_blendfile.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_layer.h"
@@ -57,25 +58,16 @@
/** \name Copy/Paste `.blend`, partial saves.
* \{ */
-/** Initialize a copy operation. */
void BKE_copybuffer_copy_begin(Main *bmain_src)
{
BKE_blendfile_write_partial_begin(bmain_src);
}
-/** Mark an ID to be copied. Should only be called after a call to #BKE_copybuffer_copy_begin. */
void BKE_copybuffer_copy_tag_ID(ID *id)
{
BKE_blendfile_write_partial_tag_ID(id, true);
}
-/**
- * Finalize a copy operation into given .blend file 'buffer'.
- *
- * \param filename: Full path to the .blend file used as copy/paste buffer.
- *
- * \return true on success, false otherwise.
- */
bool BKE_copybuffer_copy_end(Main *bmain_src, const char *filename, ReportList *reports)
{
const int write_flags = 0;
@@ -88,63 +80,60 @@ bool BKE_copybuffer_copy_end(Main *bmain_src, const char *filename, ReportList *
return retval;
}
-/**
- * Paste datablocks from the given .blend file 'buffer' (i.e. append them).
- *
- * Unlike #BKE_copybuffer_paste, it does not perform any instantiation of collections/objects/etc.
- *
- * \param libname: Full path to the .blend file used as copy/paste buffer.
- * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
- *
- * \return true on success, false otherwise.
- */
+/* Common helper for paste functions. */
+static void copybuffer_append(BlendfileLinkAppendContext *lapp_context,
+ Main *bmain,
+ ReportList *reports)
+{
+ /* Tag existing IDs in given `bmain_dst` as already existing. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ BKE_blendfile_link(lapp_context, reports);
+
+ /* Mark all library linked objects to be updated. */
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* Append, rather than linking */
+ BKE_blendfile_append(lapp_context, reports);
+
+ /* This must be unset, otherwise these object won't link into other scenes from this blend
+ * file. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* Recreate dependency graph to include new objects. */
+ DEG_relations_tag_update(bmain);
+}
+
bool BKE_copybuffer_read(Main *bmain_dst,
const char *libname,
ReportList *reports,
const uint64_t id_types_mask)
{
- BlendFileReadReport bf_reports = {.reports = reports};
- BlendHandle *bh = BLO_blendhandle_from_file(libname, &bf_reports);
- if (bh == NULL) {
- /* Error reports will have been made by BLO_blendhandle_from_file(). */
- return false;
- }
- /* Here appending/linking starts. */
+ /* Note: No recursive append here (no `BLO_LIBLINK_APPEND_RECURSIVE`), external linked data
+ * should remain linked. */
const int flag = 0;
const int id_tag_extra = 0;
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init(&liblink_params, bmain_dst, flag, id_tag_extra);
- Main *mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
- BLO_library_link_copypaste(mainl, bh, id_types_mask);
- BLO_library_link_end(mainl, &bh, &liblink_params);
- /* Mark all library linked objects to be updated. */
- BKE_main_lib_objects_recalc_all(bmain_dst);
- IMB_colormanagement_check_file_config(bmain_dst);
- /* Append, rather than linking. */
- Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath_abs));
- BKE_library_make_local(bmain_dst, lib, NULL, true, false);
- /* Important we unset, otherwise these object won't
- * link into other scenes from this blend file.
- */
- BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
- BLO_blendhandle_close(bh);
+
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
+
+ const int num_pasted = BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ lapp_context, reports, id_types_mask, 0);
+ if (num_pasted == BLENDFILE_LINK_APPEND_INVALID) {
+ BKE_blendfile_link_append_context_free(lapp_context);
+ return false;
+ }
+
+ copybuffer_append(lapp_context, bmain_dst, reports);
+
+ BKE_blendfile_link_append_context_free(lapp_context);
return true;
}
-/**
- * Paste datablocks from the given .blend file 'buffer' (i.e. append them).
- *
- * Similar to #BKE_copybuffer_read, but also handles instantiation of collections/objects/etc.
- *
- * \param libname: Full path to the .blend file used as copy/paste buffer.
- * \param flag: A combination of #eBLOLibLinkFlags and ##eFileSel_Params_Flag to control
- * link/append behavior.
- * \note: Ignores #FILE_LINK flag, since it always appends IDs.
- * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer.
- *
- * \return Number of IDs directly pasted from the buffer (does not includes indirectly linked
- * ones).
- */
int BKE_copybuffer_paste(bContext *C,
const char *libname,
const int flag,
@@ -155,59 +144,31 @@ int BKE_copybuffer_paste(bContext *C,
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C); /* may be NULL. */
- Main *mainl = NULL;
- Library *lib;
- BlendHandle *bh;
const int id_tag_extra = 0;
- BlendFileReadReport bf_reports = {.reports = reports};
- bh = BLO_blendhandle_from_file(libname, &bf_reports);
-
- if (bh == NULL) {
- /* error reports will have been made by BLO_blendhandle_from_file() */
- return 0;
- }
-
- BKE_view_layer_base_deselect_all(view_layer);
-
- /* tag everything, all untagged data can be made local
- * its also generally useful to know what is new
- *
- * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+ /* Note: No recursive append here, external linked data should remain linked. */
+ BLI_assert((flag & BLO_LIBLINK_APPEND_RECURSIVE) == 0);
- /* here appending/linking starts */
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init_with_context(
&liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
- mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
-
- const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask);
-
- BLO_library_link_end(mainl, &bh, &liblink_params);
-
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
- /* append, rather than linking */
- lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath_abs));
- BKE_library_make_local(bmain, lib, NULL, true, false);
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
- /* important we unset, otherwise these object won't
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DEG_relations_tag_update(bmain);
+ const int num_pasted = BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ lapp_context, reports, id_types_mask, 0);
+ if (num_pasted == BLENDFILE_LINK_APPEND_INVALID) {
+ BKE_blendfile_link_append_context_free(lapp_context);
+ return 0;
+ }
- /* Tag update the scene to flush base collection settings, since the new object is added to a
- * new (active) collection, not its original collection, thus need recalculation. */
- DEG_id_tag_update(&scene->id, 0);
+ BKE_view_layer_base_deselect_all(view_layer);
- BLO_blendhandle_close(bh);
- /* remove library... */
+ copybuffer_append(lapp_context, bmain, reports);
+ BKE_blendfile_link_append_context_free(lapp_context);
return num_pasted;
}
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 411ece21599..6c443a94def 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -68,7 +68,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
bContext *C)
{
Main *bmain = CTX_data_main(C);
- char mainstr[sizeof(bmain->name)];
+ char mainstr[sizeof(bmain->filepath)];
int success = 0, fileflags;
BLI_strncpy(mainstr, BKE_main_blendfile_path(bmain), sizeof(mainstr)); /* temporal store */
@@ -101,7 +101,7 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu,
/* Restore, bmain has been re-allocated. */
bmain = CTX_data_main(C);
- BLI_strncpy(bmain->name, mainstr, sizeof(bmain->name));
+ STRNCPY(bmain->filepath, mainstr);
G.fileflags = fileflags;
if (success) {
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
index edd89357fd5..b186d376e52 100644
--- a/source/blender/blenkernel/intern/blender_user_menu.c
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -110,3 +110,5 @@ void BKE_blender_user_menu_item_free_list(ListBase *lb)
}
BLI_listbase_clear(lb);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index fc535fc2ad1..6ae19c8036f 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -78,7 +78,9 @@
/** \name High Level `.blend` file read/write.
* \{ */
-static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
+static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data),
+ char *path_dst,
+ const char *path_src)
{
strcpy(path_dst, path_src);
BLI_path_slash_native(path_dst);
@@ -86,13 +88,16 @@ static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const c
}
/* make sure path names are correct for OS */
-static void clean_paths(Main *main)
+static void clean_paths(Main *bmain)
{
- Scene *scene;
-
- BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
-
- for (scene = main->scenes.first; scene; scene = scene->id.next) {
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain,
+ .callback_function = foreach_path_clean_cb,
+ .flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE,
+ .user_data = NULL,
+ });
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
BLI_path_slash_native(scene->r.pic);
}
}
@@ -355,12 +360,12 @@ static void setup_app_data(bContext *C,
/* startup.blend or recovered startup */
if (is_startup) {
- bmain->name[0] = '\0';
+ bmain->filepath[0] = '\0';
}
else if (recover) {
- /* In case of autosave or quit.blend, use original filename instead. */
+ /* In case of autosave or quit.blend, use original filepath instead. */
bmain->recovered = 1;
- BLI_strncpy(bmain->name, bfd->filename, FILE_MAX);
+ STRNCPY(bmain->filepath, bfd->filepath);
}
/* baseflags, groups, make depsgraph, etc */
@@ -447,14 +452,6 @@ static void handle_subversion_warning(Main *main, BlendFileReadReport *reports)
}
}
-/**
- * Shared setup function that makes the data from `bfd` into the current blend file,
- * replacing the contents of #G.main.
- * This uses the bfd #BKE_blendfile_read and similarly named functions.
- *
- * This is done in a separate step so the caller may perform actions after it is known the file
- * loaded correctly but before the file replaces the existing blend file contents.
- */
void BKE_blendfile_read_setup_ex(bContext *C,
BlendFileData *bfd,
const struct BlendFileReadParams *params,
@@ -480,9 +477,6 @@ void BKE_blendfile_read_setup(bContext *C,
BKE_blendfile_read_setup_ex(C, bfd, params, reports, false, NULL);
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- */
struct BlendFileData *BKE_blendfile_read(const char *filepath,
const struct BlendFileReadParams *params,
BlendFileReadReport *reports)
@@ -502,9 +496,6 @@ struct BlendFileData *BKE_blendfile_read(const char *filepath,
return bfd;
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- */
struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
const struct BlendFileReadParams *params,
@@ -520,10 +511,6 @@ struct BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
return bfd;
}
-/**
- * \return Blend file data, this must be passed to #BKE_blendfile_read_setup when non-NULL.
- * \note `memfile` is the undo buffer.
- */
struct BlendFileData *BKE_blendfile_read_from_memfile(Main *bmain,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
@@ -546,10 +533,6 @@ struct BlendFileData *BKE_blendfile_read_from_memfile(Main *bmain,
return bfd;
}
-/**
- * Utility to make a file 'empty' used for startup to optionally give an empty file.
- * Handy for tests.
- */
void BKE_blendfile_read_make_empty(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -568,7 +551,6 @@ void BKE_blendfile_read_make_empty(bContext *C)
FOREACH_MAIN_LISTBASE_END;
}
-/* only read the userdef from a .blend */
UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
{
BlendFileData *bfd;
@@ -671,10 +653,6 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
return userdef;
}
-/**
- * Only write the userdef in a .blend
- * \return success
- */
bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
{
Main *mainb = MEM_callocN(sizeof(Main), "empty main");
@@ -695,13 +673,6 @@ bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
return ok;
}
-/**
- * Only write the userdef in a .blend, merging with the existing blend file.
- * \return success
- *
- * \note In the future we should re-evaluate user preferences,
- * possibly splitting out system/hardware specific prefs.
- */
bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *reports)
{
/* if it fails, overwrite is OK. */
@@ -872,10 +843,6 @@ static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain)
}
}
-/**
- * \param remap_mode: Choose the kind of path remapping or none #eBLO_WritePathRemap.
- * \return Success.
- */
bool BKE_blendfile_write_partial(Main *bmain_src,
const char *filepath,
const int write_flags,
@@ -887,11 +854,12 @@ bool BKE_blendfile_write_partial(Main *bmain_src,
int a, retval;
void *path_list_backup = NULL;
- const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+ const eBPathForeachFlag path_list_flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED |
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
/* This is needed to be able to load that file as a real one later
- * (otherwise main->name will not be set at read time). */
- BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));
+ * (otherwise `main->filepath` will not be set at read time). */
+ STRNCPY(bmain_dst->filepath, bmain_src->filepath);
BLO_main_expander(blendfile_write_partial_cb);
BLO_expand_main(NULL, bmain_src);
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
new file mode 100644
index 00000000000..c265a6e2b7d
--- /dev/null
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -0,0 +1,1615 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ *
+ * High level `.blend` file link/append code,
+ * including linking/appending several IDs from different libraries, handling instantiations of
+ * collections/objects/object-data in current scene.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_collection_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_idtype.h"
+#include "BKE_key.h"
+#include "BKE_layer.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_override.h"
+#include "BKE_lib_query.h"
+#include "BKE_lib_remap.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
+
+#include "BKE_blendfile_link_append.h"
+
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+static CLG_LogRef LOG = {"bke.blendfile_link_append"};
+
+/* -------------------------------------------------------------------- */
+/** \name Link/append context implementation and public management API.
+ * \{ */
+
+typedef struct BlendfileLinkAppendContextItem {
+ /** Name of the ID (without the heading two-chars IDcode). */
+ char *name;
+ /** All libs (from BlendfileLinkAppendContext.libraries) to try to load this ID from. */
+ BLI_bitmap *libraries;
+ /** ID type. */
+ short idcode;
+
+ /** Type of action to perform on this item, and general status tag information.
+ * NOTE: Mostly used by append post-linking processing. */
+ char action;
+ char tag;
+
+ /** Newly linked ID (NULL until it has been successfully linked). */
+ ID *new_id;
+ /** Library ID from which the #new_id has been linked (NULL until it has been successfully
+ * linked). */
+ Library *source_library;
+ /** Opaque user data pointer. */
+ void *userdata;
+} BlendfileLinkAppendContextItem;
+
+/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */
+typedef struct BlendfileLinkAppendContextLibrary {
+ char *path; /* Absolute .blend file path. */
+ BlendHandle *blo_handle; /* Blend file handle, if any. */
+ bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */
+ /* The blendfile report associated with the `blo_handle`, if owned. */
+ BlendFileReadReport bf_reports;
+} BlendfileLinkAppendContextLibrary;
+
+typedef struct BlendfileLinkAppendContext {
+ /** List of library paths to search IDs in. */
+ LinkNodePair libraries;
+ /** List of all ID to try to link from #libraries. */
+ LinkNodePair items;
+ int num_libraries;
+ int num_items;
+ /** Linking/appending parameters. Including `bmain`, `scene`, `viewlayer` and `view3d`. */
+ LibraryLink_Params *params;
+
+ /** Allows to easily find an existing items from an ID pointer. */
+ GHash *new_id_to_item;
+
+ /** Runtime info used by append code to manage re-use of already appended matching IDs. */
+ GHash *library_weak_reference_mapping;
+
+ /** Embedded blendfile and its size, if needed. */
+ const void *blendfile_mem;
+ size_t blendfile_memsize;
+
+ /** Internal 'private' data */
+ MemArena *memarena;
+} BlendfileLinkAppendContext;
+
+typedef struct BlendfileLinkAppendContextCallBack {
+ BlendfileLinkAppendContext *lapp_context;
+ BlendfileLinkAppendContextItem *item;
+ ReportList *reports;
+
+} BlendfileLinkAppendContextCallBack;
+
+/* Actions to apply to an item (i.e. linked ID). */
+enum {
+ LINK_APPEND_ACT_UNSET = 0,
+ LINK_APPEND_ACT_KEEP_LINKED,
+ LINK_APPEND_ACT_REUSE_LOCAL,
+ LINK_APPEND_ACT_MAKE_LOCAL,
+ LINK_APPEND_ACT_COPY_LOCAL,
+};
+
+/* Various status info about an item (i.e. linked ID). */
+enum {
+ /* An indirectly linked ID. */
+ LINK_APPEND_TAG_INDIRECT = 1 << 0,
+};
+
+static BlendHandle *link_append_context_library_blohandle_ensure(
+ BlendfileLinkAppendContext *lapp_context,
+ BlendfileLinkAppendContextLibrary *lib_context,
+ ReportList *reports)
+{
+ if (reports != NULL) {
+ lib_context->bf_reports.reports = reports;
+ }
+
+ char *libname = lib_context->path;
+ BlendHandle *blo_handle = lib_context->blo_handle;
+ if (blo_handle == NULL) {
+ if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
+ blo_handle = BLO_blendhandle_from_memory(lapp_context->blendfile_mem,
+ (int)lapp_context->blendfile_memsize,
+ &lib_context->bf_reports);
+ }
+ else {
+ blo_handle = BLO_blendhandle_from_file(libname, &lib_context->bf_reports);
+ }
+ lib_context->blo_handle = blo_handle;
+ lib_context->blo_handle_is_owned = true;
+ }
+
+ return blo_handle;
+}
+
+static void link_append_context_library_blohandle_release(
+ BlendfileLinkAppendContext *UNUSED(lapp_context),
+ BlendfileLinkAppendContextLibrary *lib_context)
+{
+ if (lib_context->blo_handle_is_owned && lib_context->blo_handle != NULL) {
+ BLO_blendhandle_close(lib_context->blo_handle);
+ lib_context->blo_handle = NULL;
+ }
+}
+
+BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(LibraryLink_Params *params)
+{
+ MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ BlendfileLinkAppendContext *lapp_context = BLI_memarena_calloc(ma, sizeof(*lapp_context));
+
+ lapp_context->params = params;
+ lapp_context->memarena = ma;
+
+ return lapp_context;
+}
+
+void BKE_blendfile_link_append_context_free(BlendfileLinkAppendContext *lapp_context)
+{
+ if (lapp_context->new_id_to_item != NULL) {
+ BLI_ghash_free(lapp_context->new_id_to_item, NULL, NULL);
+ }
+
+ for (LinkNode *liblink = lapp_context->libraries.list; liblink != NULL;
+ liblink = liblink->next) {
+ BlendfileLinkAppendContextLibrary *lib_context = liblink->link;
+ link_append_context_library_blohandle_release(lapp_context, lib_context);
+ }
+
+ BLI_assert(lapp_context->library_weak_reference_mapping == NULL);
+
+ BLI_memarena_free(lapp_context->memarena);
+}
+
+void BKE_blendfile_link_append_context_flag_set(BlendfileLinkAppendContext *lapp_context,
+ const int flag,
+ const bool do_set)
+{
+ if (do_set) {
+ lapp_context->params->flag |= flag;
+ }
+ else {
+ lapp_context->params->flag &= ~flag;
+ }
+}
+
+void BKE_blendfile_link_append_context_embedded_blendfile_set(
+ BlendfileLinkAppendContext *lapp_context, const void *blendfile_mem, int blendfile_memsize)
+{
+ BLI_assert_msg(lapp_context->blendfile_mem == NULL,
+ "Please explicitly clear reference to an embedded blender memfile before "
+ "setting a new one");
+ lapp_context->blendfile_mem = blendfile_mem;
+ lapp_context->blendfile_memsize = (size_t)blendfile_memsize;
+}
+
+void BKE_blendfile_link_append_context_embedded_blendfile_clear(
+ BlendfileLinkAppendContext *lapp_context)
+{
+ lapp_context->blendfile_mem = NULL;
+ lapp_context->blendfile_memsize = 0;
+}
+
+void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *lapp_context,
+ const char *libname,
+ BlendHandle *blo_handle)
+{
+ BLI_assert(lapp_context->items.list == NULL);
+
+ BlendfileLinkAppendContextLibrary *lib_context = BLI_memarena_calloc(lapp_context->memarena,
+ sizeof(*lib_context));
+
+ size_t len = strlen(libname) + 1;
+ char *libpath = BLI_memarena_alloc(lapp_context->memarena, len);
+ BLI_strncpy(libpath, libname, len);
+
+ lib_context->path = libpath;
+ lib_context->blo_handle = blo_handle;
+ lib_context->blo_handle_is_owned = (blo_handle == NULL);
+
+ BLI_linklist_append_arena(&lapp_context->libraries, lib_context, lapp_context->memarena);
+ lapp_context->num_libraries++;
+}
+
+BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
+ BlendfileLinkAppendContext *lapp_context,
+ const char *idname,
+ const short idcode,
+ void *userdata)
+{
+ BlendfileLinkAppendContextItem *item = BLI_memarena_calloc(lapp_context->memarena,
+ sizeof(*item));
+ size_t len = strlen(idname) + 1;
+
+ item->name = BLI_memarena_alloc(lapp_context->memarena, len);
+ BLI_strncpy(item->name, idname, len);
+ item->idcode = idcode;
+ item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_context->memarena, lapp_context->num_libraries);
+
+ item->new_id = NULL;
+ item->action = LINK_APPEND_ACT_UNSET;
+ item->userdata = userdata;
+
+ BLI_linklist_append_arena(&lapp_context->items, item, lapp_context->memarena);
+ lapp_context->num_items++;
+
+ return item;
+}
+
+int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
+ BlendfileLinkAppendContext *lapp_context,
+ ReportList *reports,
+ const uint64_t id_types_filter,
+ const int library_index)
+{
+ int id_num = 0;
+ int id_code_iter = 0;
+ short id_code;
+
+ LinkNode *lib_context_link = BLI_linklist_find(lapp_context->libraries.list, library_index);
+ BlendfileLinkAppendContextLibrary *lib_context = lib_context_link->link;
+ BlendHandle *blo_handle = link_append_context_library_blohandle_ensure(
+ lapp_context, lib_context, reports);
+
+ if (blo_handle == NULL) {
+ return BLENDFILE_LINK_APPEND_INVALID;
+ }
+
+ const bool use_assets_only = (lapp_context->params->flag & FILE_ASSETS_ONLY) != 0;
+
+ while ((id_code = BKE_idtype_idcode_iter_step(&id_code_iter))) {
+ if (!BKE_idtype_idcode_is_linkable(id_code) ||
+ (id_types_filter != 0 &&
+ (BKE_idtype_idcode_to_idfilter(id_code) & id_types_filter) == 0)) {
+ continue;
+ }
+
+ int id_names_num;
+ LinkNode *id_names_list = BLO_blendhandle_get_datablock_names(
+ blo_handle, id_code, use_assets_only, &id_names_num);
+
+ for (LinkNode *link_next = NULL; id_names_list != NULL; id_names_list = link_next) {
+ link_next = id_names_list->next;
+
+ char *id_name = id_names_list->link;
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, id_name, id_code, NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(
+ lapp_context, item, library_index);
+
+ MEM_freeN(id_name);
+ MEM_freeN(id_names_list);
+ }
+
+ id_num += id_names_num;
+ }
+
+ return id_num;
+}
+
+void BKE_blendfile_link_append_context_item_library_index_enable(
+ BlendfileLinkAppendContext *UNUSED(lapp_context),
+ BlendfileLinkAppendContextItem *item,
+ const int library_index)
+{
+ BLI_BITMAP_ENABLE(item->libraries, library_index);
+}
+
+bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context)
+{
+ return lapp_context->num_items == 0;
+}
+
+void *BKE_blendfile_link_append_context_item_userdata_get(
+ BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item)
+{
+ return item->userdata;
+}
+
+ID *BKE_blendfile_link_append_context_item_newid_get(
+ BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item)
+{
+ return item->new_id;
+}
+
+short BKE_blendfile_link_append_context_item_idcode_get(
+ struct BlendfileLinkAppendContext *UNUSED(lapp_context),
+ struct BlendfileLinkAppendContextItem *item)
+{
+ return item->idcode;
+}
+
+void BKE_blendfile_link_append_context_item_foreach(
+ struct BlendfileLinkAppendContext *lapp_context,
+ BKE_BlendfileLinkAppendContexteItemFunction callback_function,
+ const eBlendfileLinkAppendForeachItemFlag flag,
+ void *userdata)
+{
+ for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT) == 0 &&
+ (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) {
+ continue;
+ }
+ if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT) == 0 &&
+ (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
+ continue;
+ }
+
+ if (!callback_function(lapp_context, item, userdata)) {
+ break;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library link/append helper functions.
+ *
+ * \{ */
+
+/* Struct gathering all required data to handle instantiation of loose data-blocks. */
+typedef struct LooseDataInstantiateContext {
+ BlendfileLinkAppendContext *lapp_context;
+
+ /* The collection in which to add loose collections/objects. */
+ Collection *active_collection;
+} LooseDataInstantiateContext;
+
+static bool object_in_any_scene(Main *bmain, Object *ob)
+{
+ LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
+ if (BKE_scene_object_find(sce, ob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool object_in_any_collection(Main *bmain, Object *ob)
+{
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ if (BKE_collection_has_object(collection, ob)) {
+ return true;
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->master_collection != NULL &&
+ BKE_collection_has_object(scene->master_collection, ob)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context,
+ BlendfileLinkAppendContextItem *item)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ /* In linking case, we always want to handle instantiation. */
+ if (lapp_context->params->flag & FILE_LINK) {
+ return item->new_id;
+ }
+
+ /* We consider that if we either kept it linked, or re-used already local data, instantiation
+ * status of those should not be modified. */
+ if (!ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_MAKE_LOCAL)) {
+ return NULL;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ return NULL;
+ }
+
+ if (item->action == LINK_APPEND_ACT_COPY_LOCAL) {
+ BLI_assert(ID_IS_LINKED(id));
+ id = id->newid;
+ if (id == NULL) {
+ return NULL;
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+ return id;
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+ return id;
+}
+
+static void loose_data_instantiate_ensure_active_collection(
+ LooseDataInstantiateContext *instantiate_context)
+{
+
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = instantiate_context->lapp_context->params->bmain;
+ Scene *scene = instantiate_context->lapp_context->params->context.scene;
+ ViewLayer *view_layer = instantiate_context->lapp_context->params->context.view_layer;
+
+ /* Find or add collection as needed. */
+ if (instantiate_context->active_collection == NULL) {
+ if (lapp_context->params->flag & FILE_ACTIVE_COLLECTION) {
+ LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
+ instantiate_context->active_collection = lc->collection;
+ }
+ else {
+ if (lapp_context->params->flag & FILE_LINK) {
+ instantiate_context->active_collection = BKE_collection_add(
+ bmain, scene->master_collection, DATA_("Linked Data"));
+ }
+ else {
+ instantiate_context->active_collection = BKE_collection_add(
+ bmain, scene->master_collection, DATA_("Appended Data"));
+ }
+ }
+ }
+}
+
+static void loose_data_instantiate_object_base_instance_init(Main *bmain,
+ Collection *collection,
+ Object *ob,
+ ViewLayer *view_layer,
+ const View3D *v3d,
+ const int flag,
+ bool set_active)
+{
+ /* Auto-select and appending. */
+ if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) {
+ /* While in general the object should not be manipulated,
+ * when the user requests the object to be selected, ensure it's visible and selectable. */
+ ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT);
+ }
+
+ BKE_collection_object_add(bmain, collection, ob);
+
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (v3d != NULL) {
+ base->local_view_bits |= v3d->local_view_uuid;
+ }
+
+ if (flag & FILE_AUTOSELECT) {
+ /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */
+ BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK));
+ if (base->flag & BASE_SELECTABLE) {
+ base->flag |= BASE_SELECTED;
+ }
+ }
+
+ if (set_active) {
+ view_layer->basact = base;
+ }
+
+ BKE_scene_object_base_flag_sync_from_base(base);
+}
+
+/* Tag obdata that actually need to be instantiated (those referenced by an object do not, since
+ * the object will be instantiated instead if needed. */
+static void loose_data_instantiate_obdata_preprocess(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ LinkNode *itemlink;
+
+ /* First pass on obdata to enable their instantiation by default, then do a second pass on
+ * objects to clear it for any obdata already in use. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL) {
+ continue;
+ }
+ const ID_Type idcode = GS(id->name);
+ if (!OB_DATA_SUPPORT_ID(idcode)) {
+ continue;
+ }
+
+ id->tag |= LIB_TAG_DOIT;
+ }
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+
+ Object *ob = (Object *)id;
+ Object *new_ob = (Object *)id->newid;
+ if (ob->data != NULL) {
+ ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT;
+ }
+ if (new_ob != NULL && new_ob->data != NULL) {
+ ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+}
+
+/* Test whether some ancestor collection is also tagged for instantiation (return true) or not
+ * (return false). */
+static bool loose_data_instantiate_collection_parents_check_recursive(Collection *collection)
+{
+ for (CollectionParent *parent_collection = collection->parents.first; parent_collection != NULL;
+ parent_collection = parent_collection->next) {
+ if ((parent_collection->collection->id.tag & LIB_TAG_DOIT) != 0) {
+ return true;
+ }
+ if (loose_data_instantiate_collection_parents_check_recursive(parent_collection->collection)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void loose_data_instantiate_collection_process(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ Scene *scene = lapp_context->params->context.scene;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ const bool do_append = (lapp_context->params->flag & FILE_LINK) == 0;
+ const bool do_instantiate_as_empty = (lapp_context->params->flag &
+ BLO_LIBLINK_COLLECTION_INSTANCE) != 0;
+
+ /* NOTE: For collections we only view_layer-instantiate duplicated collections that have
+ * non-instantiated objects in them.
+ * NOTE: Also avoid view-layer-instantiating of collections children of other instantiated
+ * collections. This is why we need two passes here. */
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_GR) {
+ continue;
+ }
+
+ /* Forced instantiation of indirectly appended collections is not wanted. Users can now
+ * easily instantiate collections (and their objects) as needed by themselves. See T67032. */
+ /* We need to check that objects in that collections are already instantiated in a scene.
+ * Otherwise, it's better to add the collection to the scene's active collection, than to
+ * instantiate its objects in active scene's collection directly. See T61141.
+ *
+ * NOTE: We only check object directly into that collection, not recursively into its
+ * children.
+ */
+ Collection *collection = (Collection *)id;
+ /* Always consider adding collections directly selected by the user. */
+ bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0;
+ /* In linking case, do not enforce instantiating non-directly linked collections/objects.
+ * This avoids cluttering the ViewLayers, user can instantiate themselves specific collections
+ * or objects easily from the Outliner if needed. */
+ if (!do_add_collection && do_append) {
+ LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
+ Object *ob = coll_ob->ob;
+ if (!object_in_any_scene(bmain, ob)) {
+ do_add_collection = true;
+ break;
+ }
+ }
+ }
+ if (do_add_collection) {
+ collection->id.tag |= LIB_TAG_DOIT;
+ }
+ }
+
+ /* Second loop to actually instantiate collections tagged as such in first loop, unless some of
+ * their ancestor is also instantiated in case this is not an empty-instantiation. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_GR) {
+ continue;
+ }
+
+ Collection *collection = (Collection *)id;
+ bool do_add_collection = (id->tag & LIB_TAG_DOIT) != 0;
+
+ /* When instantiated into view-layer, do not add collections if one of their parents is also
+ * instantiated. In case of empty-instantiation though, instantiation of all user-selected
+ * collections is the desired behavior. */
+ if (!do_add_collection ||
+ (!do_instantiate_as_empty &&
+ loose_data_instantiate_collection_parents_check_recursive(collection))) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ /* In case user requested instantiation of collections as empties, do so for the one they
+ * explicitly selected (originally directly linked IDs) only. */
+ if (do_instantiate_as_empty && (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) {
+ /* BKE_object_add(...) messes with the selection. */
+ Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
+ ob->type = OB_EMPTY;
+ ob->empty_drawsize = U.collection_instance_empty_size;
+
+ const bool set_selected = (lapp_context->params->flag & FILE_AUTOSELECT) != 0;
+ /* TODO: why is it OK to make this active here but not in other situations?
+ * See other callers of #object_base_instance_init */
+ const bool set_active = set_selected;
+ loose_data_instantiate_object_base_instance_init(
+ bmain, active_collection, ob, view_layer, v3d, lapp_context->params->flag, set_active);
+
+ /* Assign the collection. */
+ ob->instance_collection = collection;
+ id_us_plus(&collection->id);
+ ob->transflag |= OB_DUPLICOLLECTION;
+ copy_v3_v3(ob->loc, scene->cursor.location);
+ }
+ else {
+ /* Add collection as child of active collection. */
+ BKE_collection_child_add(bmain, active_collection, collection);
+
+ if ((lapp_context->params->flag & FILE_AUTOSELECT) != 0) {
+ LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
+ Object *ob = coll_ob->ob;
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ base->flag |= BASE_SELECTED;
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void loose_data_instantiate_object_process(LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ /* Do NOT make base active here! screws up GUI stuff,
+ * if you want it do it at the editor level. */
+ const bool object_set_active = false;
+
+ /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
+ * anywhere. */
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+
+ Object *ob = (Object *)id;
+
+ if (object_in_any_collection(bmain, ob)) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ CLAMP_MIN(ob->id.us, 0);
+ ob->mode = OB_MODE_OBJECT;
+
+ loose_data_instantiate_object_base_instance_init(bmain,
+ active_collection,
+ ob,
+ view_layer,
+ v3d,
+ lapp_context->params->flag,
+ object_set_active);
+ }
+}
+
+static void loose_data_instantiate_obdata_process(LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+ Scene *scene = lapp_context->params->context.scene;
+ ViewLayer *view_layer = lapp_context->params->context.view_layer;
+ const View3D *v3d = lapp_context->params->context.v3d;
+
+ /* Do NOT make base active here! screws up GUI stuff,
+ * if you want it do it at the editor level. */
+ const bool object_set_active = false;
+
+ LinkNode *itemlink;
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL) {
+ continue;
+ }
+ const ID_Type idcode = GS(id->name);
+ if (!OB_DATA_SUPPORT_ID(idcode)) {
+ continue;
+ }
+ if ((id->tag & LIB_TAG_DOIT) == 0) {
+ continue;
+ }
+
+ loose_data_instantiate_ensure_active_collection(instantiate_context);
+ Collection *active_collection = instantiate_context->active_collection;
+
+ const int type = BKE_object_obdata_to_type(id);
+ BLI_assert(type != -1);
+ Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
+ ob->data = id;
+ id_us_plus(id);
+ BKE_object_materials_test(bmain, ob, ob->data);
+
+ loose_data_instantiate_object_base_instance_init(bmain,
+ active_collection,
+ ob,
+ view_layer,
+ v3d,
+ lapp_context->params->flag,
+ object_set_active);
+
+ copy_v3_v3(ob->loc, scene->cursor.location);
+
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+}
+
+static void loose_data_instantiate_object_rigidbody_postprocess(
+ LooseDataInstantiateContext *instantiate_context)
+{
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ Main *bmain = lapp_context->params->bmain;
+
+ LinkNode *itemlink;
+ /* Add rigid body objects and constraints to current RB world(s). */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = loose_data_instantiate_process_check(instantiate_context, item);
+ if (id == NULL || GS(id->name) != ID_OB) {
+ continue;
+ }
+ BKE_rigidbody_ensure_local_object(bmain, (Object *)id);
+ }
+}
+
+static void loose_data_instantiate(LooseDataInstantiateContext *instantiate_context)
+{
+ if (instantiate_context->lapp_context->params->context.scene == NULL) {
+ /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself.
+ */
+ return;
+ }
+
+ BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context;
+ const bool do_obdata = (lapp_context->params->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0;
+
+ /* First pass on obdata to enable their instantiation by default, then do a second pass on
+ * objects to clear it for any obdata already in use. */
+ if (do_obdata) {
+ loose_data_instantiate_obdata_preprocess(instantiate_context);
+ }
+
+ /* First do collections, then objects, then obdata. */
+ loose_data_instantiate_collection_process(instantiate_context);
+ loose_data_instantiate_object_process(instantiate_context);
+ if (do_obdata) {
+ loose_data_instantiate_obdata_process(instantiate_context);
+ }
+
+ loose_data_instantiate_object_rigidbody_postprocess(instantiate_context);
+}
+
+static void new_id_to_item_mapping_add(BlendfileLinkAppendContext *lapp_context,
+ ID *id,
+ BlendfileLinkAppendContextItem *item)
+{
+ BLI_ghash_insert(lapp_context->new_id_to_item, id, item);
+
+ /* This ensures that if a liboverride reference is also linked/used by some other appended
+ * data, it gets a local copy instead of being made directly local, so that the liboverride
+ * references remain valid (i.e. linked data). */
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING;
+ }
+}
+
+/* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as
+ * liboverride references as already existing. */
+static void new_id_to_item_mapping_create(BlendfileLinkAppendContext *lapp_context)
+{
+ lapp_context->new_id_to_item = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+
+ new_id_to_item_mapping_add(lapp_context, id, item);
+ }
+}
+
+static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_data)
+{
+ /* NOTE: It is important to also skip liboverride references here, as those should never be made
+ * local. */
+ if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK |
+ IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
+ return IDWALK_RET_NOP;
+ }
+
+ BlendfileLinkAppendContextCallBack *data = cb_data->user_data;
+ ID *id = *cb_data->id_pointer;
+
+ if (id == NULL) {
+ return IDWALK_RET_NOP;
+ }
+
+ if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
+ /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items,
+ * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be
+ * processed, so we need to recursively deal with them here. */
+ /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it
+ * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of
+ * shape-key referencing the shape-key itself). */
+ if (id != cb_data->id_self) {
+ BKE_library_foreach_ID_link(
+ cb_data->bmain, id, foreach_libblock_link_append_callback, data, IDWALK_NOP);
+ }
+ return IDWALK_RET_NOP;
+ }
+
+ /* In linking case, we always consider all linked IDs, even indirectly ones, for instantiation,
+ * so we need to add them all to the items list.
+ *
+ * In appending case, when `do_recursive` is false, we only make local IDs from same
+ * library(-ies) as the initially directly linked ones.
+ *
+ * NOTE: Since in append case, linked IDs are also fully skipped during instantiation step (see
+ * #append_loose_data_instantiate_process_check), we can avoid adding them to the items list
+ * completely. */
+ const bool do_link = (data->lapp_context->params->flag & FILE_LINK) != 0;
+ const bool do_recursive = (data->lapp_context->params->flag & BLO_LIBLINK_APPEND_RECURSIVE) !=
+ 0 ||
+ do_link;
+ if (!do_recursive && cb_data->id_owner->lib != id->lib) {
+ return IDWALK_RET_NOP;
+ }
+
+ BlendfileLinkAppendContextItem *item = BLI_ghash_lookup(data->lapp_context->new_id_to_item, id);
+ if (item == NULL) {
+ item = BKE_blendfile_link_append_context_item_add(
+ data->lapp_context, id->name, GS(id->name), NULL);
+ item->new_id = id;
+ item->source_library = id->lib;
+ /* Since we did not have an item for that ID yet, we know user did not selected it explicitly,
+ * it was rather linked indirectly. This info is important for instantiation of collections. */
+ item->tag |= LINK_APPEND_TAG_INDIRECT;
+ /* In linking case we already know what we want to do with those items. */
+ if (do_link) {
+ item->action = LINK_APPEND_ACT_KEEP_LINKED;
+ }
+ new_id_to_item_mapping_add(data->lapp_context, id, item);
+ }
+
+ /* NOTE: currently there is no need to do anything else here, but in the future this would be
+ * the place to add specific per-usage decisions on how to append an ID. */
+
+ return IDWALK_RET_NOP;
+}
+
+/** \} */
+
+/** \name Library link/append code.
+ * \{ */
+
+void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
+{
+ if (lapp_context->num_items == 0) {
+ /* Nothing to append. */
+ return;
+ }
+
+ Main *bmain = lapp_context->params->bmain;
+
+ BLI_assert((lapp_context->params->flag & FILE_LINK) == 0);
+
+ const bool set_fakeuser = (lapp_context->params->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0;
+ const bool do_reuse_local_id = (lapp_context->params->flag &
+ BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0;
+
+ const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY |
+ ((lapp_context->params->flag &
+ BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != 0 ?
+ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR :
+ 0);
+
+ LinkNode *itemlink;
+
+ new_id_to_item_mapping_create(lapp_context);
+ lapp_context->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain);
+
+ /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
+ * dependencies), this list will grow and we will process those IDs later, leading to a flatten
+ * recursive processing of all the linked dependencies. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(item->userdata == NULL);
+
+ ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ?
+ BKE_main_library_weak_reference_search_item(
+ lapp_context->library_weak_reference_mapping,
+ id->lib->filepath,
+ id->name) :
+ NULL;
+
+ if (item->action != LINK_APPEND_ACT_UNSET) {
+ /* Already set, pass. */
+ }
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name);
+ item->action = LINK_APPEND_ACT_KEEP_LINKED;
+ }
+ else if (do_reuse_local_id && existing_local_id != NULL) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name);
+ item->action = LINK_APPEND_ACT_REUSE_LOCAL;
+ item->userdata = existing_local_id;
+ }
+ else if (id->tag & LIB_TAG_PRE_EXISTING) {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name);
+ item->action = LINK_APPEND_ACT_COPY_LOCAL;
+ }
+ else {
+ CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name);
+ item->action = LINK_APPEND_ACT_MAKE_LOCAL;
+ }
+
+ /* Only check dependencies if we are not keeping linked data, nor re-using existing local data.
+ */
+ if (!ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BlendfileLinkAppendContextCallBack cb_data = {
+ .lapp_context = lapp_context, .item = item, .reports = reports};
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_link_append_callback, &cb_data, IDWALK_NOP);
+ }
+
+ /* If we found a matching existing local id but are not re-using it, we need to properly clear
+ * its weak reference to linked data. */
+ if (existing_local_id != NULL &&
+ !ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BKE_main_library_weak_reference_remove_item(lapp_context->library_weak_reference_mapping,
+ id->lib->filepath,
+ id->name,
+ existing_local_id);
+ }
+ }
+
+ /* Effectively perform required operation on every linked ID. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+
+ ID *local_appended_new_id = NULL;
+ char lib_filepath[FILE_MAX];
+ BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath));
+ char lib_id_name[MAX_ID_NAME];
+ BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name));
+
+ switch (item->action) {
+ case LINK_APPEND_ACT_COPY_LOCAL:
+ BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY);
+ local_appended_new_id = id->newid;
+ break;
+ case LINK_APPEND_ACT_MAKE_LOCAL:
+ BKE_lib_id_make_local(bmain,
+ id,
+ make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL |
+ LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
+ BLI_assert(id->newid == NULL);
+ local_appended_new_id = id;
+ break;
+ case LINK_APPEND_ACT_KEEP_LINKED:
+ /* Nothing to do here. */
+ break;
+ case LINK_APPEND_ACT_REUSE_LOCAL:
+ /* We only need to set `newid` to ID found in previous loop, for proper remapping. */
+ ID_NEW_SET(id, item->userdata);
+ /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */
+ break;
+ case LINK_APPEND_ACT_UNSET:
+ CLOG_ERROR(
+ &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name);
+ break;
+ default:
+ BLI_assert(0);
+ }
+
+ if (local_appended_new_id != NULL) {
+ if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) {
+ BKE_main_library_weak_reference_add_item(lapp_context->library_weak_reference_mapping,
+ lib_filepath,
+ lib_id_name,
+ local_appended_new_id);
+ }
+
+ if (set_fakeuser) {
+ if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) {
+ /* Do not set fake user on objects nor collections (instancing). */
+ id_fake_user_set(local_appended_new_id);
+ }
+ }
+ }
+ }
+
+ BKE_main_library_weak_reference_destroy(lapp_context->library_weak_reference_mapping);
+ lapp_context->library_weak_reference_mapping = NULL;
+
+ /* Remap IDs as needed. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action == LINK_APPEND_ACT_KEEP_LINKED) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ if (ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_REUSE_LOCAL)) {
+ BLI_assert(ID_IS_LINKED(id));
+ id = id->newid;
+ if (id == NULL) {
+ continue;
+ }
+ }
+
+ BLI_assert(!ID_IS_LINKED(id));
+
+ BKE_libblock_relink_to_newid(bmain, id, 0);
+ }
+
+ /* Remove linked IDs when a local existing data has been reused instead. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action != LINK_APPEND_ACT_REUSE_LOCAL) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(ID_IS_LINKED(id));
+ BLI_assert(id->newid != NULL);
+
+ id->tag |= LIB_TAG_DOIT;
+ item->new_id = id->newid;
+ }
+ BKE_id_multi_tagged_delete(bmain);
+
+ /* Instantiate newly created (duplicated) IDs as needed. */
+ LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context,
+ .active_collection = NULL};
+ loose_data_instantiate(&instantiate_context);
+
+ /* Attempt to deal with object proxies.
+ *
+ * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not
+ * producing any useful result in any known use case), neither here nor in
+ * `BKE_library_make_local` currently.
+ * Proxies are end of life anyway, so not worth spending time on this. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+
+ if (item->action != LINK_APPEND_ACT_COPY_LOCAL) {
+ continue;
+ }
+
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(ID_IS_LINKED(id));
+
+ /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
+ * from another blend file into this one, even when that blend file contains proxified
+ * armatures that have local references. Since the proxified object needs to be linked
+ * (not local), this will only work when the "Localize all" checkbox is disabled.
+ * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
+ Object *ob = (Object *)id;
+ Object *ob_new = (Object *)id->newid;
+ bool is_local = false, is_lib = false;
+
+ /* Proxies only work when the proxified object is linked-in from a library. */
+ if (!ID_IS_LINKED(ob->proxy)) {
+ CLOG_WARN(&LOG,
+ "Proxy object %s will lose its link to %s, because the "
+ "proxified object is local",
+ id->newid->name,
+ ob->proxy->id.name);
+ continue;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* We can only switch the proxy'ing to a made-local proxy if it is no longer
+ * referred to from a library. Not checking for local use; if new local proxy
+ * was not used locally would be a nasty bug! */
+ if (is_local || is_lib) {
+ CLOG_WARN(&LOG,
+ "Made-local proxy object %s will lose its link to %s, "
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)",
+ id->newid->name,
+ ob->proxy->id.name,
+ is_local,
+ is_lib);
+ }
+ else {
+ /* we can switch the proxy'ing from the linked-in to the made-local proxy.
+ * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
+ * was already allocated by object_make_local() (which called BKE_object_copy). */
+ ob_new->proxy = ob->proxy;
+ ob_new->proxy_group = ob->proxy_group;
+ ob_new->proxy_from = ob->proxy_from;
+ ob_new->proxy->proxy_from = ob_new;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
+ }
+ }
+
+ BKE_main_id_newptr_and_tag_clear(bmain);
+}
+
+void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
+{
+ if (lapp_context->num_items == 0) {
+ /* Nothing to be linked. */
+ return;
+ }
+
+ BLI_assert(lapp_context->num_libraries != 0);
+
+ Main *mainl;
+ Library *lib;
+
+ LinkNode *liblink, *itemlink;
+ int lib_idx, item_idx;
+
+ for (lib_idx = 0, liblink = lapp_context->libraries.list; liblink;
+ lib_idx++, liblink = liblink->next) {
+ BlendfileLinkAppendContextLibrary *lib_context = liblink->link;
+ char *libname = lib_context->path;
+ BlendHandle *blo_handle = link_append_context_library_blohandle_ensure(
+ lapp_context, lib_context, reports);
+
+ if (blo_handle == NULL) {
+ /* Unlikely since we just browsed it, but possible
+ * Error reports will have been made by BLO_blendhandle_from_file() */
+ continue;
+ }
+
+ /* here appending/linking starts */
+
+ mainl = BLO_library_link_begin(&blo_handle, libname, lapp_context->params);
+ lib = mainl->curlib;
+ BLI_assert(lib);
+ UNUSED_VARS_NDEBUG(lib);
+
+ if (mainl->versionfile < 250) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Linking or appending from a very old .blend file format (%d.%d), no animation "
+ "conversion will "
+ "be done! You may want to re-save your lib file with current Blender",
+ mainl->versionfile,
+ mainl->subversionfile);
+ }
+
+ /* For each lib file, we try to link all items belonging to that lib,
+ * and tag those successful to not try to load them again with the other libs. */
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *new_id;
+
+ if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
+ continue;
+ }
+
+ new_id = BLO_library_link_named_part(
+ mainl, &blo_handle, item->idcode, item->name, lapp_context->params);
+
+ if (new_id) {
+ /* If the link is successful, clear item's libs 'todo' flags.
+ * This avoids trying to link same item with other libraries to come. */
+ BLI_bitmap_set_all(item->libraries, false, lapp_context->num_libraries);
+ item->new_id = new_id;
+ item->source_library = new_id->lib;
+ }
+ }
+
+ BLO_library_link_end(mainl, &blo_handle, lapp_context->params);
+ link_append_context_library_blohandle_release(lapp_context, lib_context);
+ }
+
+ /* Instantiate newly linked IDs as needed, if no append is scheduled. */
+ if ((lapp_context->params->flag & FILE_LINK) != 0 &&
+ lapp_context->params->context.scene != NULL) {
+ new_id_to_item_mapping_create(lapp_context);
+ /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
+ * dependencies), this list will grow and we will process those IDs later, leading to a flatten
+ * recursive processing of all the linked dependencies. */
+ for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *id = item->new_id;
+ if (id == NULL) {
+ continue;
+ }
+ BLI_assert(item->userdata == NULL);
+
+ BlendfileLinkAppendContextCallBack cb_data = {
+ .lapp_context = lapp_context, .item = item, .reports = reports};
+ BKE_library_foreach_ID_link(lapp_context->params->bmain,
+ id,
+ foreach_libblock_link_append_callback,
+ &cb_data,
+ IDWALK_NOP);
+ }
+
+ LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context,
+ .active_collection = NULL};
+ loose_data_instantiate(&instantiate_context);
+ }
+}
+
+/** \} */
+
+/** \name Library relocating code.
+ * \{ */
+
+static void blendfile_library_relocate_remap(Main *bmain,
+ ID *old_id,
+ ID *new_id,
+ ReportList *reports,
+ const bool do_reload,
+ const short remap_flags)
+{
+ BLI_assert(old_id);
+ if (do_reload) {
+ /* Since we asked for placeholders in case of missing IDs,
+ * we expect to always get a valid one. */
+ BLI_assert(new_id);
+ }
+ if (new_id) {
+ CLOG_INFO(&LOG,
+ 4,
+ "Before remap of %s, old_id users: %d, new_id users: %d",
+ old_id->name,
+ old_id->us,
+ new_id->us);
+ BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
+
+ if (old_id->flag & LIB_FAKEUSER) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+ CLOG_INFO(&LOG,
+ 4,
+ "After remap of %s, old_id users: %d, new_id users: %d",
+ old_id->name,
+ old_id->us,
+ new_id->us);
+
+ /* In some cases, new_id might become direct link, remove parent of library in this case. */
+ if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
+ if (do_reload) {
+ BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */
+ }
+ new_id->lib->parent = NULL;
+ }
+ }
+
+ if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
+ /* Note that this *should* not happen - but better be safe than sorry in this area,
+ * at least until we are 100% sure this cannot ever happen.
+ * Also, we can safely assume names were unique so far,
+ * so just replacing '.' by '~' should work,
+ * but this does not totally rules out the possibility of name collision. */
+ size_t len = strlen(old_id->name);
+ size_t dot_pos;
+ bool has_num = false;
+
+ for (dot_pos = len; dot_pos--;) {
+ char c = old_id->name[dot_pos];
+ if (c == '.') {
+ break;
+ }
+ if (c < '0' || c > '9') {
+ has_num = false;
+ break;
+ }
+ has_num = true;
+ }
+
+ if (has_num) {
+ old_id->name[dot_pos] = '~';
+ }
+ else {
+ len = MIN2(len, MAX_ID_NAME - 7);
+ BLI_strncpy(&old_id->name[len], "~000", 7);
+ }
+
+ id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL);
+
+ BKE_reportf(
+ reports,
+ RPT_WARNING,
+ "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
+ "old one (%d remaining users) had to be kept and was renamed to '%s'",
+ new_id->name,
+ old_id->us,
+ old_id->name);
+ }
+}
+
+void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
+ ReportList *reports,
+ Library *library,
+ const bool do_reload)
+{
+ ListBase *lbarray[INDEX_ID_MAX];
+ int lba_idx;
+
+ LinkNode *itemlink;
+ int item_idx;
+
+ Main *bmain = lapp_context->params->bmain;
+
+ /* All override rules need to be up to date, since there will be no do_version here, otherwise
+ * older, now-invalid rules might be applied and likely fail, or some changes might be missing,
+ * etc. See T93353. */
+ BKE_lib_override_library_main_operations_create(bmain, true);
+
+ /* Remove all IDs to be reloaded from Main. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id = lbarray[lba_idx]->first;
+ const short idcode = id ? GS(id->name) : 0;
+
+ if (!id || !BKE_idtype_idcode_is_linkable(idcode)) {
+ /* No need to reload non-linkable datatypes,
+ * those will get relinked with their 'users ID'. */
+ continue;
+ }
+
+ for (; id; id = id->next) {
+ if (id->lib == library) {
+ BlendfileLinkAppendContextItem *item;
+
+ /* We remove it from current Main, and add it to items to link... */
+ /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
+ BLI_remlink(lbarray[lba_idx], id);
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key *old_key = BKE_key_from_id(id);
+ if (old_key != NULL) {
+ BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
+ }
+
+ item = BKE_blendfile_link_append_context_item_add(lapp_context, id->name + 2, idcode, id);
+ BLI_bitmap_set_all(item->libraries, true, (size_t)lapp_context->num_libraries);
+
+ CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name);
+ }
+ }
+ }
+
+ if (lapp_context->num_items == 0) {
+ /* Early out in case there is nothing to do. */
+ return;
+ }
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* We do not want any instantiation here! */
+ BKE_blendfile_link(lapp_context, reports);
+
+ BKE_main_lock(bmain);
+
+ /* We add back old id to bmain.
+ * We need to do this in a first, separated loop, otherwise some of those may not be handled by
+ * ID remapping, which means they would still reference old data to be deleted... */
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+
+ BLI_assert(old_id);
+ BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
+
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key *old_key = BKE_key_from_id(old_id);
+ if (old_key != NULL) {
+ BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
+ }
+ }
+
+ /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking
+ * code is wrong, we need to redo it here after adding them back to main. */
+ BKE_main_id_refcount_recompute(bmain, false);
+
+ /* Note that in reload case, we also want to replace indirect usages. */
+ const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
+ ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
+ (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+ ID *new_id = item->new_id;
+
+ blendfile_library_relocate_remap(bmain, old_id, new_id, reports, do_reload, remap_flags);
+ if (new_id == NULL) {
+ continue;
+ }
+ /* Usual special code for ShapeKeys snowflakes... */
+ Key **old_key_p = BKE_key_from_id_p(old_id);
+ if (old_key_p == NULL) {
+ continue;
+ }
+ Key *old_key = *old_key_p;
+ Key *new_key = BKE_key_from_id(new_id);
+ if (old_key != NULL) {
+ *old_key_p = NULL;
+ id_us_min(&old_key->id);
+ blendfile_library_relocate_remap(
+ bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags);
+ *old_key_p = old_key;
+ id_us_plus_no_lib(&old_key->id);
+ }
+ }
+
+ BKE_main_unlock(bmain);
+
+ for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
+ item_idx++, itemlink = itemlink->next) {
+ BlendfileLinkAppendContextItem *item = itemlink->link;
+ ID *old_id = item->userdata;
+
+ if (old_id->us == 0) {
+ BKE_id_free(bmain, old_id);
+ }
+ }
+
+ /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable
+ * (shape keys e.g.), so we need another loop here to clear old ones if possible. */
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id, *id_next;
+ for (id = lbarray[lba_idx]->first; id; id = id_next) {
+ id_next = id->next;
+ /* XXX That check may be a bit to generic/permissive? */
+ if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
+ BKE_id_free(bmain, id);
+ }
+ }
+ }
+
+ /* Get rid of no more used libraries... */
+ BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id;
+ for (id = lbarray[lba_idx]->first; id; id = id->next) {
+ if (id->lib) {
+ id->lib->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ }
+ Library *lib, *lib_next;
+ for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
+ lib_next = lib->id.next;
+ if (lib->id.tag & LIB_TAG_DOIT) {
+ id_us_clear_real(&lib->id);
+ if (lib->id.us == 0) {
+ BKE_id_free(bmain, (ID *)lib);
+ }
+ }
+ }
+
+ /* Update overrides of reloaded linked data-blocks. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) ||
+ (id->tag & LIB_TAG_PRE_EXISTING) == 0) {
+ continue;
+ }
+ if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
+ BKE_lib_override_library_update(bmain, id);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Resync overrides if needed. */
+ if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
+ BKE_lib_override_library_main_resync(bmain,
+ lapp_context->params->context.scene,
+ lapp_context->params->context.view_layer,
+ &(struct BlendFileReadReport){
+ .reports = reports,
+ });
+ /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
+ BKE_lib_override_library_main_operations_create(bmain, true);
+ }
+
+ BKE_main_collection_sync(bmain);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index a7257133821..a9f26d00007 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -1061,7 +1061,6 @@ static int boid_condition_is_true(BoidCondition *cond)
}
#endif
-/* determines the velocity the boid wants to have */
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
{
BoidRule *rule;
@@ -1218,7 +1217,6 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
}
}
}
-/* tries to realize the wanted velocity taking all constraints into account */
void boid_body(BoidBrainData *bbd, ParticleData *pa)
{
BoidSettings *boids = bbd->part->boids;
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 9ce58d8129b..85e49774dfd 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -66,6 +66,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_library.h"
@@ -87,213 +88,156 @@
static CLG_LogRef LOG = {"bke.bpath"};
/* -------------------------------------------------------------------- */
-/** \name Check Missing Files
+/** \name Generic File Path Traversal API
* \{ */
-static bool checkMissingFiles_visit_cb(void *userdata,
- char *UNUSED(path_dst),
- const char *path_src)
+void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, ID *id)
{
- ReportList *reports = (ReportList *)userdata;
+ const eBPathForeachFlag flag = bpath_data->flag;
+ const char *absbase = (flag & BKE_BPATH_FOREACH_PATH_ABSOLUTE) ?
+ ID_BLEND_PATH(bpath_data->bmain, id) :
+ NULL;
+ bpath_data->absolute_base_path = absbase;
- if (!BLI_exists(path_src)) {
- BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
+ if ((flag & BKE_BPATH_FOREACH_PATH_SKIP_LINKED) && ID_IS_LINKED(id)) {
+ return;
}
- return false;
-}
-
-/* high level function */
-void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
-{
- BKE_bpath_traverse_main(bmain,
- checkMissingFiles_visit_cb,
- BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_SKIP_PACKED,
- reports);
-}
+ if (id->library_weak_reference != NULL &&
+ (flag & BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES) == 0) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, id->library_weak_reference->library_filepath);
+ }
-/** \} */
+ bNodeTree *embedded_node_tree = ntreeFromID(id);
+ if (embedded_node_tree != NULL) {
+ BKE_bpath_foreach_path_id(bpath_data, &embedded_node_tree->id);
+ }
-/* -------------------------------------------------------------------- */
-/** \name Rebase Relative Paths
- * \{ */
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
-typedef struct BPathRebase_Data {
- const char *basedir_src;
- const char *basedir_dst;
- ReportList *reports;
+ BLI_assert(id_type != NULL);
+ if (id_type == NULL || id_type->foreach_path == NULL) {
+ return;
+ }
- int count_tot;
- int count_changed;
- int count_failed;
-} BPathRebase_Data;
+ id_type->foreach_path(id, bpath_data);
+}
-static bool bpath_relative_rebase_visit_cb(void *userdata, char *path_dst, const char *path_src)
+void BKE_bpath_foreach_path_main(BPathForeachPathData *bpath_data)
{
- BPathRebase_Data *data = (BPathRebase_Data *)userdata;
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bpath_data->bmain, id) {
+ BKE_bpath_foreach_path_id(bpath_data, id);
+ }
+ FOREACH_MAIN_ID_END;
+}
- data->count_tot++;
+bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path)
+{
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- if (BLI_path_is_rel(path_src)) {
- char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
- BLI_strncpy(filepath, path_src, FILE_MAX);
- if (BLI_path_abs(filepath, data->basedir_src)) {
- BLI_path_normalize(NULL, filepath);
+ char path_src_buf[FILE_MAX];
+ const char *path_src;
+ char path_dst[FILE_MAX];
- /* This may fail, if so it's fine to leave absolute since the path is still valid. */
- BLI_path_rel(filepath, data->basedir_dst);
+ if (absolute_base_path) {
+ BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
+ BLI_path_abs(path_src_buf, absolute_base_path);
+ path_src = path_src_buf;
+ }
+ else {
+ path_src = path;
+ }
- BLI_strncpy(path_dst, filepath, FILE_MAX);
- data->count_changed++;
- return true;
- }
+ /* so functions can check old value */
+ BLI_strncpy(path_dst, path, FILE_MAX);
- /* Failed to make relative path absolute. */
- BLI_assert(0);
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
- data->count_failed++;
- return false;
+ if (bpath_data->callback_function(bpath_data, path_dst, path_src)) {
+ BLI_strncpy(path, path_dst, FILE_MAX);
+ return true;
}
- /* Absolute, leave this as-is. */
return false;
}
-void BKE_bpath_relative_rebase(Main *bmain,
- const char *basedir_src,
- const char *basedir_dst,
- ReportList *reports)
+bool BKE_bpath_foreach_path_dirfile_fixed_process(BPathForeachPathData *bpath_data,
+ char *path_dir,
+ char *path_file)
{
- BPathRebase_Data data = {NULL};
- const int flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
-
- BLI_assert(basedir_src[0] != '\0');
- BLI_assert(basedir_dst[0] != '\0');
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- data.basedir_src = basedir_src;
- data.basedir_dst = basedir_dst;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_relative_rebase_visit_cb, flag, (void *)&data);
+ char path_src[FILE_MAX];
+ char path_dst[FILE_MAX];
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
-}
+ BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
-/** \} */
+ /* So that functions can access the old value. */
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
-/* -------------------------------------------------------------------- */
-/** \name Make Paths Relative
- * \{ */
+ if (absolute_base_path) {
+ BLI_path_abs(path_src, absolute_base_path);
+ }
-typedef struct BPathRemap_Data {
- const char *basedir;
- ReportList *reports;
+ if (bpath_data->callback_function(bpath_data, path_dst, (const char *)path_src)) {
+ BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
+ return true;
+ }
- int count_tot;
- int count_changed;
- int count_failed;
-} BPathRemap_Data;
+ return false;
+}
-static bool bpath_relative_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
+bool BKE_bpath_foreach_path_allocated_process(BPathForeachPathData *bpath_data, char **path)
{
- BPathRemap_Data *data = (BPathRemap_Data *)userdata;
+ const char *absolute_base_path = bpath_data->absolute_base_path;
- data->count_tot++;
-
- if (BLI_path_is_rel(path_src)) {
- return false; /* already relative */
- }
+ char path_src_buf[FILE_MAX];
+ const char *path_src;
+ char path_dst[FILE_MAX];
- strcpy(path_dst, path_src);
- BLI_path_rel(path_dst, data->basedir);
- if (BLI_path_is_rel(path_dst)) {
- data->count_changed++;
+ if (absolute_base_path) {
+ BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
+ BLI_path_abs(path_src_buf, absolute_base_path);
+ path_src = path_src_buf;
}
else {
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
- data->count_failed++;
+ path_src = *path;
}
- return true;
-}
-
-void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
-{
- BPathRemap_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
- if (basedir[0] == '\0') {
- CLOG_ERROR(&LOG, "basedir='', this is a bug");
- return;
+ if (bpath_data->callback_function(bpath_data, path_dst, path_src)) {
+ MEM_freeN(*path);
+ (*path) = BLI_strdup(path_dst);
+ return true;
}
- data.basedir = basedir;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_relative_convert_visit_cb, flag, (void *)&data);
-
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
+ return false;
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Make Paths Absolute
+/** \name Check Missing Files
* \{ */
-static bool bpath_absolute_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool check_missing_files_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- BPathRemap_Data *data = (BPathRemap_Data *)userdata;
-
- data->count_tot++;
+ ReportList *reports = (ReportList *)bpath_data->user_data;
- if (BLI_path_is_rel(path_src) == false) {
- return false; /* already absolute */
+ if (!BLI_exists(path_src)) {
+ BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
}
- strcpy(path_dst, path_src);
- BLI_path_abs(path_dst, data->basedir);
- if (BLI_path_is_rel(path_dst) == false) {
- data->count_changed++;
- }
- else {
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
- data->count_failed++;
- }
- return true;
+ return false;
}
-/* similar to BKE_bpath_relative_convert - keep in sync! */
-void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
+void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
{
- BPathRemap_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
-
- if (basedir[0] == '\0') {
- CLOG_ERROR(&LOG, "basedir='', this is a bug");
- return;
- }
-
- data.basedir = basedir;
- data.reports = reports;
-
- BKE_bpath_traverse_main(bmain, bpath_absolute_convert_visit_cb, flag, (void *)&data);
-
- BKE_reportf(reports,
- data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot,
- data.count_changed,
- data.count_failed);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain,
+ .callback_function = check_missing_files_foreach_path_cb,
+ .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED,
+ .user_data = reports});
}
/** \} */
@@ -302,72 +246,79 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re
/** \name Find Missing Files
* \{ */
-/**
- * find this file recursively, use the biggest file so thumbnails don't get used by mistake
- * \param filename_new: the path will be copied here, caller must initialize as empty string.
- * \param dirname: subdir to search
- * \param filename: set this filename
- * \param filesize: filesize for the file
+#define MAX_DIR_RECURSE 16
+#define FILESIZE_INVALID_DIRECTORY -1
+
+/** Find the given filename recursively in the given search directory and its sub-directories.
+ *
+ * \note Use the biggest matching file found, so that thumbnails don't get used by mistake.
+ *
+ * \param search_directory: Directory to search in.
+ * \param filename_src: Search for this filename.
+ * \param r_filename_new: The path of the new found file will be copied here, caller must
+ * initialize as empty string.
+ * \param r_filesize: Size of the file, `FILESIZE_INVALID_DIRECTORY` if search directory could not
+ * be opened.
+ * \param r_recurse_depth: Current recursion depth.
*
- * \returns found: 1/0.
+ * \return true if found, false otherwise.
*/
-#define MAX_RECUR 16
-static bool missing_files_find__recursive(char *filename_new,
- const char *dirname,
- const char *filename,
+static bool missing_files_find__recursive(const char *search_directory,
+ const char *filename_src,
+ char r_filename_new[FILE_MAX],
int64_t *r_filesize,
- int *r_recur_depth)
+ int *r_recurse_depth)
{
- /* file searching stuff */
+ /* TODO: Move this function to BLI_path_utils? The 'biggest size' behavior is quite specific
+ * though... */
DIR *dir;
- struct dirent *de;
BLI_stat_t status;
char path[FILE_MAX];
int64_t size;
bool found = false;
- dir = opendir(dirname);
+ dir = opendir(search_directory);
if (dir == NULL) {
return found;
}
- if (*r_filesize == -1) {
- *r_filesize = 0; /* dir opened fine */
+ if (*r_filesize == FILESIZE_INVALID_DIRECTORY) {
+ *r_filesize = 0; /* The directory opened fine. */
}
- while ((de = readdir(dir)) != NULL) {
-
+ for (struct dirent *de = readdir(dir); de != NULL; de = readdir(dir)) {
if (FILENAME_IS_CURRPAR(de->d_name)) {
continue;
}
- BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
+ BLI_join_dirfile(path, sizeof(path), search_directory, de->d_name);
if (BLI_stat(path, &status) == -1) {
- continue; /* can't stat, don't bother with this file, could print debug info here */
+ CLOG_WARN(&LOG, "Cannot get file status (`stat()`) of '%s'", path);
+ continue;
}
- if (S_ISREG(status.st_mode)) { /* is file */
- if (BLI_path_ncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */
- /* open the file to read its size */
+ if (S_ISREG(status.st_mode)) { /* It is a file. */
+ if (BLI_path_ncmp(filename_src, de->d_name, FILE_MAX) == 0) { /* Names match. */
size = status.st_size;
- if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
+ if ((size > 0) && (size > *r_filesize)) { /* Find the biggest matching file. */
*r_filesize = size;
- BLI_strncpy(filename_new, path, FILE_MAX);
+ BLI_strncpy(r_filename_new, path, FILE_MAX);
found = true;
}
}
}
- else if (S_ISDIR(status.st_mode)) { /* is subdir */
- if (*r_recur_depth <= MAX_RECUR) {
- (*r_recur_depth)++;
+ else if (S_ISDIR(status.st_mode)) { /* It is a sub-directory. */
+ if (*r_recurse_depth <= MAX_DIR_RECURSE) {
+ (*r_recurse_depth)++;
found |= missing_files_find__recursive(
- filename_new, path, filename, r_filesize, r_recur_depth);
- (*r_recur_depth)--;
+ path, filename_src, r_filename_new, r_filesize, r_recurse_depth);
+ (*r_recurse_depth)--;
}
}
}
+
closedir(dir);
return found;
}
@@ -376,37 +327,37 @@ typedef struct BPathFind_Data {
const char *basedir;
const char *searchdir;
ReportList *reports;
- bool find_all;
+ bool find_all; /* Also search for files which current path is still valid. */
} BPathFind_Data;
-static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool missing_files_find_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- BPathFind_Data *data = (BPathFind_Data *)userdata;
+ BPathFind_Data *data = (BPathFind_Data *)bpath_data->user_data;
char filename_new[FILE_MAX];
- int64_t filesize = -1;
- int recur_depth = 0;
- bool found;
+ int64_t filesize = FILESIZE_INVALID_DIRECTORY;
+ int recurse_depth = 0;
+ bool is_found;
- if (data->find_all == false) {
- if (BLI_exists(path_src)) {
- return false;
- }
+ if (!data->find_all && BLI_exists(path_src)) {
+ return false;
}
filename_new[0] = '\0';
- found = missing_files_find__recursive(
- filename_new, data->searchdir, BLI_path_basename(path_src), &filesize, &recur_depth);
+ is_found = missing_files_find__recursive(
+ data->searchdir, BLI_path_basename(path_src), filename_new, &filesize, &recurse_depth);
- if (filesize == -1) { /* could not open dir */
+ if (filesize == FILESIZE_INVALID_DIRECTORY) {
BKE_reportf(data->reports,
RPT_WARNING,
- "Could not open directory '%s'",
+ "Could not open the directory '%s'",
BLI_path_basename(data->searchdir));
return false;
}
- if (found == false) {
+ if (is_found == false) {
BKE_reportf(data->reports,
RPT_WARNING,
"Could not find '%s' in '%s'",
@@ -419,7 +370,7 @@ static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const c
BLI_strncpy(path_dst, filename_new, FILE_MAX);
- /* keep path relative if the previous one was relative */
+ /* Keep the path relative if the previous one was relative. */
if (was_relative) {
BLI_path_rel(path_dst, data->basedir);
}
@@ -433,480 +384,281 @@ void BKE_bpath_missing_files_find(Main *bmain,
const bool find_all)
{
struct BPathFind_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
+ const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED;
data.basedir = BKE_main_blendfile_path(bmain);
data.reports = reports;
data.searchdir = searchpath;
data.find_all = find_all;
- BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data);
+ BKE_bpath_foreach_path_main(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = missing_files_find_foreach_path_cb,
+ .flag = flag,
+ .user_data = &data});
}
+#undef MAX_DIR_RECURSE
+#undef FILESIZE_INVALID_DIRECTORY
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Generic File Path Traversal API
+/** \name Rebase Relative Paths
* \{ */
-/**
- * Run a visitor on a string, replacing the contents of the string as needed.
- */
-static bool rewrite_path_fixed(char *path,
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
+typedef struct BPathRebase_Data {
+ const char *basedir_src;
+ const char *basedir_dst;
+ ReportList *reports;
+
+ int count_tot;
+ int count_changed;
+ int count_failed;
+} BPathRebase_Data;
+
+static bool relative_rebase_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- char path_src_buf[FILE_MAX];
- const char *path_src;
- char path_dst[FILE_MAX];
+ BPathRebase_Data *data = (BPathRebase_Data *)bpath_data->user_data;
- if (absbase) {
- BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
- BLI_path_abs(path_src_buf, absbase);
- path_src = path_src_buf;
+ data->count_tot++;
+
+ if (!BLI_path_is_rel(path_src)) {
+ /* Absolute, leave this as-is. */
+ return false;
}
- else {
- path_src = path;
+
+ char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
+ BLI_strncpy(filepath, path_src, FILE_MAX);
+ if (!BLI_path_abs(filepath, data->basedir_src)) {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
+ data->count_failed++;
+ return false;
}
- /* so functions can check old value */
- BLI_strncpy(path_dst, path, FILE_MAX);
+ BLI_path_normalize(NULL, filepath);
- if (visit_cb(userdata, path_dst, path_src)) {
- BLI_strncpy(path, path_dst, FILE_MAX);
- return true;
- }
+ /* This may fail, if so it's fine to leave absolute since the path is still valid. */
+ BLI_path_rel(filepath, data->basedir_dst);
- return false;
+ BLI_strncpy(path_dst, filepath, FILE_MAX);
+ data->count_changed++;
+ return true;
}
-static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
- char path_file[FILE_MAXFILE],
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
+void BKE_bpath_relative_rebase(Main *bmain,
+ const char *basedir_src,
+ const char *basedir_dst,
+ ReportList *reports)
{
- char path_src[FILE_MAX];
- char path_dst[FILE_MAX];
-
- BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ BPathRebase_Data data = {NULL};
+ const int flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED | BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
- /* so functions can check old value */
- BLI_strncpy(path_dst, path_src, FILE_MAX);
+ BLI_assert(basedir_src[0] != '\0');
+ BLI_assert(basedir_dst[0] != '\0');
- if (absbase) {
- BLI_path_abs(path_src, absbase);
- }
+ data.basedir_src = basedir_src;
+ data.basedir_dst = basedir_dst;
+ data.reports = reports;
- if (visit_cb(userdata, path_dst, (const char *)path_src)) {
- BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
- return true;
- }
+ BKE_bpath_foreach_path_main(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = relative_rebase_foreach_path_cb,
+ .flag = flag,
+ .user_data = &data});
- return false;
+ BKE_reportf(reports,
+ data.count_failed ? RPT_WARNING : RPT_INFO,
+ "Total files %d | Changed %d | Failed %d",
+ data.count_tot,
+ data.count_changed,
+ data.count_failed);
}
-static bool rewrite_path_alloc(char **path,
- BPathVisitor visit_cb,
- const char *absbase,
- void *userdata)
-{
- char path_src_buf[FILE_MAX];
- const char *path_src;
- char path_dst[FILE_MAX];
-
- if (absbase) {
- BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
- BLI_path_abs(path_src_buf, absbase);
- path_src = path_src_buf;
- }
- else {
- path_src = *path;
- }
+/** \} */
- if (visit_cb(userdata, path_dst, path_src)) {
- MEM_freeN(*path);
- (*path) = BLI_strdup(path_dst);
- return true;
- }
+/* -------------------------------------------------------------------- */
+/** \name Make Paths Relative Or Absolute
+ * \{ */
- return false;
-}
+typedef struct BPathRemap_Data {
+ const char *basedir;
+ ReportList *reports;
-typedef struct Seq_callback_data {
- const char *absbase;
- void *bpath_user_data;
- BPathVisitor visit_cb;
- const int flag;
-} Seq_callback_data;
+ int count_tot;
+ int count_changed;
+ int count_failed;
+} BPathRemap_Data;
-static bool seq_rewrite_path_callback(Sequence *seq, void *user_data)
+static bool relative_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- if (SEQ_HAS_PATH(seq)) {
- StripElem *se = seq->strip->stripdata;
- Seq_callback_data *cd = (Seq_callback_data *)user_data;
+ BPathRemap_Data *data = (BPathRemap_Data *)bpath_data->user_data;
- if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
- rewrite_path_fixed_dirfile(
- seq->strip->dir, se->name, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
- else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
- /* might want an option not to loop over all strips */
- unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
- unsigned int i;
-
- if (cd->flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) {
- /* only operate on one path */
- len = MIN2(1u, len);
- }
+ data->count_tot++;
- for (i = 0; i < len; i++, se++) {
- rewrite_path_fixed_dirfile(
- seq->strip->dir, se->name, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
- }
- else {
- /* simple case */
- rewrite_path_fixed(seq->strip->dir, cd->visit_cb, cd->absbase, cd->bpath_user_data);
- }
+ if (BLI_path_is_rel(path_src)) {
+ return false; /* Already relative. */
+ }
+
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
+ BLI_path_rel(path_dst, data->basedir);
+ if (BLI_path_is_rel(path_dst)) {
+ data->count_changed++;
+ }
+ else {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
+ data->count_failed++;
}
return true;
}
-/**
- * Run visitor function 'visit' on all paths contained in 'id'.
- */
-void BKE_bpath_traverse_id(
- Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+static bool absolute_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
+ BPathRemap_Data *data = (BPathRemap_Data *)bpath_data->user_data;
- if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED(id)) {
- return;
- }
+ data->count_tot++;
- if (id->library_weak_reference != NULL) {
- rewrite_path_fixed(
- id->library_weak_reference->library_filepath, visit_cb, absbase, bpath_user_data);
+ if (!BLI_path_is_rel(path_src)) {
+ return false; /* Already absolute. */
}
- switch (GS(id->name)) {
- case ID_IM: {
- Image *ima;
- ima = (Image *)id;
- if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- /* Skip empty file paths, these are typically from generated images and
- * don't make sense to add directories to until the image has been saved
- * once to give it a meaningful value. */
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) &&
- ima->filepath[0]) {
- if (rewrite_path_fixed(ima->filepath, visit_cb, absbase, bpath_user_data)) {
- if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
- if (!BKE_image_has_packedfile(ima) &&
- /* image may have been painted onto (and not saved, T44543) */
- !BKE_image_is_dirty(ima)) {
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
- }
- }
- }
- }
- }
- break;
- }
- case ID_BR: {
- Brush *brush = (Brush *)id;
- if (brush->icon_filepath[0]) {
- rewrite_path_fixed(brush->icon_filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_OB: {
- Object *ob = (Object *)id;
- ModifierData *md;
- ParticleSystem *psys;
-
-#define BPATH_TRAVERSE_POINTCACHE(ptcaches) \
- { \
- PointCache *cache; \
- for (cache = (ptcaches).first; cache; cache = cache->next) { \
- if (cache->flag & PTCACHE_DISK_CACHE) { \
- rewrite_path_fixed(cache->path, visit_cb, absbase, bpath_user_data); \
- } \
- } \
- } \
- (void)0
-
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Fluidsim) {
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
- if (fluidmd->fss) {
- rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
- }
- }
- else if (md->type == eModifierType_Fluid) {
- FluidModifierData *fmd = (FluidModifierData *)md;
- if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
- rewrite_path_fixed(fmd->domain->cache_directory, visit_cb, absbase, bpath_user_data);
- }
- }
- else if (md->type == eModifierType_Cloth) {
- ClothModifierData *clmd = (ClothModifierData *)md;
- BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
- }
- else if (md->type == eModifierType_Ocean) {
- OceanModifierData *omd = (OceanModifierData *)md;
- rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);
- }
- else if (md->type == eModifierType_MeshCache) {
- MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md;
- rewrite_path_fixed(mcmd->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
-
- if (ob->soft) {
- BPATH_TRAVERSE_POINTCACHE(ob->soft->shared->ptcaches);
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- BPATH_TRAVERSE_POINTCACHE(psys->ptcaches);
- }
-
-#undef BPATH_TRAVERSE_POINTCACHE
-
- break;
- }
- case ID_SO: {
- bSound *sound = (bSound *)id;
- if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- rewrite_path_fixed(sound->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_VO: {
- Volume *volume = (Volume *)id;
- if (volume->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- rewrite_path_fixed(volume->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_TXT:
- if (((Text *)id)->filepath) {
- rewrite_path_alloc(&((Text *)id)->filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- case ID_VF: {
- VFont *vfont = (VFont *)id;
- if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- if (BKE_vfont_is_builtin(vfont) == false) {
- rewrite_path_fixed(((VFont *)id)->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- break;
- }
- case ID_MA: {
- Material *ma = (Material *)id;
- bNodeTree *ntree = ma->nodetree;
-
- if (ntree) {
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
- }
- else if (node->type == SH_NODE_TEX_IES) {
- NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
- rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- }
- break;
- }
- case ID_NT: {
- bNodeTree *ntree = (bNodeTree *)id;
- bNode *node;
-
- if (ntree->type == NTREE_SHADER) {
- /* same as lines above */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
- }
- else if (node->type == SH_NODE_TEX_IES) {
- NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
- rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- }
- break;
- }
- case ID_SCE: {
- Scene *scene = (Scene *)id;
- if (scene->ed) {
- Seq_callback_data user_data = {absbase, bpath_user_data, visit_cb, flag};
- SEQ_for_each_callback(&scene->ed->seqbase, seq_rewrite_path_callback, &user_data);
- }
- break;
- }
- case ID_ME: {
- Mesh *me = (Mesh *)id;
- if (me->ldata.external) {
- rewrite_path_fixed(me->ldata.external->filename, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_LI: {
- Library *lib = (Library *)id;
- /* keep packedfile paths always relative to the blend */
- if (lib->packedfile == NULL) {
- if (rewrite_path_fixed(lib->filepath, visit_cb, absbase, bpath_user_data)) {
- BKE_library_filepath_set(bmain, lib, lib->filepath);
- }
- }
- break;
- }
- case ID_MC: {
- MovieClip *clip = (MovieClip *)id;
- rewrite_path_fixed(clip->filepath, visit_cb, absbase, bpath_user_data);
- break;
- }
- case ID_CF: {
- CacheFile *cache_file = (CacheFile *)id;
- rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
- break;
- }
- default:
- /* Nothing to do for other IDs that don't contain file paths. */
- break;
+ BLI_strncpy(path_dst, path_src, FILENAME_MAX);
+ BLI_path_abs(path_dst, data->basedir);
+ if (BLI_path_is_rel(path_dst) == false) {
+ data->count_changed++;
+ }
+ else {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
+ data->count_failed++;
}
+ return true;
}
-void BKE_bpath_traverse_id_list(
- Main *bmain, ListBase *lb, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+static void bpath_absolute_relative_convert(Main *bmain,
+ const char *basedir,
+ ReportList *reports,
+ BPathForeachPathFunctionCallback callback_function)
{
- ID *id;
- for (id = lb->first; id; id = id->next) {
- BKE_bpath_traverse_id(bmain, id, visit_cb, flag, bpath_user_data);
+ BPathRemap_Data data = {NULL};
+ const int flag = BKE_BPATH_FOREACH_PATH_SKIP_LINKED;
+
+ BLI_assert(basedir[0] != '\0');
+ if (basedir[0] == '\0') {
+ CLOG_ERROR(&LOG, "basedir='', this is a bug");
+ return;
}
+
+ data.basedir = basedir;
+ data.reports = reports;
+
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = bmain, .callback_function = callback_function, .flag = flag, .user_data = &data});
+
+ BKE_reportf(reports,
+ data.count_failed ? RPT_WARNING : RPT_INFO,
+ "Total files %d | Changed %d | Failed %d",
+ data.count_tot,
+ data.count_changed,
+ data.count_failed);
}
-void BKE_bpath_traverse_main(Main *bmain,
- BPathVisitor visit_cb,
- const int flag,
- void *bpath_user_data)
+void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
{
- ListBase *lbarray[INDEX_ID_MAX];
- int a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data);
- }
+ bpath_absolute_relative_convert(bmain, basedir, reports, relative_convert_foreach_path_cb);
}
-/**
- * Rewrites a relative path to be relative to the main file - unless the path is
- * absolute, in which case it is not altered.
- */
-bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *path_src)
+void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
{
- /* be sure there is low chance of the path being too short */
- char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
- const char *base_new = ((char **)pathbase_v)[0];
- const char *base_old = ((char **)pathbase_v)[1];
-
- if (BLI_path_is_rel(base_old)) {
- CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
- return false;
- }
-
- /* Make referenced file absolute. This would be a side-effect of
- * BLI_path_normalize, but we do it explicitly so we know if it changed. */
- BLI_strncpy(filepath, path_src, FILE_MAX);
- if (BLI_path_abs(filepath, base_old)) {
- /* Path was relative and is now absolute. Remap.
- * Important BLI_path_normalize runs before the path is made relative
- * because it won't work for paths that start with "//../" */
- BLI_path_normalize(base_new, filepath);
- BLI_path_rel(filepath, base_new);
- BLI_strncpy(path_dst, filepath, FILE_MAX);
- return true;
- }
-
- /* Path was not relative to begin with. */
- return false;
+ bpath_absolute_relative_convert(bmain, basedir, reports, absolute_convert_foreach_path_cb);
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Backup/Restore/Free functions,
+/** \name Backup/Restore/Free paths list functions.
*
- * \note These functions assume the data won't change order.
* \{ */
struct PathStore {
struct PathStore *next, *prev;
};
-static bool bpath_list_append(void *userdata, char *UNUSED(path_dst), const char *path_src)
+static bool bpath_list_append(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- /* store the path and string in a single alloc */
- ListBase *ls = userdata;
+ ListBase *path_list = bpath_data->user_data;
size_t path_size = strlen(path_src) + 1;
+
+ /* NOTE: the PathStore and its string are allocated together in a single alloc. */
struct PathStore *path_store = MEM_mallocN(sizeof(struct PathStore) + path_size, __func__);
char *filepath = (char *)(path_store + 1);
- memcpy(filepath, path_src, path_size);
- BLI_addtail(ls, path_store);
+ BLI_strncpy(filepath, path_src, path_size);
+ BLI_addtail(path_list, path_store);
return false;
}
-static bool bpath_list_restore(void *userdata, char *path_dst, const char *path_src)
+static bool bpath_list_restore(BPathForeachPathData *bpath_data,
+ char *path_dst,
+ const char *path_src)
{
- /* assume ls->first won't be NULL because the number of paths can't change!
- * (if they do caller is wrong) */
- ListBase *ls = userdata;
- struct PathStore *path_store = ls->first;
+ ListBase *path_list = bpath_data->user_data;
+
+ /* `ls->first` should never be NULL, because the number of paths should not change.
+ * If this happens, there is a bug in caller code. */
+ BLI_assert(!BLI_listbase_is_empty(path_list));
+
+ struct PathStore *path_store = path_list->first;
const char *filepath = (char *)(path_store + 1);
- bool ret;
+ bool is_path_changed = false;
- if (STREQ(path_src, filepath)) {
- ret = false;
- }
- else {
+ if (!STREQ(path_src, filepath)) {
BLI_strncpy(path_dst, filepath, FILE_MAX);
- ret = true;
+ is_path_changed = true;
}
- BLI_freelinkN(ls, path_store);
- return ret;
+ BLI_freelinkN(path_list, path_store);
+ return is_path_changed;
}
-/* return ls_handle */
-void *BKE_bpath_list_backup(Main *bmain, const int flag)
+void *BKE_bpath_list_backup(Main *bmain, const eBPathForeachFlag flag)
{
- ListBase *ls = MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *path_list = MEM_callocN(sizeof(ListBase), __func__);
- BKE_bpath_traverse_main(bmain, bpath_list_append, flag, ls);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){.bmain = bmain,
+ .callback_function = bpath_list_append,
+ .flag = flag,
+ .user_data = path_list});
- return ls;
+ return path_list;
}
-void BKE_bpath_list_restore(Main *bmain, const int flag, void *ls_handle)
+void BKE_bpath_list_restore(Main *bmain, const eBPathForeachFlag flag, void *path_list_handle)
{
- ListBase *ls = ls_handle;
+ ListBase *path_list = path_list_handle;
- BKE_bpath_traverse_main(bmain, bpath_list_restore, flag, ls);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){.bmain = bmain,
+ .callback_function = bpath_list_restore,
+ .flag = flag,
+ .user_data = path_list});
}
-void BKE_bpath_list_free(void *ls_handle)
+void BKE_bpath_list_free(void *path_list_handle)
{
- ListBase *ls = ls_handle;
- BLI_assert(BLI_listbase_is_empty(ls)); /* assumes we were used */
- BLI_freelistN(ls);
- MEM_freeN(ls);
+ ListBase *path_list = path_list_handle;
+ /* The whole list should have been consumed by #BKE_bpath_list_restore, see also comment in
+ * #bpath_list_restore. */
+ BLI_assert(BLI_listbase_is_empty(path_list));
+
+ BLI_freelistN(path_list);
+ MEM_freeN(path_list);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/bpath_test.cc b/source/blender/blenkernel/intern/bpath_test.cc
new file mode 100644
index 00000000000..121d47af75f
--- /dev/null
+++ b/source/blender/blenkernel/intern/bpath_test.cc
@@ -0,0 +1,181 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ */
+#include "testing/testing.h"
+
+#include "CLG_log.h"
+
+#include "BKE_bpath.h"
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_text_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+namespace blender::bke::tests {
+
+#ifdef WIN32
+# define ABSOLUTE_ROOT "C:" SEP_STR
+#else
+# define ABSOLUTE_ROOT SEP_STR
+#endif
+
+#define RELATIVE_ROOT "//"
+#define BASE_DIR ABSOLUTE_ROOT "blendfiles" SEP_STR
+#define REBASE_DIR BASE_DIR "rebase" SEP_STR
+
+#define BLENDFILE_NAME "bpath.blend"
+#define BLENDFILE_PATH BASE_DIR BLENDFILE_NAME
+
+#define TEXT_PATH_ITEM "texts" SEP_STR "text.txt"
+#define TEXT_PATH_ABSOLUTE ABSOLUTE_ROOT TEXT_PATH_ITEM
+#define TEXT_PATH_ABSOLUTE_MADE_RELATIVE RELATIVE_ROOT ".." SEP_STR TEXT_PATH_ITEM
+#define TEXT_PATH_RELATIVE RELATIVE_ROOT TEXT_PATH_ITEM
+#define TEXT_PATH_RELATIVE_MADE_ABSOLUTE BASE_DIR TEXT_PATH_ITEM
+
+#define MOVIECLIP_PATH_ITEM "movieclips" SEP_STR "movieclip.avi"
+#define MOVIECLIP_PATH_ABSOLUTE ABSOLUTE_ROOT MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_ABSOLUTE_MADE_RELATIVE RELATIVE_ROOT ".." SEP_STR MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_RELATIVE RELATIVE_ROOT MOVIECLIP_PATH_ITEM
+#define MOVIECLIP_PATH_RELATIVE_MADE_ABSOLUTE BASE_DIR MOVIECLIP_PATH_ITEM
+
+class BPathTest : public testing::Test {
+ public:
+ static void SetUpTestSuite()
+ {
+ CLG_init();
+ BKE_idtype_init();
+ }
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ }
+
+ void SetUp() override
+ {
+ bmain = BKE_main_new();
+ STRNCPY(bmain->filepath, BLENDFILE_PATH);
+
+ BKE_id_new(bmain, ID_TXT, nullptr);
+ BKE_id_new(bmain, ID_MC, nullptr);
+ }
+
+ void TearDown() override
+ {
+ BKE_main_free(bmain);
+ }
+
+ Main *bmain;
+};
+
+TEST_F(BPathTest, rebase_on_relative)
+{
+ // Test on relative paths, should be modified.
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_RELATIVE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_rebase(bmain, BASE_DIR, REBASE_DIR, nullptr);
+
+ EXPECT_STREQ(text->filepath, RELATIVE_ROOT ".." SEP_STR TEXT_PATH_ITEM);
+ EXPECT_STREQ(movie_clip->filepath, RELATIVE_ROOT ".." SEP_STR MOVIECLIP_PATH_ITEM);
+}
+
+TEST_F(BPathTest, rebase_on_absolute)
+{
+ // Test on absolute paths, should not be modified.
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_rebase(bmain, BASE_DIR, REBASE_DIR, nullptr);
+
+ EXPECT_STREQ(text->filepath, TEXT_PATH_ABSOLUTE);
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+}
+
+TEST_F(BPathTest, convert_to_relative)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_relative_convert(bmain, BASE_DIR, nullptr);
+
+ // Already relative path should not be modified.
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
+ // Absolute path should be modified.
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE_MADE_RELATIVE);
+}
+
+TEST_F(BPathTest, convert_to_absolute)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_absolute_convert(bmain, BASE_DIR, nullptr);
+
+ // Relative path should be modified.
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE_MADE_ABSOLUTE);
+ // Already absolute path should not be modified.
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+}
+
+TEST_F(BPathTest, list_backup_restore)
+{
+ Text *text = reinterpret_cast<Text *>(bmain->texts.first);
+ text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
+
+ MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
+
+ void *path_list_handle = BKE_bpath_list_backup(bmain, static_cast<eBPathForeachFlag>(0));
+
+ ListBase *path_list = reinterpret_cast<ListBase *>(path_list_handle);
+ EXPECT_EQ(BLI_listbase_count(path_list), 2);
+
+ MEM_freeN(text->filepath);
+ text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
+ BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_RELATIVE, sizeof(movie_clip->filepath));
+
+ BKE_bpath_list_restore(bmain, static_cast<eBPathForeachFlag>(0), path_list_handle);
+
+ EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
+ EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
+ EXPECT_EQ(BLI_listbase_count(path_list), 0);
+
+ BKE_bpath_list_free(path_list_handle);
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index dc3c2a8e55e..153a65d67db 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -33,6 +33,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -218,6 +219,14 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_texture_mtex_foreach_id(data, &brush->mask_mtex));
}
+static void brush_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Brush *brush = (Brush *)id;
+ if (brush->icon_filepath[0] != '\0') {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, brush->icon_filepath);
+ }
+}
+
static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Brush *brush = (Brush *)id;
@@ -414,6 +423,7 @@ IDTypeInfo IDType_ID_BR = {
.name_plural = "brushes",
.translation_context = BLT_I18NCONTEXT_ID_BRUSH,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = brush_init_data,
.copy_data = brush_copy_data,
@@ -421,6 +431,7 @@ IDTypeInfo IDType_ID_BR = {
.make_local = brush_make_local,
.foreach_id = brush_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = brush_foreach_path,
.owner_get = NULL,
.blend_write = brush_blend_write,
@@ -503,10 +514,6 @@ static void brush_defaults(Brush *brush)
/* Datablock add/copy/free/make_local */
-/**
- * \note Resulting brush will have two users: one as a fake user,
- * another is assumed to be used by the caller.
- */
Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
{
Brush *brush;
@@ -518,7 +525,6 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
return brush;
}
-/* add grease pencil settings */
void BKE_brush_init_gpencil_settings(Brush *brush)
{
if (brush->gpencil_settings == NULL) {
@@ -546,7 +552,6 @@ void BKE_brush_init_gpencil_settings(Brush *brush)
brush->gpencil_settings->curve_rand_value = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-/* add a new gp-brush */
Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eObjectMode mode)
{
Paint *paint = NULL;
@@ -586,7 +591,6 @@ Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eO
return brush;
}
-/* Delete a Brush. */
bool BKE_brush_delete(Main *bmain, Brush *brush)
{
if (brush->id.tag & LIB_TAG_INDIRECT) {
@@ -1320,7 +1324,6 @@ static Brush *gpencil_brush_ensure(
return brush;
}
-/* Create a set of grease pencil Drawing presets. */
void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1422,7 +1425,6 @@ void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool r
}
}
-/* Create a set of grease pencil Vertex Paint presets. */
void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1469,7 +1471,6 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool
}
}
-/* Create a set of grease pencil Sculpt Paint presets. */
void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1544,7 +1545,6 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool
}
}
-/* Create a set of grease pencil Weight Paint presets. */
void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
bool r_new = false;
@@ -1946,9 +1946,6 @@ void BKE_brush_sculpt_reset(Brush *br)
}
}
-/**
- * Library Operations
- */
void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
{
CurveMapping *cumap = NULL;
@@ -1966,10 +1963,6 @@ void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
BKE_curvemapping_changed(cumap, false);
}
-/* Generic texture sampler for 3D painting systems. point has to be either in
- * region space mouse coordinates, or 3d world coordinates for 3D mapping.
- *
- * rgba outputs straight alpha. */
float BKE_brush_sample_tex_3d(const Scene *scene,
const Brush *br,
const float point[3],
@@ -2362,7 +2355,6 @@ void BKE_brush_weight_set(const Scene *scene, Brush *brush, float value)
}
}
-/* scale unprojected radius to reflect a change in the brush's 2D size */
void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
int new_brush_size,
int old_brush_size)
@@ -2375,7 +2367,6 @@ void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
(*unprojected_radius) *= scale;
}
-/* scale brush size to reflect a change in the brush's unprojected radius */
void BKE_brush_scale_size(int *r_brush_size,
float new_unprojected_radius,
float old_unprojected_radius)
@@ -2426,7 +2417,6 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
}
}
-/* Uses the brush curve control to find a strength value */
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
{
float strength = 1.0f;
@@ -2474,8 +2464,7 @@ float BKE_brush_curve_strength(const Brush *br, float p, const float len)
return strength;
}
-/* Uses the brush curve control to find a strength value between 0 and 1 */
-float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len)
+float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len)
{
float strength = BKE_brush_curve_strength(br, p, len);
@@ -2517,7 +2506,6 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
return texcache;
}
-/**** Radial Control ****/
struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient)
{
ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 1f92f834972..a68119fbc1d 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -125,7 +125,7 @@ bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
return false;
}
-BVHCache *bvhcache_init(void)
+BVHCache *bvhcache_init()
{
BVHCache *cache = (BVHCache *)MEM_callocN(sizeof(BVHCache), __func__);
BLI_mutex_init(&cache->mutex);
@@ -147,9 +147,6 @@ static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType typ
item->is_filled = true;
}
-/**
- * frees a bvhcache
- */
void bvhcache_free(BVHCache *bvh_cache)
{
for (int index = 0; index < BVHTREE_MAX_ITEM; index++) {
@@ -184,6 +181,7 @@ static void bvhtree_balance(BVHTree *tree, const bool isolate)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Local Callbacks
* \{ */
@@ -669,9 +667,6 @@ static void bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh *data,
data->vert_allocated = vert_allocated;
}
-/**
- * Builds a BVH-tree where nodes are the vertices of the given `em`.
- */
BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *verts_mask,
@@ -727,13 +722,6 @@ BVHTree *bvhtree_from_editmesh_verts(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a BVH-tree where nodes are the given vertices (NOTE: does not copy given `vert`!).
- * \param vert_allocated: if true, vert freeing will be done when freeing data.
- * \param verts_mask: if not null, true elements give which vert to add to BVH-tree.
- * \param verts_num_active: if >= 0, number of active verts to add to BVH-tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
const MVert *vert,
const int verts_num,
@@ -884,9 +872,6 @@ static void bvhtree_from_mesh_edges_setup_data(BVHTreeFromMesh *data,
data->edge_allocated = edge_allocated;
}
-/**
- * Builds a BVH-tree where nodes are the edges of the given `em`.
- */
BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *edges_mask,
@@ -941,14 +926,6 @@ BVHTree *bvhtree_from_editmesh_edges(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a BVH-tree where nodes are the given edges.
- * \param vert, vert_allocated: if true, elem freeing will be done when freeing data.
- * \param edge, edge_allocated: if true, elem freeing will be done when freeing data.
- * \param edges_mask: if not null, true elements give which vert to add to BVH-tree.
- * \param edges_num_active: if >= 0, number of active edges to add to BVH-tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
const MVert *vert,
const bool vert_allocated,
@@ -1075,15 +1052,6 @@ static void bvhtree_from_mesh_faces_setup_data(BVHTreeFromMesh *data,
data->face_allocated = face_allocated;
}
-/**
- * Builds a BVH-tree where nodes are the given tessellated faces
- * (NOTE: does not copy given mfaces!).
- * \param vert_allocated: if true, vert freeing will be done when freeing data.
- * \param face_allocated: if true, face freeing will be done when freeing data.
- * \param faces_mask: if not null, true elements give which faces to add to BVH-tree.
- * \param faces_num_active: if >= 0, number of active faces to add to BVH-tree
- * (else will be computed from mask).
- */
BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
const MVert *vert,
const bool vert_allocated,
@@ -1257,9 +1225,6 @@ static void bvhtree_from_mesh_looptri_setup_data(BVHTreeFromMesh *data,
data->looptri_allocated = looptri_allocated;
}
-/**
- * Builds a BVH-tree where nodes are the `looptri` faces of the given `bm`.
- */
BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
BMEditMesh *em,
const BLI_bitmap *looptri_mask,
@@ -1314,11 +1279,6 @@ BVHTree *bvhtree_from_editmesh_looptri(
data, em, nullptr, -1, epsilon, tree_type, axis, BVHTREE_FROM_VERTS, nullptr, nullptr);
}
-/**
- * Builds a BVH-tree where nodes are the looptri faces of the given mesh.
- *
- * \note for edit-mesh this is currently a duplicate of #bvhtree_from_mesh_faces_ex
- */
BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
const struct MVert *vert,
const bool vert_allocated,
@@ -1461,12 +1421,6 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
return looptri_mask;
}
-/**
- * Builds or queries a bvhcache for the cache bvhtree of the request type.
- *
- * \note This function only fills a cache, and therefore the mesh argument can
- * be considered logically const. Concurrent access is protected by a mutex.
- */
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const struct Mesh *mesh,
const BVHCacheType bvh_cache_type,
@@ -1650,9 +1604,6 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
return tree;
}
-/**
- * Builds or queries a bvhcache for the cache bvhtree of the request type.
- */
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
@@ -1767,9 +1718,10 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
/** \} */
-/**
- * Frees data allocated by a call to `bvhtree_from_editmesh_*`.
- */
+/* -------------------------------------------------------------------- */
+/** \name Free Functions
+ * \{ */
+
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
{
if (data->tree) {
@@ -1780,9 +1732,6 @@ void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
}
}
-/**
- * Frees data allocated by a call to `bvhtree_from_mesh_*`.
- */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
if (data->tree && !data->cached) {
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index e642bbc9e06..8833f3eabe9 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -40,6 +40,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_cachefile.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -94,6 +95,12 @@ static void cache_file_free_data(ID *id)
BLI_freelistN(&cache_file->object_paths);
}
+static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ CacheFile *cache_file = (CacheFile *)id;
+ BKE_bpath_foreach_path_fixed_process(bpath_data, cache_file->filepath);
+}
+
static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
CacheFile *cache_file = (CacheFile *)id;
@@ -134,6 +141,7 @@ IDTypeInfo IDType_ID_CF = {
.name_plural = "cache_files",
.translation_context = BLT_I18NCONTEXT_ID_CACHEFILE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = cache_file_init_data,
.copy_data = cache_file_copy_data,
@@ -141,6 +149,7 @@ IDTypeInfo IDType_ID_CF = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = cache_file_foreach_path,
.owner_get = NULL,
.blend_write = cache_file_blend_write,
@@ -411,12 +420,6 @@ float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, c
return cache_file->is_sequence ? frame : frame / fps - time_offset;
}
-/**
- * Determine whether the #CacheFile should use a render engine procedural. If so, data is not read
- * from the file and bounding boxes are used to represent the objects in the Scene.
- * Render engines will receive the bounding box as a placeholder but can instead
- * load the data directly if they support it.
- */
bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file,
Scene *scene,
const int dag_eval_mode)
diff --git a/source/blender/blenkernel/intern/callbacks.c b/source/blender/blenkernel/intern/callbacks.c
index 72dd51a940d..992eb896d2d 100644
--- a/source/blender/blenkernel/intern/callbacks.c
+++ b/source/blender/blenkernel/intern/callbacks.c
@@ -115,7 +115,6 @@ void BKE_callback_global_init(void)
callbacks_initialized = true;
}
-/* call on application exit */
void BKE_callback_global_finalize(void)
{
eCbEvent evt;
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index d355de73170..7940936b64a 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -182,6 +182,7 @@ IDTypeInfo IDType_ID_CA = {
.name_plural = "cameras",
.translation_context = BLT_I18NCONTEXT_ID_CAMERA,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = camera_init_data,
.copy_data = camera_copy_data,
@@ -189,6 +190,7 @@ IDTypeInfo IDType_ID_CA = {
.make_local = NULL,
.foreach_id = camera_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = camera_blend_write,
@@ -216,7 +218,6 @@ void *BKE_camera_add(Main *bmain, const char *name)
return cam;
}
-/* get the camera's dof value, takes the dof object into account */
float BKE_camera_object_dof_distance(Object *ob)
{
Camera *cam = (Camera *)ob->data;
@@ -425,7 +426,6 @@ void BKE_camera_params_compute_viewplane(
params->viewplane = viewplane;
}
-/* viewplane is assumed to be already computed */
void BKE_camera_params_compute_matrix(CameraParams *params)
{
rctf viewplane = params->viewplane;
@@ -756,8 +756,6 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
return false;
}
-/* don't move the camera, just yield the fit location */
-/* r_scale only valid/useful for ortho cameras */
bool BKE_camera_view_frame_fit_to_scene(
Depsgraph *depsgraph, const Scene *scene, Object *camera_ob, float r_co[3], float *r_scale)
{
@@ -908,7 +906,6 @@ static void camera_stereo3d_model_matrix(const Object *camera,
}
}
-/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
void BKE_camera_multiview_view_matrix(const RenderData *rd,
const Object *camera,
const bool is_left,
@@ -1031,7 +1028,6 @@ static Object *camera_multiview_advanced(const Scene *scene, Object *camera, con
return camera;
}
-/* returns the camera to be used for render */
Object *BKE_camera_multiview_render(const Scene *scene, Object *camera, const char *viewname)
{
const bool is_multiview = (camera != NULL) && (scene->r.scemode & R_MULTIVIEW) != 0;
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 080a7c90c46..42633ff3809 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -326,6 +326,7 @@ static int do_step_cloth(
/************************************************
* clothModifier_do - main simulation function
************************************************/
+
void clothModifier_do(ClothModifierData *clmd,
Depsgraph *depsgraph,
Scene *scene,
@@ -433,7 +434,6 @@ void clothModifier_do(ClothModifierData *clmd,
clmd->clothObject->last_frame = framenr;
}
-/* frees all */
void cloth_free_modifier(ClothModifierData *clmd)
{
Cloth *cloth = NULL;
@@ -504,7 +504,6 @@ void cloth_free_modifier(ClothModifierData *clmd)
}
}
-/* frees all */
void cloth_free_modifier_extern(ClothModifierData *clmd)
{
Cloth *cloth = NULL;
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 22b939d3cf9..21a9159004f 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -375,6 +375,7 @@ IDTypeInfo IDType_ID_GR = {
.name_plural = "collections",
.translation_context = BLT_I18NCONTEXT_ID_COLLECTION,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = collection_init_data,
.copy_data = collection_copy_data,
@@ -382,6 +383,7 @@ IDTypeInfo IDType_ID_GR = {
.make_local = NULL,
.foreach_id = collection_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = collection_owner_get,
.blend_write = collection_blend_write,
@@ -429,10 +431,6 @@ static Collection *collection_add(Main *bmain,
return collection;
}
-/**
- * Add a collection to a collection ListBase and synchronize all render layers
- * The ListBase is NULL when the collection is to be added to the master collection
- */
Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
{
Collection *collection = collection_add(bmain, collection_parent, name_custom);
@@ -440,12 +438,6 @@ Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const
return collection;
}
-/**
- * Add \a collection_dst to all scene collections that reference object \a ob_src is in.
- * Used to replace an instance object with a collection (library override operator).
- *
- * Logic is very similar to #BKE_collection_object_add_from().
- */
void BKE_collection_add_from_object(Main *bmain,
Scene *scene,
const Object *ob_src,
@@ -468,12 +460,6 @@ void BKE_collection_add_from_object(Main *bmain,
BKE_main_collection_sync(bmain);
}
-/**
- * Add \a collection_dst to all scene collections that reference collection \a collection_src is
- * in.
- *
- * Logic is very similar to #BKE_collection_object_add_from().
- */
void BKE_collection_add_from_collection(Main *bmain,
Scene *scene,
Collection *collection_src,
@@ -507,17 +493,12 @@ void BKE_collection_add_from_collection(Main *bmain,
/** \name Free and Delete Collection
* \{ */
-/** Free (or release) any data used by this collection (does not free the collection itself). */
void BKE_collection_free_data(Collection *collection)
{
BKE_libblock_free_data(&collection->id, false);
collection_free_data(&collection->id);
}
-/**
- * Remove a collection, optionally removing its child objects or moving
- * them to parent collections.
- */
bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
{
/* Master collection is not real datablock, can't be removed. */
@@ -678,14 +659,6 @@ static Collection *collection_duplicate_recursive(Main *bmain,
return collection_new;
}
-/**
- * Make a deep copy (aka duplicate) of the given collection and all of its children, recursively.
- *
- * \warning This functions will clear all \a bmain #ID.idnew pointers, unless \a
- * #LIB_ID_DUPLICATE_IS_SUBPROCESS duplicate option is passed on, in which case caller is
- * responsible to reconstruct collection dependencies information's
- * (i.e. call #BKE_main_collection_sync).
- */
Collection *BKE_collection_duplicate(Main *bmain,
Collection *parent,
Collection *collection,
@@ -744,9 +717,6 @@ Collection *BKE_collection_duplicate(Main *bmain,
/** \name Collection Naming
* \{ */
-/**
- * The automatic/fallback name of a new collection.
- */
void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
{
char *name;
@@ -769,9 +739,6 @@ void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
MEM_freeN(name);
}
-/**
- * The name to show in the interface.
- */
const char *BKE_collection_ui_name_get(struct Collection *collection)
{
if (collection->flag & COLLECTION_IS_MASTER) {
@@ -1127,9 +1094,6 @@ static bool collection_object_remove(Main *bmain,
return true;
}
-/**
- * Add object to collection
- */
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
{
if (ELEM(NULL, collection, ob)) {
@@ -1158,12 +1122,6 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
return true;
}
-/**
- * Add \a ob_dst to all scene collections that reference object \a ob_src is in.
- * Used for copying objects.
- *
- * Logic is very similar to #BKE_collection_add_from_object()
- */
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
{
bool is_instantiated = false;
@@ -1186,9 +1144,6 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O
BKE_main_collection_sync(bmain);
}
-/**
- * Remove object from collection.
- */
bool BKE_collection_object_remove(Main *bmain,
Collection *collection,
Object *ob,
@@ -1236,9 +1191,6 @@ static bool scene_collections_object_remove(
return removed;
}
-/**
- * Remove object from all collections of scene
- */
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
return scene_collections_object_remove(bmain, scene, ob, free_us, NULL);
@@ -1302,18 +1254,6 @@ static void collection_missing_parents_remove(Collection *collection)
}
}
-/**
- * Remove all NULL children from parent collections of changed \a collection.
- * This is used for library remapping, where these pointers have been set to NULL.
- * Otherwise this should never happen.
- *
- * \note caller must ensure #BKE_main_collection_sync_remap() is called afterwards!
- *
- * \param parent_collection: The collection owning the pointers that were remapped. May be \a NULL,
- * in which case whole \a bmain database of collections is checked.
- * \param child_collection: The collection that was remapped to another pointer. May be \a NULL,
- * in which case whole \a bmain database of collections is checked.
- */
void BKE_collections_child_remove_nulls(Main *bmain,
Collection *parent_collection,
Collection *child_collection)
@@ -1358,11 +1298,6 @@ void BKE_collections_child_remove_nulls(Main *bmain,
}
}
-/**
- * Move object from a collection into another
- *
- * If source collection is NULL move it from all the existing collections.
- */
void BKE_collection_object_move(
Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
{
@@ -1437,15 +1372,6 @@ static bool collection_instance_find_recursive(Collection *collection,
return false;
}
-/**
- * Find potential cycles in collections.
- *
- * \param new_ancestor: the potential new owner of given \a collection,
- * or the collection to check if the later is NULL.
- * \param collection: the collection we want to add to \a new_ancestor,
- * may be NULL if we just want to ensure \a new_ancestor does not already have cycles.
- * \return true if a cycle is found.
- */
bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
{
if (collection == new_ancestor) {
@@ -1509,12 +1435,6 @@ static bool collection_cycle_fix_recursive(Main *bmain,
return cycles_found;
}
-/**
- * Find and fix potential cycles in collections.
- *
- * \param collection: The collection to check for existing cycles.
- * \return true if cycles are found and fixed.
- */
bool BKE_collection_cycles_fix(Main *bmain, Collection *collection)
{
return collection_cycle_fix_recursive(bmain, collection, collection) ||
@@ -1627,11 +1547,6 @@ bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *ch
return true;
}
-/**
- * Rebuild parent relationships from child ones, for all children of given \a collection.
- *
- * \note Given collection is assumed to already have valid parents.
- */
void BKE_collection_parent_relations_rebuild(Collection *collection)
{
LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
@@ -1680,9 +1595,6 @@ static void collection_parents_rebuild_recursive(Collection *collection)
}
}
-/**
- * Rebuild parent relationships from child ones, for all collections in given \a bmain.
- */
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
{
/* Only collections not in bmain (master ones in scenes) have no parent... */
@@ -1743,11 +1655,6 @@ static Collection *collection_from_index_recursive(Collection *collection,
return NULL;
}
-/**
- * Return Scene Collection for a given index.
- *
- * The index is calculated from top to bottom counting the children before the siblings.
- */
Collection *BKE_collection_from_index(Scene *scene, const int index)
{
int index_current = 0;
@@ -1791,10 +1698,6 @@ static bool collection_objects_select(ViewLayer *view_layer, Collection *collect
return changed;
}
-/**
- * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
- * Return true if any object was selected.
- */
bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
{
LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer,
@@ -1920,10 +1823,6 @@ static void scene_collections_array(Scene *scene,
scene_collection_callback(collection, scene_collections_build_array, &array);
}
-/**
- * Only use this in non-performance critical situations
- * (it iterates over all scene collections twice)
- */
void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
{
Scene *scene = data_in;
@@ -2065,13 +1964,6 @@ void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
}
}
-/**
- * Generate a new GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
- * all collections of given `scene`.
- *
- * \note This will include objects without a base currently
- * (because they would belong to excluded collections only e.g.).
- */
GSet *BKE_scene_objects_as_gset(Scene *scene, GSet *objects_gset)
{
BLI_Iterator iter;
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 03957d54629..671c6530685 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -78,7 +78,6 @@ typedef struct SelfColDetectData {
* Collision modifier code start
***********************************/
-/* step is limited from 0 (frame start position) to 1 (frame end position) */
void collision_move_object(CollisionModifierData *collmd,
const float step,
const float prevstep,
@@ -1261,9 +1260,6 @@ static void add_collision_object(ListBase *relations,
}
}
-/* Create list of collision relations in the collection or entire scene.
- * This is used by the depsgraph to build relations, as well as faster
- * lookup of colliders during evaluation. */
ListBase *BKE_collision_relations_create(Depsgraph *depsgraph,
Collection *collection,
unsigned int modifier_type)
@@ -1292,8 +1288,6 @@ void BKE_collision_relations_free(ListBase *relations)
}
}
-/* Create effective list of colliders from relations built beforehand.
- * Self will be excluded. */
Object **BKE_collision_objects_create(Depsgraph *depsgraph,
Object *self,
Collection *collection,
@@ -1341,8 +1335,6 @@ void BKE_collision_objects_free(Object **objects)
}
}
-/* Create effective list of colliders from relations built beforehand.
- * Self will be excluded. */
ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collection *collection)
{
ListBase *relations = DEG_get_collision_relations(
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 62b817487fc..b12b19453ae 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -183,7 +183,6 @@ void BKE_curvemapping_set_black_white(CurveMapping *cumap,
/* ***************** operations on single curve ************* */
/* ********** NOTE: requires BKE_curvemapping_changed() call after ******** */
-/* remove specified point */
bool BKE_curvemap_remove_point(CurveMap *cuma, CurveMapPoint *point)
{
CurveMapPoint *cmp;
@@ -213,7 +212,6 @@ bool BKE_curvemap_remove_point(CurveMap *cuma, CurveMapPoint *point)
return (removed != 0);
}
-/* removes with flag set */
void BKE_curvemap_remove(CurveMap *cuma, const short flag)
{
CurveMapPoint *cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
@@ -439,9 +437,6 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
}
}
-/**
- * \param type: eBezTriple_Handle
- */
void BKE_curvemap_handle_set(CurveMap *cuma, int type)
{
int a;
@@ -800,10 +795,10 @@ static void curvemap_make_table(const CurveMapping *cumap, CurveMap *cuma)
cuma->table = cmp;
}
-/* call when you do images etc, needs restore too. also verifies tables */
-/* it uses a flag to prevent premul or free to happen twice */
-void BKE_curvemapping_premultiply(CurveMapping *cumap, int restore)
+void BKE_curvemapping_premultiply(CurveMapping *cumap, bool restore)
{
+ /* It uses a flag to prevent pre-multiply or free to happen twice. */
+
int a;
if (restore) {
@@ -873,7 +868,6 @@ static int sort_curvepoints(const void *a1, const void *a2)
/* ************************ more CurveMapping calls *************** */
-/* NOTE: only does current curvemap! */
void BKE_curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
{
CurveMap *cuma = cumap->cm + cumap->cur;
@@ -965,13 +959,11 @@ void BKE_curvemapping_changed_all(CurveMapping *cumap)
cumap->cur = cur;
}
-/* Reset the view for current curve. */
void BKE_curvemapping_reset_view(CurveMapping *cumap)
{
cumap->curr = cumap->clipr;
}
-/* table should be verified */
float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, float value)
{
/* index in table */
@@ -994,7 +986,6 @@ float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, fl
return (1.0f - fi) * cuma->table[i].y + (fi)*cuma->table[i + 1].y;
}
-/* works with curve 'cur' */
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
{
const CurveMap *cuma = cumap->cm + cur;
@@ -1013,7 +1004,6 @@ float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value
return val;
}
-/* vector case */
void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
{
vecout[0] = BKE_curvemap_evaluateF(cumap, &cumap->cm[0], vecin[0]);
@@ -1021,7 +1011,6 @@ void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], con
vecout[2] = BKE_curvemap_evaluateF(cumap, &cumap->cm[2], vecin[2]);
}
-/* RGB case, no black/white points, no premult */
void BKE_curvemapping_evaluateRGBF(const CurveMapping *cumap,
float vecout[3],
const float vecin[3])
@@ -1052,16 +1041,6 @@ static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap,
vecout[channel_offset[2]] = v2;
}
-/**
- * Same as #BKE_curvemapping_evaluate_premulRGBF
- * but black/bwmul are passed as args for the compositor
- * where they can change per pixel.
- *
- * Use in conjunction with #BKE_curvemapping_set_black_white_ex
- *
- * \param black: Use instead of cumap->black
- * \param bwmul: Use instead of cumap->bwmul
- */
void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
float vecout[3],
const float vecin[3],
@@ -1127,7 +1106,6 @@ void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
}
}
-/* RGB with black/white points and premult. tables are checked */
void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap,
float vecout[3],
const float vecin[3])
@@ -1135,7 +1113,6 @@ void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap,
BKE_curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul);
}
-/* same as above, byte version */
void BKE_curvemapping_evaluate_premulRGB(const CurveMapping *cumap,
unsigned char vecout_byte[3],
const unsigned char vecin_byte[3])
@@ -1262,7 +1239,6 @@ void BKE_curvemapping_curves_blend_write(BlendWriter *writer, const CurveMapping
}
}
-/* cumap itself has been read already. */
void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap)
{
/* flag seems to be able to hang? Maybe old files... not bad to clear anyway */
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 3455baa9292..d284c32b1df 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -123,7 +123,6 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
/* -------------- Naming -------------- */
-/* Find the first available, non-duplicate name for a given constraint */
void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
{
BLI_uniquename(list, con, DATA_("Const"), '.', offsetof(bConstraint, name), sizeof(con->name));
@@ -132,8 +131,6 @@ void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
/* ----------------- Evaluation Loop Preparation --------------- */
/* package an object/bone for use in constraint evaluation */
-/* This function MEM_calloc's a bConstraintOb struct,
- * that will need to be freed after evaluation */
bConstraintOb *BKE_constraints_make_evalob(
Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
{
@@ -211,7 +208,6 @@ bConstraintOb *BKE_constraints_make_evalob(
return cob;
}
-/* cleanup after constraint evaluation */
void BKE_constraints_clear_evalob(bConstraintOb *cob)
{
float delta[4][4], imat[4][4];
@@ -261,10 +257,6 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
/* -------------- Space-Conversion API -------------- */
-/* This function is responsible for the correct transformations/conversions
- * of a matrix from one space to another for constraint evaluation.
- * For now, this is only implemented for Objects and PoseChannels.
- */
void BKE_constraint_mat_convertspace(Object *ob,
bPoseChannel *pchan,
bConstraintOb *cob,
@@ -5556,9 +5548,6 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */
}
-/* This function should be used for getting the appropriate type-info when only
- * a constraint type is known
- */
const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
{
/* initialize the type-info list? */
@@ -5578,9 +5567,6 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
return NULL;
}
-/* This function should always be used to get the appropriate type-info, as it
- * has checks which prevent segfaults in some weird cases.
- */
const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
{
/* only return typeinfo for valid constraints */
@@ -5611,11 +5597,6 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con),
}
}
-/**
- * Free data of a specific constraint if it has any info.
- * be sure to run #BIK_clear_data() when freeing an IK constraint,
- * unless DAG_relations_tag_update is called.
- */
void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
{
if (con->data) {
@@ -5643,7 +5624,6 @@ void BKE_constraint_free_data(bConstraint *con)
BKE_constraint_free_data_ex(con, true);
}
-/* Free all constraints from a constraint-stack */
void BKE_constraints_free_ex(ListBase *list, bool do_id_user)
{
/* Free constraint data and also any extra data */
@@ -5660,7 +5640,6 @@ void BKE_constraints_free(ListBase *list)
BKE_constraints_free_ex(list, true);
}
-/* Remove the specified constraint from the given constraint stack */
bool BKE_constraint_remove(ListBase *list, bConstraint *con)
{
if (con) {
@@ -5686,7 +5665,6 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool
return false;
}
-/* Apply the specified constraint in the given constraint stack */
bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -5920,7 +5898,6 @@ bool BKE_constraint_target_uses_bbone(struct bConstraint *con,
/* ......... */
-/* Add new constraint for the given bone */
bConstraint *BKE_constraint_add_for_pose(Object *ob,
bPoseChannel *pchan,
const char *name,
@@ -5933,7 +5910,6 @@ bConstraint *BKE_constraint_add_for_pose(Object *ob,
return add_new_constraint(ob, pchan, name, type);
}
-/* Add new constraint for the given object */
bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short type)
{
return add_new_constraint(ob, NULL, name, type);
@@ -5941,7 +5917,6 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t
/* ......... */
-/* Run the given callback on all ID-blocks in list of constraints */
void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata)
{
LISTBASE_FOREACH (bConstraint *, con, conlist) {
@@ -6016,7 +5991,6 @@ static void constraint_copy_data_ex(bConstraint *dst,
}
}
-/** Allocate and duplicate a single constraint, outside of any object/pose context. */
bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern)
{
bConstraint *dst = MEM_dupallocN(src);
@@ -6025,7 +5999,6 @@ bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const
return dst;
}
-/* Add a copy of the given constraint for the given bone */
bConstraint *BKE_constraint_copy_for_pose(Object *ob, bPoseChannel *pchan, bConstraint *src)
{
if (pchan == NULL) {
@@ -6037,7 +6010,6 @@ bConstraint *BKE_constraint_copy_for_pose(Object *ob, bPoseChannel *pchan, bCons
return new_con;
}
-/* Add a copy of the given constraint for the given object */
bConstraint *BKE_constraint_copy_for_object(Object *ob, bConstraint *src)
{
bConstraint *new_con = BKE_constraint_duplicate_ex(src, 0, !ID_IS_LINKED(ob));
@@ -6045,7 +6017,6 @@ bConstraint *BKE_constraint_copy_for_object(Object *ob, bConstraint *src)
return new_con;
}
-/* duplicate all of the constraints in a constraint stack */
void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
bConstraint *con, *srccon;
@@ -6074,7 +6045,6 @@ bConstraint *BKE_constraints_find_name(ListBase *list, const char *name)
return BLI_findstring(list, name, offsetof(bConstraint, name));
}
-/* finds the 'active' constraint in a constraint stack */
bConstraint *BKE_constraints_active_get(ListBase *list)
{
@@ -6091,7 +6061,6 @@ bConstraint *BKE_constraints_active_get(ListBase *list)
return NULL;
}
-/* Set the given constraint as the active one (clearing all the others) */
void BKE_constraints_active_set(ListBase *list, bConstraint *con)
{
@@ -6127,7 +6096,6 @@ static bConstraint *constraint_list_find_from_target(ListBase *constraints, bCon
return NULL;
}
-/* Finds the constraint that owns the given target within the object. */
bConstraint *BKE_constraint_find_from_target(Object *ob,
bConstraintTarget *tgt,
bPoseChannel **r_pchan)
@@ -6225,12 +6193,6 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
return orig_con;
}
-/**
- * Check whether given constraint is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param con: May be NULL, in which case we consider it as a non-local constraint case.
- */
bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstraint *con)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
@@ -6239,8 +6201,6 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai
/* -------- Constraints and Proxies ------- */
-/* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL
- * (i.e. added to bone that's proxy-synced in this file) */
void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src)
{
bConstraint *con, *next;
@@ -6257,7 +6217,6 @@ void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src)
}
}
-/* Returns if the owner of the constraint is proxy-protected */
bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
{
/* Currently, constraints can only be on object or bone level */
@@ -6281,13 +6240,6 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
/* -------- Target-Matrix Stuff ------- */
-/* This function is a relic from the prior implementations of the constraints system, when all
- * constraints either had one or no targets. It used to be called during the main constraint
- * solving loop, but is now only used for the remaining cases for a few constraints.
- *
- * None of the actual calculations of the matrices should be done here! Also, this function is
- * not to be used by any new constraints, particularly any that have multiple targets.
- */
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
Scene *scene,
bConstraint *con,
@@ -6364,7 +6316,6 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
}
}
-/* Get the list of targets required for solving a constraint */
void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
bConstraint *con,
bConstraintOb *cob,
@@ -6434,12 +6385,6 @@ void BKE_constraint_custom_object_space_get(float r_mat[4][4], bConstraint *con)
/* ---------- Evaluation ----------- */
-/* This function is called whenever constraints need to be evaluated. Currently, all
- * constraints that can be evaluated are every time this gets run.
- *
- * BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and
- * after running this function, to sort out cob
- */
void BKE_constraints_solve(struct Depsgraph *depsgraph,
ListBase *conlist,
bConstraintOb *cob,
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index c235a1bbb6a..ceaed5d2bba 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -547,12 +547,6 @@ static void data_dir_add(ListBase *lb, const char *member, const bool use_all)
BLI_addtail(lb, link);
}
-/**
- * \param C: Context
- * \param use_store: Use 'C->wm.store'
- * \param use_rna: Use Include the properties from 'RNA_Context'
- * \param use_all: Don't skip values (currently only "scene")
- */
ListBase CTX_data_dir_get_ex(const bContext *C,
const bool use_store,
const bool use_rna,
@@ -1127,13 +1121,6 @@ RenderEngineType *CTX_data_engine_type(const bContext *C)
return RE_engines_find(scene->r.engine);
}
-/**
- * This is tricky. Sometimes the user overrides the render_layer
- * but not the scene_collection. In this case what to do?
- *
- * If the scene_collection is linked to the ViewLayer we use it.
- * Otherwise we fallback to the active one of the ViewLayer.
- */
LayerCollection *CTX_data_layer_collection(const bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 26894495777..6bbb9957b03 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -98,7 +98,6 @@ static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob)
return disabled;
}
-/* disable subsurf temporal, get mapped cos, and enable it */
float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object *obedit))[3]
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -243,10 +242,6 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
}
}
-/**
- * Returns an array of deform matrices for crazy-space correction,
- * and the number of modifiers left.
- */
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 1ff0ca92306..d532ed9e4b2 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -139,7 +139,7 @@ std::optional<std::string> CryptomatteSession::operator[](float encoded_hash) co
return std::nullopt;
}
-CryptomatteSession *BKE_cryptomatte_init(void)
+CryptomatteSession *BKE_cryptomatte_init()
{
CryptomatteSession *session = new CryptomatteSession();
return session;
@@ -212,7 +212,6 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
return blender::bke::cryptomatte::CryptomatteHash(cryptomatte_hash).float_encoded();
}
-/* Find an ID in the given main that matches the given encoded float. */
bool BKE_cryptomatte_find_name(const CryptomatteSession *session,
const float encoded_hash,
char *r_name,
@@ -489,10 +488,6 @@ std::string BKE_cryptomatte_meta_data_key(const StringRef layer_name, const Stri
return "cryptomatte/" + cryptomatte_layer_name_hash(layer_name) + "/" + key_name;
}
-/* Extracts the cryptomatte name from a render pass name.
- *
- * Example: A render pass could be named `CryptoObject00`. This
- * function would remove the trailing digits and return `CryptoObject`. */
StringRef BKE_cryptomatte_extract_layer_name(const StringRef render_pass_name)
{
int64_t last_token = render_pass_name.size();
@@ -525,16 +520,6 @@ std::string CryptomatteHash::hex_encoded() const
return encoded.str();
}
-/* Convert a cryptomatte hash to a float.
- *
- * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
- * cryptomatte specification. See Floating point conversion section in
- * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
- *
- * The conversion uses as many 32 bit floating point values as possible to minimize hash
- * collisions. Unfortunately not all 32 bits can be used as NaN and Inf can be problematic.
- *
- * Note that this conversion assumes to be running on a L-endian system. */
float CryptomatteHash::float_encoded() const
{
uint32_t mantissa = hash & ((1 << 23) - 1);
@@ -626,7 +611,6 @@ void CryptomatteStampDataCallbackData::extract_layer_names(void *_data,
data->hash_to_layer_name.add(layer_hash, propvalue);
}
-/* C type callback function (StampCallback). */
void CryptomatteStampDataCallbackData::extract_layer_manifest(void *_data,
const char *propname,
char *propvalue,
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.cc
index aae9ac383a4..dc2527f9b62 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -21,9 +21,9 @@
* \ingroup bke
*/
-#include <math.h> /* floor */
-#include <stdlib.h>
-#include <string.h>
+#include <cmath> /* floor */
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -43,7 +43,7 @@
#include "DNA_defaults.h"
#include "DNA_material_types.h"
-/* for dereferencing pointers */
+/* For dereferencing pointers. */
#include "DNA_key_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -89,12 +89,12 @@ static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
BLI_listbase_clear(&curve_dst->nurb);
BKE_nurbList_duplicate(&(curve_dst->nurb), &(curve_src->nurb));
- curve_dst->mat = MEM_dupallocN(curve_src->mat);
+ curve_dst->mat = (Material **)MEM_dupallocN(curve_src->mat);
- curve_dst->str = MEM_dupallocN(curve_src->str);
- curve_dst->strinfo = MEM_dupallocN(curve_src->strinfo);
- curve_dst->tb = MEM_dupallocN(curve_src->tb);
- curve_dst->batch_cache = NULL;
+ curve_dst->str = (char *)MEM_dupallocN(curve_src->str);
+ curve_dst->strinfo = (CharInfo *)MEM_dupallocN(curve_src->strinfo);
+ curve_dst->tb = (TextBox *)MEM_dupallocN(curve_src->tb);
+ curve_dst->batch_cache = nullptr;
curve_dst->bevel_profile = BKE_curveprofile_copy(curve_src->bevel_profile);
@@ -104,8 +104,8 @@ static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
curve_dst->key->from = &curve_dst->id;
}
- curve_dst->editnurb = NULL;
- curve_dst->editfont = NULL;
+ curve_dst->editnurb = nullptr;
+ curve_dst->editfont = nullptr;
}
static void curve_free_data(ID *id)
@@ -148,9 +148,9 @@ static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_addres
Curve *cu = (Curve *)id;
/* Clean up, important in undo case to reduce false detection of changed datablocks. */
- cu->editnurb = NULL;
- cu->editfont = NULL;
- cu->batch_cache = NULL;
+ cu->editnurb = nullptr;
+ cu->editfont = nullptr;
+ cu->batch_cache = nullptr;
/* write LibData */
BLO_write_id_struct(writer, Curve, id_address, &cu->id);
@@ -188,7 +188,7 @@ static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_addres
}
}
- if (cu->bevel_profile != NULL) {
+ if (cu->bevel_profile != nullptr) {
BKE_curveprofile_blend_write(writer, cu->bevel_profile);
}
}
@@ -218,13 +218,13 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &cu->strinfo);
BLO_read_data_address(reader, &cu->tb);
- if (cu->vfont == NULL) {
+ if (cu->vfont == nullptr) {
BLO_read_list(reader, &(cu->nurb));
}
else {
- cu->nurb.first = cu->nurb.last = NULL;
+ cu->nurb.first = cu->nurb.last = nullptr;
- TextBox *tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
+ TextBox *tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBoxread");
if (cu->tb) {
memcpy(tb, cu->tb, cu->totbox * sizeof(TextBox));
MEM_freeN(cu->tb);
@@ -241,16 +241,16 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
}
}
- cu->editnurb = NULL;
- cu->editfont = NULL;
- cu->batch_cache = NULL;
+ cu->editnurb = nullptr;
+ cu->editfont = nullptr;
+ cu->batch_cache = nullptr;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
BLO_read_data_address(reader, &nu->bezt);
BLO_read_data_address(reader, &nu->bp);
BLO_read_data_address(reader, &nu->knotsu);
BLO_read_data_address(reader, &nu->knotsv);
- if (cu->vfont == NULL) {
+ if (cu->vfont == nullptr) {
nu->charidx = 0;
}
@@ -261,7 +261,7 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
cu->texflag &= ~CU_AUTOSPACE_EVALUATED;
BLO_read_data_address(reader, &cu->bevel_profile);
- if (cu->bevel_profile != NULL) {
+ if (cu->bevel_profile != nullptr) {
BKE_curveprofile_blend_read(reader, cu->bevel_profile);
}
}
@@ -304,34 +304,35 @@ static void curve_blend_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_CU = {
- .id_code = ID_CU,
- .id_filter = FILTER_ID_CU,
- .main_listbase_index = INDEX_ID_CU,
- .struct_size = sizeof(Curve),
- .name = "Curve",
- .name_plural = "curves",
- .translation_context = BLT_I18NCONTEXT_ID_CURVE,
- .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
-
- .init_data = curve_init_data,
- .copy_data = curve_copy_data,
- .free_data = curve_free_data,
- .make_local = NULL,
- .foreach_id = curve_foreach_id,
- .foreach_cache = NULL,
- .owner_get = NULL,
-
- .blend_write = curve_blend_write,
- .blend_read_data = curve_blend_read_data,
- .blend_read_lib = curve_blend_read_lib,
- .blend_read_expand = curve_blend_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = NULL,
+ /* id_code */ ID_CU,
+ /* id_filter */ FILTER_ID_CU,
+ /* main_listbase_index */ INDEX_ID_CU,
+ /* struct_size */ sizeof(Curve),
+ /* name */ "Curve",
+ /* name_plural */ "curves",
+ /* translation_context */ BLT_I18NCONTEXT_ID_CURVE,
+ /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
+
+ /* init_data */ curve_init_data,
+ /* copy_data */ curve_copy_data,
+ /* free_data */ curve_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ curve_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
+ /* owner_get */ nullptr,
+
+ /* blend_write */ curve_blend_write,
+ /* blend_read_data */ curve_blend_read_data,
+ /* blend_read_lib */ curve_blend_read_lib,
+ /* blend_read_expand */ curve_blend_read_expand,
+
+ /* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
-/* frees editcurve entirely */
void BKE_curve_editfont_free(Curve *cu)
{
if (cu->editfont) {
@@ -348,21 +349,21 @@ void BKE_curve_editfont_free(Curve *cu)
}
MEM_freeN(ef);
- cu->editfont = NULL;
+ cu->editfont = nullptr;
}
}
static void curve_editNurb_keyIndex_cv_free_cb(void *val)
{
- CVKeyIndex *index = val;
+ CVKeyIndex *index = (CVKeyIndex *)val;
MEM_freeN(index->orig_cv);
MEM_freeN(val);
}
void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
{
- BLI_assert(keyindex != NULL);
- BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb);
+ BLI_assert(keyindex != nullptr);
+ BLI_ghash_remove(keyindex, cv, nullptr, curve_editNurb_keyIndex_cv_free_cb);
}
void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
@@ -370,8 +371,8 @@ void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
if (!(*keyindex)) {
return;
}
- BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb);
- *keyindex = NULL;
+ BLI_ghash_free(*keyindex, nullptr, curve_editNurb_keyIndex_cv_free_cb);
+ *keyindex = nullptr;
}
void BKE_curve_editNurb_free(Curve *cu)
@@ -380,7 +381,7 @@ void BKE_curve_editNurb_free(Curve *cu)
BKE_nurbList_free(&cu->editnurb->nurbs);
BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex);
MEM_freeN(cu->editnurb);
- cu->editnurb = NULL;
+ cu->editnurb = nullptr;
}
}
@@ -394,12 +395,12 @@ void BKE_curve_init(Curve *cu, const short curve_type)
cu->flag |= CU_FRONT | CU_BACK;
cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
cu->vfont->id.us += 4;
- cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
+ cu->str = (char *)MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
BLI_strncpy(cu->str, "Text", 12);
cu->len = cu->len_char32 = cu->pos = 4;
- cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
+ cu->strinfo = (CharInfo *)MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
cu->totbox = cu->actbox = 1;
- cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
+ cu->tb = (TextBox *)MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
cu->tb[0].w = cu->tb[0].h = 0.0;
}
else if (cu->type == OB_SURF) {
@@ -407,7 +408,7 @@ void BKE_curve_init(Curve *cu, const short curve_type)
cu->resolu = 4;
cu->resolv = 4;
}
- cu->bevel_profile = NULL;
+ cu->bevel_profile = nullptr;
}
Curve *BKE_curve_add(Main *bmain, const char *name, int type)
@@ -415,21 +416,20 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
Curve *cu;
/* We cannot use #BKE_id_new here as we need some custom initialization code. */
- cu = BKE_libblock_alloc(bmain, ID_CU, name, 0);
+ cu = (Curve *)BKE_libblock_alloc(bmain, ID_CU, name, 0);
BKE_curve_init(cu, type);
return cu;
}
-/* Get list of nurbs from editnurbs structure */
ListBase *BKE_curve_editNurbs_get(Curve *cu)
{
if (cu->editnurb) {
return &cu->editnurb->nurbs;
}
- return NULL;
+ return nullptr;
}
const ListBase *BKE_curve_editNurbs_get_for_read(const Curve *cu)
@@ -438,7 +438,7 @@ const ListBase *BKE_curve_editNurbs_get_for_read(const Curve *cu)
return &cu->editnurb->nurbs;
}
- return NULL;
+ return nullptr;
}
short BKE_curve_type_get(const Curve *cu)
@@ -481,10 +481,10 @@ void BKE_curve_dimension_update(Curve *cu)
void BKE_curve_type_test(Object *ob)
{
- ob->type = BKE_curve_type_get(ob->data);
+ ob->type = BKE_curve_type_get((Curve *)ob->data);
if (ob->type == OB_CURVE) {
- Curve *cu = ob->data;
+ Curve *cu = (Curve *)ob->data;
if (CU_IS_2D(cu)) {
BKE_curve_dimension_update(cu);
}
@@ -495,15 +495,15 @@ BoundBox *BKE_curve_boundbox_get(Object *ob)
{
/* This is Object-level data access,
* DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Curve *cu = ob->data;
+ if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Curve *cu = (Curve *)ob->data;
float min[3], max[3];
INIT_MINMAX(min, max);
BKE_curve_minmax(cu, true, min, max);
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
@@ -618,26 +618,26 @@ int BKE_nurbList_verts_count_without_handles(const ListBase *nurb)
void BKE_nurb_free(Nurb *nu)
{
- if (nu == NULL) {
+ if (nu == nullptr) {
return;
}
if (nu->bezt) {
MEM_freeN(nu->bezt);
}
- nu->bezt = NULL;
+ nu->bezt = nullptr;
if (nu->bp) {
MEM_freeN(nu->bp);
}
- nu->bp = NULL;
+ nu->bp = nullptr;
if (nu->knotsu) {
MEM_freeN(nu->knotsu);
}
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
if (nu->knotsv) {
MEM_freeN(nu->knotsv);
}
- nu->knotsv = NULL;
+ nu->knotsv = nullptr;
// if (nu->trim.first) freeNurblist(&(nu->trim));
MEM_freeN(nu);
@@ -645,7 +645,7 @@ void BKE_nurb_free(Nurb *nu)
void BKE_nurbList_free(ListBase *lb)
{
- if (lb == NULL) {
+ if (lb == nullptr) {
return;
}
@@ -661,8 +661,8 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
int len;
newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb");
- if (newnu == NULL) {
- return NULL;
+ if (newnu == nullptr) {
+ return nullptr;
}
memcpy(newnu, nu, sizeof(Nurb));
@@ -675,19 +675,19 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
newnu->bp = (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3");
memcpy(newnu->bp, nu->bp, len * sizeof(BPoint));
- newnu->knotsu = newnu->knotsv = NULL;
+ newnu->knotsu = newnu->knotsv = nullptr;
if (nu->knotsu) {
len = KNOTSU(nu);
if (len) {
- newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
+ newnu->knotsu = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len);
}
}
if (nu->pntsv > 1 && nu->knotsv) {
len = KNOTSV(nu);
if (len) {
- newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
+ newnu->knotsv = (float *)MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len);
}
}
@@ -695,7 +695,6 @@ Nurb *BKE_nurb_duplicate(const Nurb *nu)
return newnu;
}
-/* copy the nurb but allow for different number of points (to be copied after this) */
Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
{
Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb");
@@ -708,8 +707,8 @@ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
newnu->pntsv = pntsv;
/* caller can manually handle these arrays */
- newnu->knotsu = NULL;
- newnu->knotsv = NULL;
+ newnu->knotsu = nullptr;
+ newnu->knotsv = nullptr;
if (src->bezt) {
newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2");
@@ -757,10 +756,6 @@ void BKE_nurb_project_2d(Nurb *nu)
}
}
-/**
- * if use_radius is truth, minmax will take points' radius into account,
- * which will make boundbox closer to beveled curve.
- */
void BKE_nurb_minmax(const Nurb *nu, bool use_radius, float min[3], float max[3])
{
BezTriple *bezt;
@@ -842,7 +837,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
}
}
else if (nu->type == CU_BEZIER) {
- points = MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
+ points = (float *)MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
a = nu->pntsu - 1;
bezt = nu->bezt;
if (nu->flagu & CU_NURB_CYCLIC) {
@@ -886,9 +881,9 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
else if (nu->type == CU_NURBS) {
if (nu->pntsv == 1) {
/* important to zero for BKE_nurb_makeCurve. */
- points = MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
+ points = (float *)MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
- BKE_nurb_makeCurve(nu, points, NULL, NULL, NULL, resolu, sizeof(float[3]));
+ BKE_nurb_makeCurve(nu, points, nullptr, nullptr, nullptr, resolu, sizeof(float[3]));
if (nu->flagu & CU_NURB_CYCLIC) {
b = pntsu * resolu + 1;
@@ -914,10 +909,9 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
return length;
}
-/* be sure to call makeknots after this */
void BKE_nurb_points_add(Nurb *nu, int number)
{
- nu->bp = MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
+ nu->bp = (BPoint *)MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
BPoint *bp;
int i;
@@ -933,7 +927,7 @@ void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
BezTriple *bezt;
int i;
- nu->bezt = MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
+ nu->bezt = (BezTriple *)MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) {
bezt->radius = 1.0f;
@@ -984,7 +978,7 @@ BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
bezt_next = nu->bezt;
}
else {
- bezt_next = NULL;
+ bezt_next = nullptr;
}
}
else {
@@ -1005,7 +999,7 @@ BPoint *BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp)
bp_next = nu->bp;
}
else {
- bp_next = NULL;
+ bp_next = nullptr;
}
}
else {
@@ -1027,7 +1021,7 @@ BezTriple *BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
bezt_prev = &nu->bezt[nu->pntsu - 1];
}
else {
- bezt_prev = NULL;
+ bezt_prev = nullptr;
}
}
else {
@@ -1049,7 +1043,7 @@ BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
bp_prev = &nu->bp[nu->pntsu - 1];
}
else {
- bp_prev = NULL;
+ bp_prev = nullptr;
}
}
else {
@@ -1217,7 +1211,7 @@ static void makecyclicknots(float *knots, int pnts, short order)
{
int a, b, order2, c;
- if (knots == NULL) {
+ if (knots == nullptr) {
return;
}
@@ -1252,7 +1246,7 @@ static void makeknots(Nurb *nu, short uv)
MEM_freeN(nu->knotsu);
}
if (BKE_nurb_check_valid_u(nu)) {
- nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
+ nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
if (nu->flagu & CU_NURB_CYCLIC) {
calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */
makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
@@ -1262,7 +1256,7 @@ static void makeknots(Nurb *nu, short uv)
}
}
else {
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
}
}
else if (uv == 2) {
@@ -1270,7 +1264,7 @@ static void makeknots(Nurb *nu, short uv)
MEM_freeN(nu->knotsv);
}
if (BKE_nurb_check_valid_v(nu)) {
- nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
+ nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
if (nu->flagv & CU_NURB_CYCLIC) {
calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */
makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
@@ -1280,7 +1274,7 @@ static void makeknots(Nurb *nu, short uv)
}
}
else {
- nu->knotsv = NULL;
+ nu->knotsv = nullptr;
}
}
}
@@ -1374,9 +1368,6 @@ static void basisNurb(
}
}
-/**
- * \param coord_array: has to be (3 * 4 * resolu * resolv) in size, and zero-ed.
- */
void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
{
BPoint *bp;
@@ -1387,7 +1378,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv;
- if (nu->knotsu == NULL || nu->knotsv == NULL) {
+ if (nu->knotsu == nullptr || nu->knotsv == nullptr) {
return;
}
if (nu->orderu > nu->pntsu) {
@@ -1396,7 +1387,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
if (nu->orderv > nu->pntsv) {
return;
}
- if (coord_array == NULL) {
+ if (coord_array == nullptr) {
return;
}
@@ -1447,7 +1438,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
- /* precalculation of basisv and jstart, jend */
+ /* Pre-calculation of `basisv` and `jstart`, `jend`. */
if (nu->flagv & CU_NURB_CYCLIC) {
cycl = nu->orderv - 1;
}
@@ -1569,11 +1560,6 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
MEM_freeN(jend);
}
-/**
- * \param coord_array: Has to be 3 * 4 * pntsu * resolu in size and zero-ed
- * \param tilt_array: set when non-NULL
- * \param radius_array: set when non-NULL
- */
void BKE_nurb_makeCurve(const Nurb *nu,
float *coord_array,
float *tilt_array,
@@ -1590,13 +1576,13 @@ void BKE_nurb_makeCurve(const Nurb *nu,
*weight_fp = weight_array;
int i, len, istart, iend, cycl;
- if (nu->knotsu == NULL) {
+ if (nu->knotsu == nullptr) {
return;
}
if (nu->orderu > nu->pntsu) {
return;
}
- if (coord_array == NULL) {
+ if (coord_array == nullptr) {
return;
}
@@ -1690,16 +1676,16 @@ void BKE_nurb_makeCurve(const Nurb *nu,
}
}
- coord_fp = POINTER_OFFSET(coord_fp, stride);
+ coord_fp = (float *)POINTER_OFFSET(coord_fp, stride);
if (tilt_fp) {
- tilt_fp = POINTER_OFFSET(tilt_fp, stride);
+ tilt_fp = (float *)POINTER_OFFSET(tilt_fp, stride);
}
if (radius_fp) {
- radius_fp = POINTER_OFFSET(radius_fp, stride);
+ radius_fp = (float *)POINTER_OFFSET(radius_fp, stride);
}
if (weight_fp) {
- weight_fp = POINTER_OFFSET(weight_fp, stride);
+ weight_fp = (float *)POINTER_OFFSET(weight_fp, stride);
}
u += ustep;
@@ -1710,9 +1696,6 @@ void BKE_nurb_makeCurve(const Nurb *nu,
MEM_freeN(basisu);
}
-/**
- * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
- */
unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
const unsigned int resolu,
const bool is_cyclic,
@@ -1724,12 +1707,6 @@ unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
return points_len;
}
-/**
- * Calculate an array for the entire curve (cyclic or non-cyclic).
- * \note Call for each axis.
- *
- * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
- */
void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
const unsigned int bezt_array_len,
const unsigned int resolu,
@@ -1757,7 +1734,7 @@ void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
r_points_offset,
(int)resolu,
stride);
- r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
}
if (is_cyclic) {
@@ -1770,23 +1747,22 @@ void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
r_points_offset,
(int)resolu,
stride);
- r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, resolu_stride);
if (use_cyclic_duplicate_endpoint) {
*r_points_offset = *r_points;
- r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
}
}
else {
- float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
+ float *r_points_last = (float *)POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
*r_points_last = bezt_array[bezt_array_last].vec[1][axis];
- r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ r_points_offset = (float *)POINTER_OFFSET(r_points_offset, stride);
}
- BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
+ BLI_assert((float *)POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
UNUSED_VARS_NDEBUG(points_len);
}
-/* forward differencing method for bezier curve */
void BKE_curve_forward_diff_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
@@ -1808,14 +1784,13 @@ void BKE_curve_forward_diff_bezier(
for (a = 0; a <= it; a++) {
*p = q0;
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
q2 += q3;
}
}
-/* forward differencing method for first derivative of cubic bezier curve */
void BKE_curve_forward_diff_tangent_bezier(
float q0, float q1, float q2, float q3, float *p, int it, int stride)
{
@@ -1834,7 +1809,7 @@ void BKE_curve_forward_diff_tangent_bezier(
for (a = 0; a <= it; a++) {
*p = q0;
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
q0 += q1;
q1 += q2;
}
@@ -1860,7 +1835,7 @@ static void forward_diff_bezier_cotangent(const float p0[3],
(-18.0f * t + 6.0f) * p2[i] + (6.0f * t) * p3[i];
}
normalize_v3(p);
- p = POINTER_OFFSET(p, stride);
+ p = (float *)POINTER_OFFSET(p, stride);
}
}
@@ -1973,7 +1948,7 @@ struct BevelSort {
static int vergxcobev(const void *a1, const void *a2)
{
- const struct BevelSort *x1 = a1, *x2 = a2;
+ const struct BevelSort *x1 = (BevelSort *)a1, *x2 = (BevelSort *)a2;
if (x1->left > x2->left) {
return 1;
@@ -2047,7 +2022,7 @@ static void tilt_bezpart(const BezTriple *prevbezt,
float fac, dfac, t[4];
int a;
- if (tilt_array == NULL && radius_array == NULL) {
+ if (tilt_array == nullptr && radius_array == nullptr) {
return;
}
@@ -2095,7 +2070,7 @@ static void tilt_bezpart(const BezTriple *prevbezt,
t[3] * next->tilt;
}
- tilt_array = POINTER_OFFSET(tilt_array, stride);
+ tilt_array = (float *)POINTER_OFFSET(tilt_array, stride);
}
if (radius_array) {
@@ -2109,14 +2084,14 @@ static void tilt_bezpart(const BezTriple *prevbezt,
else {
/* reuse interpolation from tilt if we can */
- if (tilt_array == NULL || nu->tilt_interp != nu->radius_interp) {
+ if (tilt_array == nullptr || nu->tilt_interp != nu->radius_interp) {
key_curve_position_weights(fac, t, nu->radius_interp);
}
*radius_array = t[0] * pprev->radius + t[1] * prevbezt->radius + t[2] * bezt->radius +
t[3] * next->radius;
}
- radius_array = POINTER_OFFSET(radius_array, stride);
+ radius_array = (float *)POINTER_OFFSET(radius_array, stride);
}
if (weight_array) {
@@ -2124,15 +2099,15 @@ static void tilt_bezpart(const BezTriple *prevbezt,
*weight_array = prevbezt->weight + (bezt->weight - prevbezt->weight) *
(3.0f * fac * fac - 2.0f * fac * fac * fac);
- weight_array = POINTER_OFFSET(weight_array, stride);
+ weight_array = (float *)POINTER_OFFSET(weight_array, stride);
}
}
}
-/* make_bevel_list_3D_* funcs, at a minimum these must
- * fill in the bezp->quat and bezp->dir values */
+/* `make_bevel_list_3D_*` functions, at a minimum these must
+ * fill in the #BevPoint.quat and #BevPoint.dir values. */
-/* utility for make_bevel_list_3D_* funcs */
+/** Utility for `make_bevel_list_3D_*` functions. */
static void bevel_list_calc_bisect(BevList *bl)
{
BevPoint *bevp2, *bevp1, *bevp0;
@@ -2354,14 +2329,14 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
/* Need to correct for the start/end points not matching
* do this by calculating the tilt angle difference, then apply
- * the rotation gradually over the entire curve
+ * the rotation gradually over the entire curve.
*
- * note that the split is between last and second last, rather than first/last as youd expect.
+ * Note that the split is between last and second last, rather than first/last as you'd expect.
*
* real order is like this
* 0,1,2,3,4 --> 1,2,3,4,0
*
- * this is why we compare last with second last
+ * This is why we compare last with second last.
*/
float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
@@ -2622,13 +2597,13 @@ static void bevlist_firstlast_direction_calc_from_bpoint(const Nurb *nu, BevList
void BKE_curve_bevelList_free(ListBase *bev)
{
LISTBASE_FOREACH_MUTABLE (BevList *, bl, bev) {
- if (bl->seglen != NULL) {
+ if (bl->seglen != nullptr) {
MEM_freeN(bl->seglen);
}
- if (bl->segbevcount != NULL) {
+ if (bl->segbevcount != nullptr) {
MEM_freeN(bl->segbevcount);
}
- if (bl->bevpoints != NULL) {
+ if (bl->bevpoints != nullptr) {
MEM_freeN(bl->bevpoints);
}
MEM_freeN(bl);
@@ -2639,22 +2614,21 @@ void BKE_curve_bevelList_free(ListBase *bev)
void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
{
- /*
- * - convert all curves to polys, with indication of resol and flags for double-vertices
- * - possibly; do a smart vertice removal (in case Nurb)
- * - separate in individual blocks with BoundBox
- * - AutoHole detection
+ /* - Convert all curves to polys, with indication of resolution and flags for double-vertices.
+ * - Possibly; do a smart vertex removal (in case #Nurb).
+ * - Separate in individual blocks with #BoundBox.
+ * - Auto-hole detection.
*/
- /* this function needs an object, because of tflag and upflag */
- Curve *cu = ob->data;
+ /* This function needs an object, because of `tflag` and `upflag`. */
+ Curve *cu = (Curve *)ob->data;
BezTriple *bezt, *prevbezt;
BPoint *bp;
BevList *blnew;
- BevPoint *bevp2, *bevp1 = NULL, *bevp0;
+ BevPoint *bevp2, *bevp1 = nullptr, *bevp0;
const float threshold = 0.00001f;
float min, inp;
- float *seglen = NULL;
+ float *seglen = nullptr;
struct BevelSort *sortdata, *sd, *sd1;
int a, b, nr, poly, resolu = 0, len = 0, segcount;
int *segbevcount;
@@ -2662,7 +2636,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bool is_editmode = false;
ListBase *bev;
- /* segbevcount alsp requires seglen. */
+ /* segbevcount also requires seglen. */
const bool need_seglen = ELEM(
cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
@@ -2679,7 +2653,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
if (cu->editnurb && ob->type != OB_FONT) {
- is_editmode = 1;
+ is_editmode = true;
}
LISTBASE_FOREACH (const Nurb *, nu, nurbs) {
@@ -2690,8 +2664,8 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* check we are a single point? also check we are not a surface and that the orderu is sane,
* enforced in the UI but can go wrong possibly */
if (!BKE_nurb_check_valid_u(nu)) {
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList1");
- bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), "makeBevelList1");
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
BLI_addtail(bev, bl);
bl->nr = 0;
bl->charidx = nu->charidx;
@@ -2720,11 +2694,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
if (nu->type == CU_POLY) {
len = nu->pntsu;
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList2");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
@@ -2744,7 +2718,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bevp->radius = bp->radius;
bevp->weight = bp->weight;
bp++;
- if (seglen != NULL && len != 0) {
+ if (seglen != nullptr && len != 0) {
*seglen = len_v3v3(bevp->vec, bp->vec);
bevp++;
bevp->offset = *seglen;
@@ -2770,11 +2744,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* in case last point is not cyclic */
len = segcount * resolu + 1;
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelBPoints_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
@@ -2786,7 +2760,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
segbevcount = bl->segbevcount;
bevp->offset = 0;
- if (seglen != NULL) {
+ if (seglen != nullptr) {
*seglen = 0;
*segbevcount = 0;
}
@@ -2818,7 +2792,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bevp++;
bl->nr++;
bl->dupe_nr = 1;
- if (seglen != NULL) {
+ if (seglen != nullptr) {
*seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]);
bevp->offset = *seglen;
seglen++;
@@ -2830,10 +2804,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
}
else {
- /* always do all three, to prevent data hanging around */
+ /* Always do all three, to prevent data hanging around. */
int j;
- /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */
+ /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */
for (j = 0; j < 3; j++) {
BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
prevbezt->vec[2][j],
@@ -2844,13 +2818,13 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* if both arrays are NULL do nothiong */
+ /* If both arrays are `nullptr` do nothing. */
tilt_bezpart(prevbezt,
bezt,
nu,
- do_tilt ? &bevp->tilt : NULL,
- do_radius ? &bevp->radius : NULL,
- do_weight ? &bevp->weight : NULL,
+ do_tilt ? &bevp->tilt : nullptr,
+ do_radius ? &bevp->radius : nullptr,
+ do_weight ? &bevp->weight : nullptr,
resolu,
sizeof(BevPoint));
@@ -2864,15 +2838,15 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* seglen */
- if (seglen != NULL) {
+ /* `seglen`. */
+ if (seglen != nullptr) {
*seglen = 0;
*segbevcount = 0;
for (j = 0; j < resolu; j++) {
bevp0 = bevp;
bevp++;
bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
- /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ /* Match `seglen` and `segbevcount` to the cleaned up bevel lists (see STEP 2). */
if (bevp->offset > threshold) {
*seglen += bevp->offset;
*segbevcount += 1;
@@ -2906,11 +2880,11 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
if (nu->pntsv == 1) {
len = (resolu * segcount);
- BevList *bl = MEM_callocN(sizeof(BevList), "makeBevelList3");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3");
+ BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList3_segbevcount");
+ bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
+ bl->segbevcount = (int *)MEM_malloc_arrayN(segcount, sizeof(int), __func__);
}
BLI_addtail(bev, bl);
bl->nr = len;
@@ -2924,14 +2898,14 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BKE_nurb_makeCurve(nu,
&bevp->vec[0],
- do_tilt ? &bevp->tilt : NULL,
- do_radius ? &bevp->radius : NULL,
- do_weight ? &bevp->weight : NULL,
+ do_tilt ? &bevp->tilt : nullptr,
+ do_radius ? &bevp->radius : nullptr,
+ do_weight ? &bevp->weight : nullptr,
resolu,
sizeof(BevPoint));
/* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
- if (seglen != NULL) {
+ if (seglen != nullptr) {
nr = segcount;
bevp0 = bevp;
bevp++;
@@ -2983,7 +2957,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
nr--;
while (nr--) {
- if (seglen != NULL) {
+ if (seglen != nullptr) {
if (fabsf(bevp1->offset) < threshold) {
bevp0->dupe_tag = true;
bl->dupe_nr++;
@@ -3005,10 +2979,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
continue;
}
- nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
- blnew = MEM_mallocN(sizeof(BevList), "makeBevelList4");
+ nr = bl->nr - bl->dupe_nr + 1; /* +1 because vector-bezier sets flag too. */
+ blnew = (BevList *)MEM_mallocN(sizeof(BevList), "makeBevelList4");
memcpy(blnew, bl, sizeof(BevList));
- blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
+ blnew->bevpoints = (BevPoint *)MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
if (!blnew->bevpoints) {
MEM_freeN(blnew);
break;
@@ -3017,7 +2991,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
blnew->seglen = bl->seglen;
blnew->nr = 0;
BLI_remlink(bev, bl);
- BLI_insertlinkbefore(bev, bl->next, blnew); /* to make sure bevlist is tuned with nurblist */
+ BLI_insertlinkbefore(bev, bl->next, blnew); /* Ensure `bevlist` is tuned with `nurblist`. */
bevp0 = bl->bevpoints;
bevp1 = blnew->bevpoints;
nr = bl->nr;
@@ -3029,7 +3003,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
bevp0++;
}
- if (bl->bevpoints != NULL) {
+ if (bl->bevpoints != nullptr) {
MEM_freeN(bl->bevpoints);
}
MEM_freeN(bl);
@@ -3048,7 +3022,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* find extreme left points, also test (turning) direction */
if (poly > 0) {
- sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5");
+ sd = sortdata = (BevelSort *)MEM_malloc_arrayN(poly, sizeof(struct BevelSort), __func__);
LISTBASE_FOREACH (BevList *, bl, bev) {
if (bl->poly > 0) {
BevPoint *bevp;
@@ -3139,7 +3113,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_2D(bl);
}
else {
@@ -3154,7 +3128,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_3D(bl);
}
else {
@@ -3194,7 +3168,7 @@ static void calchandleNurb_intern(BezTriple *bezt,
p2 = bezt->vec[1];
- if (prev == NULL) {
+ if (prev == nullptr) {
p3 = next->vec[1];
pt[0] = 2.0f * p2[0] - p3[0];
pt[1] = 2.0f * p2[1] - p3[1];
@@ -3205,7 +3179,7 @@ static void calchandleNurb_intern(BezTriple *bezt,
p1 = prev->vec[1];
}
- if (next == NULL) {
+ if (next == nullptr) {
pt[0] = 2.0f * p2[0] - p1[0];
pt[1] = 2.0f * p2[1] - p1[1];
pt[2] = 2.0f * p2[2] - p1[2];
@@ -3283,13 +3257,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
if (ydiff1 <= 0.0f) {
if (prev->vec[1][1] > bezt->vec[0][1]) {
bezt->vec[0][1] = prev->vec[1][1];
- leftviolate = 1;
+ leftviolate = true;
}
}
else {
if (prev->vec[1][1] < bezt->vec[0][1]) {
bezt->vec[0][1] = prev->vec[1][1];
- leftviolate = 1;
+ leftviolate = true;
}
}
}
@@ -3310,13 +3284,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
if (ydiff1 <= 0.0f) {
if (next->vec[1][1] < bezt->vec[2][1]) {
bezt->vec[2][1] = next->vec[1][1];
- rightviolate = 1;
+ rightviolate = true;
}
}
else {
if (next->vec[1][1] > bezt->vec[2][1]) {
bezt->vec[2][1] = next->vec[1][1];
- rightviolate = 1;
+ rightviolate = true;
}
}
}
@@ -3346,13 +3320,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
}
if (skip_align ||
- /* when one handle is free, alignming makes no sense, see: T35952 */
+ /* When one handle is free, aligning makes no sense, see: T35952 */
ELEM(HD_FREE, bezt->h1, bezt->h2) ||
- /* also when no handles are aligned, skip this step */
+ /* Also when no handles are aligned, skip this step. */
(!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
- /* handles need to be updated during animation and applying stuff like hooks,
+ /* Handles need to be updated during animation and applying stuff like hooks,
* but in such situations it's quite difficult to distinguish in which order
- * align handles should be aligned so skip them for now */
+ * align handles should be aligned so skip them for now. */
return;
}
@@ -3427,19 +3401,19 @@ static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bo
prev = bezt + (a - 1);
}
else {
- prev = NULL;
+ prev = nullptr;
}
next = bezt + 1;
while (a--) {
- calchandleNurb_intern(bezt, prev, next, handle_sel_flag, 0, skip_align, 0);
+ calchandleNurb_intern(bezt, prev, next, handle_sel_flag, false, skip_align, 0);
prev = bezt;
if (a == 1) {
if (nu->flagu & CU_NURB_CYCLIC) {
next = nu->bezt;
}
else {
- next = NULL;
+ next = nullptr;
}
}
else {
@@ -3455,7 +3429,8 @@ static void calchandlesNurb_intern(Nurb *nu, eBezTriple_Flag handle_sel_flag, bo
* with easy error checking and de-allocation, and an easy way to add or remove
* arrays that are processed in this way when changing code.
*
- * floats, chars: NULL-terminated arrays of pointers to array pointers that need to be allocated.
+ * floats, chars: null-terminated arrays of pointers to array pointers that need to be
+ * allocated.
*
* Returns: pointer to the buffer that contains all of the arrays.
*/
@@ -3474,10 +3449,10 @@ static void *allocate_arrays(int count, float ***floats, char ***chars, const ch
void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name);
if (!buffer) {
- return NULL;
+ return nullptr;
}
- float *fptr = buffer;
+ float *fptr = (float *)buffer;
for (int i = 0; i < num_floats; i++, fptr += count) {
*floats[i] = fptr;
@@ -3546,9 +3521,9 @@ static bool tridiagonal_solve_with_limits(float *a,
int solve_count)
{
float *a0, *b0, *c0, *d0;
- float **arrays[] = {&a0, &b0, &c0, &d0, NULL};
+ float **arrays[] = {&a0, &b0, &c0, &d0, nullptr};
char *is_locked, *num_unlocks;
- char **flagarrays[] = {&is_locked, &num_unlocks, NULL};
+ char **flagarrays[] = {&is_locked, &num_unlocks, nullptr};
void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits");
if (!tmps) {
@@ -3815,7 +3790,7 @@ static void bezier_handle_calc_smooth_fcurve(
BezTriple *bezt, int total, int start, int count, bool cycle)
{
float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin;
- float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, NULL};
+ float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, nullptr};
int solve_count = count;
@@ -3844,7 +3819,7 @@ static void bezier_handle_calc_smooth_fcurve(
/* allocate all */
- void *tmp_buffer = allocate_arrays(count, arrays, NULL, "bezier_calc_smooth_tmp");
+ void *tmp_buffer = allocate_arrays(count, arrays, nullptr, "bezier_calc_smooth_tmp");
if (!tmp_buffer) {
return;
}
@@ -4020,8 +3995,8 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
}
}
- /* Find continuous subsequences of free auto handles and smooth them, starting at
- * search_base. In cyclic mode these subsequences can span the cycle boundary. */
+ /* Find continuous sub-sequences of free auto handles and smooth them, starting at search_base.
+ * In cyclic mode these sub-sequences can span the cycle boundary. */
int start = search_base, count = 1;
for (int i = 1, j = start + 1; i < total; i++, j++) {
@@ -4046,23 +4021,12 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
}
}
-/**
- * Recalculate the handles of a nurb bezier-triple. Acts based on handle selection with `SELECT`
- * flag. To use a different flag, use #BKE_nurb_handle_calc_ex().
- */
void BKE_nurb_handle_calc(
BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
{
- calchandleNurb_intern(bezt, prev, next, SELECT, is_fcurve, false, smoothing);
+ calchandleNurb_intern(bezt, prev, next, (eBezTriple_Flag)SELECT, is_fcurve, false, smoothing);
}
-/**
- * Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag.
- *
- * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
- * Usually #SELECT, but may want to use a different one at times
- * (if caller does not operate on selection).
- */
void BKE_nurb_handle_calc_ex(BezTriple *bezt,
BezTriple *prev,
BezTriple *next,
@@ -4070,12 +4034,13 @@ void BKE_nurb_handle_calc_ex(BezTriple *bezt,
const bool is_fcurve,
const char smoothing)
{
- calchandleNurb_intern(bezt, prev, next, handle_sel_flag, is_fcurve, false, smoothing);
+ calchandleNurb_intern(
+ bezt, prev, next, (eBezTriple_Flag)handle_sel_flag, is_fcurve, false, smoothing);
}
void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */
{
- calchandlesNurb_intern(nu, SELECT, false);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, false);
}
/**
@@ -4103,14 +4068,12 @@ static void nurb_handles_calc__align_selected(Nurb *nu)
nurbList_handles_swap_select(nu);
}
-/* similar to BKE_nurb_handle_calc but for curves and
- * figures out the previous and next for us */
void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt)
{
if (nu->pntsu > 1) {
BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt);
BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt);
- BKE_nurb_handle_calc(bezt, prev, next, 0, 0);
+ BKE_nurb_handle_calc(bezt, prev, next, false, 0);
}
}
@@ -4129,19 +4092,6 @@ void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
}
}
-/**
- * Update selected handle types to ensure valid state, e.g. deduce "Auto" types to concrete ones.
- * Thereby \a sel_flag defines what qualifies as selected.
- * Use when something has changed handle positions.
- *
- * The caller needs to recalculate handles.
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- * \param use_handle: Check selection state of individual handles, otherwise always update both
- * handles if the key is selected.
- */
void BKE_nurb_bezt_handle_test(BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
const bool use_handle,
@@ -4223,7 +4173,7 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
const float eps = 0.0001f;
const float eps_sq = eps * eps;
- if (nu == NULL || nu->bezt == NULL) {
+ if (nu == nullptr || nu->bezt == nullptr) {
return;
}
@@ -4238,13 +4188,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* left handle: */
if (flag == 0 || (bezt1->f1 & flag)) {
bezt1->h1 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
bezt1->h1 = HD_VECT;
leftsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
align = true;
bezt1->h1 = HD_ALIGN;
@@ -4258,13 +4208,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* right handle: */
if (flag == 0 || (bezt1->f3 & flag)) {
bezt1->h2 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
bezt1->h2 = HD_VECT;
rightsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (align) {
bezt1->h2 = HD_ALIGN;
}
@@ -4305,15 +4255,6 @@ void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag)
}
}
-/**
- * \param code:
- * - 1 (#HD_AUTO): set auto-handle.
- * - 2 (#HD_VECT): set vector-handle.
- * - 3 (#HD_ALIGN) it toggle, vector-handles become #HD_FREE.
- *
- * - 5: Set align, like 3 but no toggle.
- * - 6: Clear align (setting #HD_FREE), like 3 but no toggle.
- */
void BKE_nurbList_handles_set(ListBase *editnurb, const char code)
{
BezTriple *bezt;
@@ -4491,9 +4432,6 @@ void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set)
}
}
-/**
- * Set \a flag for every point that already has \a from_flag set.
- */
bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, uint8_t from_flag, uint8_t flag)
{
bool changed = false;
@@ -4608,7 +4546,7 @@ void BKE_nurb_direction_switch(Nurb *nu)
/* and make in increasing order again */
a = KNOTSU(nu);
fp1 = nu->knotsu;
- fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
+ fp2 = tempf = (float *)MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
a--;
fp2[a] = fp1[a];
while (a--) {
@@ -4678,7 +4616,8 @@ void BKE_curve_nurbs_vert_coords_get(const ListBase *lb, float (*vert_coords)[3]
float (*BKE_curve_nurbs_vert_coords_alloc(const ListBase *lb, int *r_vert_len))[3]
{
const int vert_len = BKE_nurbList_verts_count(lb);
- float(*vert_coords)[3] = MEM_malloc_arrayN(vert_len, sizeof(*vert_coords), __func__);
+ float(*vert_coords)[3] = (float(*)[3])MEM_malloc_arrayN(
+ vert_len, sizeof(*vert_coords), __func__);
BKE_curve_nurbs_vert_coords_get(lb, vert_coords, vert_len);
*r_vert_len = vert_len;
return vert_coords;
@@ -4717,7 +4656,7 @@ void BKE_curve_nurbs_vert_coords_apply_with_mat4(ListBase *lb,
BKE_nurb_project_2d(nu);
}
- calchandlesNurb_intern(nu, SELECT, true);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, true);
}
}
@@ -4753,14 +4692,14 @@ void BKE_curve_nurbs_vert_coords_apply(ListBase *lb,
BKE_nurb_project_2d(nu);
}
- calchandlesNurb_intern(nu, SELECT, true);
+ calchandlesNurb_intern(nu, (eBezTriple_Flag)SELECT, true);
}
}
float (*BKE_curve_nurbs_key_vert_coords_alloc(const ListBase *lb, float *key, int *r_vert_len))[3]
{
int vert_len = BKE_nurbList_verts_count(lb);
- float(*cos)[3] = MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
+ float(*cos)[3] = (float(*)[3])MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
float *co = cos[0];
LISTBASE_FOREACH (const Nurb *, nu, lb) {
@@ -4910,9 +4849,6 @@ bool BKE_nurb_order_clamp_v(struct Nurb *nu)
return changed;
}
-/**
- * \note caller must ensure active vertex remains valid.
- */
bool BKE_nurb_type_convert(Nurb *nu,
const short type,
const bool use_handles,
@@ -4923,7 +4859,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
int a, c, nr;
if (nu->type == CU_POLY) {
- if (type == CU_BEZIER) { /* To Bezier with vecthandles. */
+ if (type == CU_BEZIER) { /* To Bezier with vector-handles. */
nr = nu->pntsu;
bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
@@ -4939,7 +4875,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bp);
- nu->bp = NULL;
+ nu->bp = nullptr;
nu->pntsu = nr;
nu->pntsv = 0;
nu->type = CU_BEZIER;
@@ -4961,7 +4897,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
else if (nu->type == CU_BEZIER) { /* Bezier */
if (ELEM(type, CU_POLY, CU_NURBS)) {
nr = use_handles ? (3 * nu->pntsu) : nu->pntsu;
- nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
+ nu->bp = (BPoint *)MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
a = nu->pntsu;
bezt = nu->bezt;
bp = nu->bp;
@@ -4993,7 +4929,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bezt);
- nu->bezt = NULL;
+ nu->bezt = nullptr;
nu->pntsu = nr;
nu->pntsv = 1;
nu->orderu = 4;
@@ -5013,20 +4949,20 @@ bool BKE_nurb_type_convert(Nurb *nu,
if (nu->knotsu) {
MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
}
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
MEM_SAFE_FREE(nu->knotsv);
}
else if (type == CU_BEZIER) { /* to Bezier */
nr = nu->pntsu / 3;
if (nr < 2) {
- if (r_err_msg != NULL) {
+ if (r_err_msg != nullptr) {
*r_err_msg = "At least 6 points required for conversion";
}
return false; /* conversion impossible */
}
- bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
+ bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
a = nr;
bp = nu->bp;
@@ -5045,9 +4981,9 @@ bool BKE_nurb_type_convert(Nurb *nu,
bezt++;
}
MEM_freeN(nu->bp);
- nu->bp = NULL;
+ nu->bp = nullptr;
MEM_freeN(nu->knotsu);
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
nu->pntsu = nr;
nu->type = CU_BEZIER;
}
@@ -5056,7 +4992,6 @@ bool BKE_nurb_type_convert(Nurb *nu,
return true;
}
-/* Get edit nurbs or normal nurbs list */
ListBase *BKE_curve_nurbs_get(Curve *cu)
{
if (cu->editnurb) {
@@ -5077,7 +5012,7 @@ const ListBase *BKE_curve_nurbs_get_for_read(const Curve *cu)
void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
{
- if (nu == NULL) {
+ if (nu == nullptr) {
cu->actnu = CU_ACT_NONE;
}
else {
@@ -5090,14 +5025,13 @@ void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
Nurb *BKE_curve_nurb_active_get(Curve *cu)
{
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- return BLI_findlink(nurbs, cu->actnu);
+ return (Nurb *)BLI_findlink(nurbs, cu->actnu);
}
-/* Get active vert for curve */
void *BKE_curve_vert_active_get(Curve *cu)
{
- Nurb *nu = NULL;
- void *vert = NULL;
+ Nurb *nu = nullptr;
+ void *vert = nullptr;
BKE_curve_nurb_vert_active_get(cu, &nu, &vert);
return vert;
@@ -5114,7 +5048,6 @@ int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
return (BPoint *)vert - nu->bp;
}
-/* Set active nurb and active vert for curve */
void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
{
if (nu) {
@@ -5132,15 +5065,14 @@ void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
}
}
-/* Get points to the active nurb and active vert for curve. */
bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
{
- Nurb *nu = NULL;
- void *vert = NULL;
+ Nurb *nu = nullptr;
+ void *vert = nullptr;
if (cu->actvert != CU_ACT_NONE) {
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- nu = BLI_findlink(nurbs, cu->actnu);
+ nu = (Nurb *)BLI_findlink(nurbs, cu->actnu);
if (nu) {
if (nu->type == CU_BEZIER) {
@@ -5157,7 +5089,7 @@ bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
*r_nu = nu;
*r_vert = vert;
- return (*r_vert != NULL);
+ return (*r_vert != nullptr);
}
void BKE_curve_nurb_vert_active_validate(Curve *cu)
@@ -5167,13 +5099,13 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
if (nu->type == CU_BEZIER) {
- BezTriple *bezt = vert;
+ BezTriple *bezt = (BezTriple *)vert;
if (BEZT_ISSEL_ANY(bezt) == 0) {
cu->actvert = CU_ACT_NONE;
}
}
else {
- BPoint *bp = vert;
+ BPoint *bp = (BPoint *)vert;
if ((bp->f1 & SELECT) == 0) {
cu->actvert = CU_ACT_NONE;
}
@@ -5185,11 +5117,10 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
}
}
-/* basic vertex data functions */
bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
{
ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
- ListBase temp_nurb_lb = {NULL, NULL};
+ ListBase temp_nurb_lb = {nullptr, nullptr};
const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0);
/* For font curves we generate temp list of splines.
*
@@ -5198,7 +5129,7 @@ bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
*/
if (is_font) {
nurb_lb = &temp_nurb_lb;
- BKE_vfont_to_curve_ex(NULL, cu, FO_EDIT, nurb_lb, NULL, NULL, NULL, NULL);
+ BKE_vfont_to_curve_ex(nullptr, cu, FO_EDIT, nurb_lb, nullptr, nullptr, nullptr, nullptr);
use_radius = false;
}
/* Do bounding box based on splines. */
@@ -5303,7 +5234,7 @@ void BKE_curve_transform_ex(Curve *cu,
if (do_keys && cu->key) {
LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
- float *fp = kb->data;
+ float *fp = (float *)kb->data;
int n = kb->totelem;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
@@ -5361,7 +5292,7 @@ void BKE_curve_translate(Curve *cu, const float offset[3], const bool do_keys)
if (do_keys && cu->key) {
LISTBASE_FOREACH (KeyBlock *, kb, &cu->key->block) {
- float *fp = kb->data;
+ float *fp = (float *)kb->data;
int n = kb->totelem;
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
@@ -5513,11 +5444,10 @@ void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int
}
}
else {
- Nurb *nu;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
MAT_NR_REMAP(nu->mat_nr);
}
}
@@ -5551,8 +5481,6 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu,
r_rect->ymin = r_rect->ymax - tb->h;
}
-/* This function is almost the same as BKE_fcurve_correct_bezpart(), but doesn't allow as large a
- * tangent. */
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
{
float h1[2], h2[2], len1, len2, len, fac;
@@ -5609,8 +5537,8 @@ void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
}
/* Draw Engine */
-void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = NULL;
-void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
+void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = nullptr;
+void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = nullptr;
void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode)
{
diff --git a/source/blender/blenkernel/intern/curve_bevel.c b/source/blender/blenkernel/intern/curve_bevel.c
index d205d8cca46..18e4ab3ade1 100644
--- a/source/blender/blenkernel/intern/curve_bevel.c
+++ b/source/blender/blenkernel/intern/curve_bevel.c
@@ -64,8 +64,8 @@ static void bevel_quarter_fill(const Curve *curve,
float angle = 0.0f;
const float dangle = (float)M_PI_2 / (curve->bevresol + 1);
for (int i = 0; i < curve->bevresol + 1; i++) {
- quarter_coords_x[i] = (float)(cosf(angle) * (curve->ext2));
- quarter_coords_y[i] = (float)(sinf(angle) * (curve->ext2));
+ quarter_coords_x[i] = (float)(cosf(angle) * (curve->bevel_radius));
+ quarter_coords_y[i] = (float)(sinf(angle) * (curve->bevel_radius));
angle += dangle;
}
}
@@ -76,11 +76,11 @@ static void bevel_quarter_fill(const Curve *curve,
/* If there aren't enough samples, the curveprofile won't
* sample the start vertex, so set it manually instead. */
- quarter_coords_x[0] = curve->ext2;
+ quarter_coords_x[0] = curve->bevel_radius;
quarter_coords_y[0] = 0.0f;
for (int i = 1; i < curve->bevresol + 1; i++) {
- quarter_coords_x[i] = (float)(curve->bevel_profile->segments[i].x * (curve->ext2));
- quarter_coords_y[i] = (float)(curve->bevel_profile->segments[i].y * (curve->ext2));
+ quarter_coords_x[i] = (float)(curve->bevel_profile->segments[i].x * (curve->bevel_radius));
+ quarter_coords_y[i] = (float)(curve->bevel_profile->segments[i].y * (curve->bevel_radius));
}
}
}
@@ -133,13 +133,13 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
/* Add the bottom vertex. */
fp[0] = 0.0f;
fp[1] = 0.0f;
- fp[2] = -cu->ext1 - cu->ext2;
+ fp[2] = -cu->extrude - cu->bevel_radius;
fp += 3;
for (int i = cu->bevresol; i >= 0; i--) {
fp[0] = 0.0f;
fp[1] = quarter_coords_x[i];
- fp[2] = -quarter_coords_y[i] - cu->ext1;
+ fp[2] = -quarter_coords_y[i] - cu->extrude;
fp += 3;
}
}
@@ -147,8 +147,8 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
/* Add the extrusion if we're only building either the back or the front. */
if (use_extrude && ELEM(fill_type, FRONT, BACK)) {
fp[0] = 0.0f;
- fp[1] = cu->ext2;
- fp[2] = (fill_type == FRONT) ? -cu->ext1 : cu->ext1;
+ fp[1] = cu->bevel_radius;
+ fp[2] = (fill_type == FRONT) ? -cu->extrude : cu->extrude;
fp += 3;
}
@@ -159,13 +159,13 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
for (int i = front_start; i < cu->bevresol + 1; i++) {
fp[0] = 0.0f;
fp[1] = quarter_coords_x[i];
- fp[2] = quarter_coords_y[i] + cu->ext1;
+ fp[2] = quarter_coords_y[i] + cu->extrude;
fp += 3;
}
/* Add the top vertex. */
fp[0] = 0.0f;
fp[1] = 0.0f;
- fp[2] = cu->ext1 + cu->ext2;
+ fp[2] = cu->extrude + cu->bevel_radius;
fp += 3;
}
@@ -174,22 +174,22 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
for (int i = cu->bevresol; i > 0; i--) {
fp[0] = 0.0f;
fp[1] = -quarter_coords_x[i];
- fp[2] = quarter_coords_y[i] + cu->ext1;
+ fp[2] = quarter_coords_y[i] + cu->extrude;
fp += 3;
}
if (use_extrude) {
/* Add the extrusion. */
fp[0] = 0.0f;
- fp[1] = -cu->ext2;
- fp[2] = cu->ext1;
+ fp[1] = -cu->bevel_radius;
+ fp[2] = cu->extrude;
fp += 3;
}
for (int i = 0; i < cu->bevresol + 1; i++) {
fp[0] = 0.0f;
fp[1] = -quarter_coords_x[i];
- fp[2] = -quarter_coords_y[i] - cu->ext1;
+ fp[2] = -quarter_coords_y[i] - cu->extrude;
fp += 3;
}
}
@@ -213,8 +213,8 @@ static void curve_bevel_make_full_circle(const Curve *cu, ListBase *disp)
for (int i = 0; i < nr; i++) {
fp[0] = 0.0;
- fp[1] = (cosf(angle) * (cu->ext2));
- fp[2] = (sinf(angle) * (cu->ext2)) - cu->ext1;
+ fp[1] = (cosf(angle) * (cu->bevel_radius));
+ fp[2] = (sinf(angle) * (cu->bevel_radius)) - cu->extrude;
angle += dangle;
fp += 3;
}
@@ -232,9 +232,9 @@ static void curve_bevel_make_only_extrude(const Curve *cu, ListBase *disp)
float *fp = dl->verts;
fp[0] = fp[1] = 0.0;
- fp[2] = -cu->ext1;
+ fp[2] = -cu->extrude;
fp[3] = fp[4] = 0.0;
- fp[5] = cu->ext1;
+ fp[5] = cu->extrude;
}
static void curve_bevel_make_from_object(const Curve *cu, ListBase *disp)
@@ -247,7 +247,7 @@ static void curve_bevel_make_from_object(const Curve *cu, ListBase *disp)
}
Curve *bevcu = cu->bevobj->data;
- if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) {
+ if (bevcu->extrude == 0.0f && bevcu->bevel_radius == 0.0f) {
ListBase bevdisp = {NULL, NULL};
float facx = cu->bevobj->scale[0];
float facy = cu->bevobj->scale[1];
@@ -299,8 +299,8 @@ ListBase BKE_curve_bevel_make(const Curve *curve)
}
}
else {
- const bool use_extrude = curve->ext1 != 0.0f;
- const bool use_bevel = curve->ext2 != 0.0f;
+ const bool use_extrude = curve->extrude != 0.0f;
+ const bool use_bevel = curve->bevel_radius != 0.0f;
/* Pass. */
if (use_extrude && !use_bevel) {
curve_bevel_make_only_extrude(curve, &bevel_shape);
diff --git a/source/blender/blenkernel/intern/curve_deform.c b/source/blender/blenkernel/intern/curve_deform.c
index b8b8506d681..d754f8cc27d 100644
--- a/source/blender/blenkernel/intern/curve_deform.c
+++ b/source/blender/blenkernel/intern/curve_deform.c
@@ -410,12 +410,6 @@ void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve,
em_target);
}
-/**
- * \param orco: Input vec and orco = local coord in curve space
- * orco is original not-animated or deformed reference point.
- *
- * The result written in vec and r_mat.
- */
void BKE_curve_deform_co(const Object *ob_curve,
const Object *ob_target,
const float orco[3],
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index ff0478f2543..38f736e6907 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -50,12 +50,6 @@ blender::MutableSpan<SplinePtr> CurveEval::splines()
return splines_;
}
-/**
- * \return True if the curve contains a spline with the given type.
- *
- * \note If you are looping over all of the splines in the same scope anyway,
- * it's better to avoid calling this function, in case there are many splines.
- */
bool CurveEval::has_spline_with_type(const Spline::Type type) const
{
for (const SplinePtr &spline : this->splines()) {
@@ -72,14 +66,18 @@ void CurveEval::resize(const int size)
attributes.reallocate(size);
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all splines.
- */
void CurveEval::add_spline(SplinePtr spline)
{
splines_.append(std::move(spline));
}
+void CurveEval::add_splines(MutableSpan<SplinePtr> splines)
+{
+ for (SplinePtr &spline : splines) {
+ this->add_spline(std::move(spline));
+ }
+}
+
void CurveEval::remove_splines(blender::IndexMask mask)
{
for (int i = mask.size() - 1; i >= 0; i--) {
@@ -109,13 +107,24 @@ void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluate
}
}
-/**
- * Return the start indices for each of the curve spline's control points, if they were part
- * of a flattened array. This can be used to facilitate parallelism by avoiding the need to
- * accumulate an offset while doing more complex calculations.
- *
- * \note The result array is one longer than the spline count; the last element is the total size.
- */
+float CurveEval::total_length() const
+{
+ float length = 0.0f;
+ for (const SplinePtr &spline : this->splines()) {
+ length += spline->length();
+ }
+ return length;
+}
+
+int CurveEval::total_control_point_size() const
+{
+ int count = 0;
+ for (const SplinePtr &spline : this->splines()) {
+ count += spline->size();
+ }
+ return count;
+}
+
blender::Array<int> CurveEval::control_point_offsets() const
{
Array<int> offsets(splines_.size() + 1);
@@ -128,9 +137,6 @@ blender::Array<int> CurveEval::control_point_offsets() const
return offsets;
}
-/**
- * Exactly like #control_point_offsets, but uses the number of evaluated points instead.
- */
blender::Array<int> CurveEval::evaluated_point_offsets() const
{
Array<int> offsets(splines_.size() + 1);
@@ -143,11 +149,6 @@ blender::Array<int> CurveEval::evaluated_point_offsets() const
return offsets;
}
-/**
- * Return the accumulated length at the start of every spline in the curve.
- *
- * \note The result is one longer than the spline count; the last element is the total length.
- */
blender::Array<float> CurveEval::accumulated_spline_lengths() const
{
Array<float> spline_lengths(splines_.size() + 1);
@@ -343,13 +344,6 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
return curve_eval_from_dna_curve(dna_curve, *BKE_curve_nurbs_get_for_read(&dna_curve));
}
-/**
- * Check the invariants that curve control point attributes should always uphold, necessary
- * because attributes are stored on splines rather than in a flat array on the curve:
- * - The same set of attributes exists on every spline.
- * - Attributes with the same name have the same type on every spline.
- * - Attributes are in the same order on every spline.
- */
void CurveEval::assert_valid_point_attributes() const
{
#ifdef DEBUG
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 03525e32a52..5522a84d094 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -691,16 +691,6 @@ static void copy_spline_domain_attributes_to_mesh(const CurveEval &curve,
}
}
-/**
- * Extrude all splines in the profile curve along the path of every spline in the curve input.
- * Transfer curve attributes to the mesh.
- *
- * \note Normal calculation is by far the slowest part of calculations relating to the result mesh.
- * Although it would be a sensible decision to use the better topology information available while
- * generating the mesh to also generate the normals, that work may wasted if the output mesh is
- * changed anyway in a way that affects the normals. So currently this code uses the safer /
- * simpler solution of deferring normal calculation to the rest of Blender.
- */
Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, const bool fill_caps)
{
Span<SplinePtr> profiles = profile.splines();
@@ -776,10 +766,6 @@ static CurveEval get_curve_single_vert()
return curve;
}
-/**
- * Create a loose-edge mesh based on the evaluated path of the curve's splines.
- * Transfer curve attributes to the mesh.
- */
Mesh *curve_to_wire_mesh(const CurveEval &curve)
{
static const CurveEval vert_curve = get_curve_single_vert();
diff --git a/source/blender/blenkernel/intern/curveprofile.cc b/source/blender/blenkernel/intern/curveprofile.cc
index 7f2a2bc342d..387709fca29 100644
--- a/source/blender/blenkernel/intern/curveprofile.cc
+++ b/source/blender/blenkernel/intern/curveprofile.cc
@@ -44,9 +44,6 @@
/** \name Data Handling
* \{ */
-/**
- * Returns a pointer to a newly allocated curve profile, using the given preset.
- */
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset)
{
CurveProfile *profile = (CurveProfile *)MEM_callocN(sizeof(CurveProfile), __func__);
@@ -104,7 +101,6 @@ void BKE_curveprofile_blend_write(struct BlendWriter *writer, const struct Curve
BLO_write_struct_array(writer, CurveProfilePoint, profile->path_len, profile->path);
}
-/* Expects that the curve profile itself has been read already. */
void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurveProfile *profile)
{
BLO_read_data_address(reader, &profile->path);
@@ -125,14 +121,6 @@ void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurvePro
/** \name Editing
* \{ */
-/**
- * Move a point's handle, accounting for the alignment of handles with the #HD_ALIGN type.
- *
- * \param handle_1: Whether to move the 1st or 2nd control point.
- * \param delta: The *relative* change in the handle's position.
- * \note Requires #BKE_curveprofile_update call after.
- * \return Whether the handle moved from its start position.
- */
bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
const bool handle_1,
const bool snap,
@@ -173,14 +161,6 @@ bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
return false;
}
-/**
- * Moves a control point, accounting for clipping and snapping, and moving free handles.
- *
- * \param snap: Whether to snap the point to the grid
- * \param delta: The *relative* change of the point's location.
- * \return Whether the point moved from its start position.
- * \note Requires #BKE_curveprofile_update call after.
- */
bool BKE_curveprofile_move_point(struct CurveProfile *profile,
struct CurveProfilePoint *point,
const bool snap,
@@ -228,10 +208,6 @@ bool BKE_curveprofile_move_point(struct CurveProfile *profile,
return false;
}
-/**
- * Removes a specific point from the path of control points.
- * \note Requires #BKE_curveprofile_update call after.
- */
bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *point)
{
/* Must have 2 points minimum. */
@@ -262,13 +238,6 @@ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *poi
return true;
}
-/**
- * Removes every point in the widget with the supplied flag set, except for the first and last.
- *
- * \param flag: #CurveProfilePoint.flag.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_remove_by_flag(CurveProfile *profile, const short flag)
{
/* Copy every point without the flag into the new path. */
@@ -308,13 +277,6 @@ static void point_init(CurveProfilePoint *point, float x, float y, short flag, c
point->h2 = h2;
}
-/**
- * Adds a new point at the specified location. The choice for which points to place the new vertex
- * between is made by checking which control point line segment is closest to the new point and
- * placing the new vertex in between that segment's points.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float y)
{
const float new_loc[2] = {x, y};
@@ -370,11 +332,6 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float
return new_pt;
}
-/**
- * Sets the handle type of the selected control points.
- * \param type_1, type_2: Handle type for the first handle. HD_VECT, HD_AUTO, HD_FREE, or HD_ALIGN.
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_selected_handle_set(CurveProfile *profile, int type_1, int type_2)
{
for (int i = 0; i < profile->path_len; i++) {
@@ -397,11 +354,6 @@ static CurveProfilePoint mirror_point(const CurveProfilePoint *point)
return new_point;
}
-/**
- * Flips the profile across the diagonal so that its orientation is reversed.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_reverse(CurveProfile *profile)
{
/* When there are only two points, reversing shouldn't do anything. */
@@ -478,19 +430,11 @@ static void curveprofile_build_steps(CurveProfile *profile)
}
}
-/**
- * Reset the view to the clipping rectangle.
- */
void BKE_curveprofile_reset_view(CurveProfile *profile)
{
profile->view_rect = profile->clip_rect;
}
-/**
- * Resets the profile to the current preset.
- *
- * \note Requires #BKE_curveprofile_update call after.
- */
void BKE_curveprofile_reset(CurveProfile *profile)
{
MEM_SAFE_FREE(profile->path);
@@ -871,10 +815,6 @@ static void create_samples(CurveProfile *profile,
MEM_freeN(n_samples);
}
-/**
- * Sets the default settings and clip range for the profile widget.
- * Does not generate either table.
- */
void BKE_curveprofile_set_defaults(CurveProfile *profile)
{
profile->flag = PROF_USE_CLIP;
@@ -895,12 +835,6 @@ void BKE_curveprofile_set_defaults(CurveProfile *profile)
profile->changed_timestamp = 0;
}
-/**
- * Refreshes the higher resolution table sampled from the input points. A call to this or
- * #BKE_curveprofile_update is needed before evaluation functions that use the table.
- * Also sets the number of segments used for the display preview of the locations
- * of the sampled points.
- */
void BKE_curveprofile_init(CurveProfile *profile, short segments_len)
{
if (segments_len != profile->segments_len) {
@@ -1044,12 +978,6 @@ static void curveprofile_make_segments_table(CurveProfile *profile)
profile->segments = new_table;
}
-/**
- * Should be called after the widget is changed. Does profile and remove double checks and more
- * importantly, recreates the display / evaluation and segments tables.
- * \param update_flags: Bitfield with fields defined in header file. Controls removing doubles and
- * clipping.
- */
void BKE_curveprofile_update(CurveProfile *profile, const int update_flags)
{
CurveProfilePoint *points = profile->path;
@@ -1105,13 +1033,6 @@ void BKE_curveprofile_update(CurveProfile *profile, const int update_flags)
}
}
-/**
- * Does a single evaluation along the profile's path.
- * Travels down (length_portion * path) length and returns the position at that point.
- *
- * \param length_portion: The portion (0 to 1) of the path's full length to sample at.
- * \note Requires #BKE_curveprofile_init or #BKE_curveprofile_update call before to fill table.
- */
void BKE_curveprofile_evaluate_length_portion(const CurveProfile *profile,
float length_portion,
float *x_out,
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 743d5471aa7..090de26c230 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -73,7 +73,6 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "siz
static CLG_LogRef LOG = {"bke.customdata"};
-/** Update mask_dst with layers defined in mask_src (equivalent to a bitwise OR). */
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src)
{
@@ -84,7 +83,6 @@ void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
mask_dst->lmask |= mask_src->lmask;
}
-/** Return True if all layers set in \a mask_required are also set in \a mask_ref */
bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
const CustomData_MeshMasks *mask_required)
{
@@ -2182,7 +2180,6 @@ bool CustomData_merge(const struct CustomData *source,
return changed;
}
-/* NOTE: Take care of referenced layers by yourself! */
void CustomData_realloc(CustomData *data, int totelem)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -2444,8 +2441,6 @@ void CustomData_set_layer_stencil(CustomData *data, int type, int n)
}
}
-/* For using with an index from CustomData_get_active_layer_index and
- * CustomData_get_render_layer_index. */
void CustomData_set_layer_active_index(CustomData *data, int type, int n)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -2648,7 +2643,6 @@ void *CustomData_add_layer(
return NULL;
}
-/* Same as above but accepts a name. */
void *CustomData_add_layer_named(CustomData *data,
int type,
eCDAllocType alloctype,
@@ -3068,18 +3062,6 @@ void CustomData_free_elem(CustomData *data, int index, int count)
#define SOURCE_BUF_SIZE 100
-/**
- * Interpolate given custom data source items into a single destination one.
- *
- * \param src_indices: Indices of every source items to interpolate into the destination one.
- * \param weights: The weight to apply to each source value individually. If NULL, they will be
- * averaged.
- * \param sub_weights: The weights of sub-items, only used to affect each corners of a
- * tessellated face data (should always be and array of four values).
- * \param count: The number of source items to interpolate.
- * \param dest_index: Index of the destination item, in which to put the result of the
- * interpolation.
- */
void CustomData_interp(const CustomData *source,
CustomData *dest,
const int *src_indices,
@@ -3162,13 +3144,6 @@ void CustomData_interp(const CustomData *source,
}
}
-/**
- * Swap data inside each item, for all layers.
- * This only applies to item types that may store several sub-item data
- * (e.g. corner data [UVs, VCol, ...] of tessellated faces).
- *
- * \param corner_indices: A mapping 'new_index -> old_index' of sub-item data.
- */
void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -3182,9 +3157,6 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
}
}
-/**
- * Swap two items of given custom data, in all available layers.
- */
void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
{
char buff_static[256];
@@ -3362,7 +3334,7 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou
}
/* BMesh functions */
-/* needed to convert to/from different face reps */
+
void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
{
for (int i = 0; i < fdata->totlayer; i++) {
@@ -3418,12 +3390,6 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
}
#ifndef NDEBUG
-/**
- * Debug check, used to assert when we expect layers to be in/out of sync.
- *
- * \param fallback: Use when there are no layers to handle,
- * since callers may expect success or failure.
- */
bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback)
{
int a_num = 0, b_num = 0;
@@ -3491,11 +3457,6 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
}
}
-/* update active indices for active/render/clone/stencil custom data layers
- * based on indices from fdata layers
- * used by do_versions in readfile.c when creating pdata and ldata for pre-bmesh
- * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files
- */
void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
@@ -3677,9 +3638,6 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
*block = NULL;
}
-/**
- * Same as #CustomData_bmesh_free_block but zero the memory rather than freeing.
- */
void CustomData_bmesh_free_block_data(CustomData *data, void *block)
{
if (block == NULL) {
@@ -3713,9 +3671,6 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
}
}
-/**
- * A selective version of #CustomData_bmesh_free_block_data.
- */
void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
void *block,
const CustomDataMask mask_exclude)
@@ -3832,9 +3787,6 @@ void CustomData_bmesh_copy_data(const CustomData *source,
CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0);
}
-/* BMesh Custom Data Functions.
- * Should replace edit-mesh ones with these as well, due to more efficient memory alloc.
- */
void *CustomData_bmesh_get(const CustomData *data, void *block, int type)
{
/* get the layer index of the first layer of type */
@@ -3857,7 +3809,6 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
return POINTER_OFFSET(block, data->layers[layer_index + n].offset);
}
-/* Gets from the layer at physical index n, NOTE: doesn't check type. */
void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
{
if (n < 0 || n >= data->totlayer) {
@@ -3902,7 +3853,6 @@ bool CustomData_has_math(const struct CustomData *data)
return false;
}
-/* a non bmesh version would have to check layer->data */
bool CustomData_bmesh_has_free(const struct CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
@@ -3938,8 +3888,6 @@ bool CustomData_has_referenced(const struct CustomData *data)
return false;
}
-/* copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
- * another, while not overwriting anything else (e.g. flags). */
void CustomData_data_copy_value(int type, const void *source, void *dest)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -3956,8 +3904,6 @@ void CustomData_data_copy_value(int type, const void *source, void *dest)
}
}
-/* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
- * another, while not overwriting anything else (e.g. flags). */
void CustomData_data_mix_value(
int type, const void *source, void *dest, const int mixmode, const float mixfactor)
{
@@ -4074,10 +4020,6 @@ void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, const vo
}
}
-/**
- * \note src_blocks_ofs & dst_block_ofs
- * must be pointers to the data, offset by layer->offset already.
- */
void CustomData_bmesh_interp_n(CustomData *data,
const void **src_blocks_ofs,
const float *weights,
@@ -4146,11 +4088,6 @@ void CustomData_bmesh_interp(CustomData *data,
}
}
-/**
- * \param use_default_init: initializes data which can't be copied,
- * typically you'll want to use this if the BM_xxx create function
- * is called with BM_CREATE_SKIP_CD flag
- */
void CustomData_to_bmesh_block(const CustomData *source,
CustomData *dest,
int src_index,
@@ -4265,25 +4202,6 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str
*r_struct_num = typeInfo->structnum;
}
-/**
- * Prepare given custom data for file writing.
- *
- * \param data: the customdata to tweak for .blend file writing (modified in place).
- * \param r_write_layers: contains a reduced set of layers to be written to file,
- * use it with writestruct_at_address()
- * (caller must free it if != \a write_layers_buff).
- *
- * \param write_layers_buff: an optional buffer for r_write_layers (to avoid allocating it).
- * \param write_layers_size: the size of pre-allocated \a write_layer_buff.
- *
- * \warning After this func has ran, given custom data is no more valid from Blender PoV
- * (its totlayer is invalid). This func shall always be called with localized data
- * (as it is in write_meshes()).
- *
- * \note data->typemap is not updated here, since it is always rebuilt on file read anyway.
- * This means written typemap does not match written layers (as returned by \a r_write_layers).
- * Trivial to fix is ever needed.
- */
void CustomData_blend_write_prepare(CustomData *data,
CustomDataLayer **r_write_layers,
CustomDataLayer *write_layers_buff,
@@ -4337,20 +4255,12 @@ const char *CustomData_layertype_name(int type)
return layerType_getName(type);
}
-/**
- * Can only ever be one of these.
- */
bool CustomData_layertype_is_singleton(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
return typeInfo->defaultname == NULL;
}
-/**
- * Has dynamically allocated members.
- * This is useful to know if operations such as #memcmp are
- * valid when comparing data from two layers.
- */
bool CustomData_layertype_is_dynamic(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -4358,9 +4268,6 @@ bool CustomData_layertype_is_dynamic(int type)
return (typeInfo->free != NULL);
}
-/**
- * \return Maximum number of layers of given \a type, -1 means 'no limit'.
- */
int CustomData_layertype_layers_max(const int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -4502,12 +4409,6 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
return keeplayer;
}
-/**
- * Validate and fix data of \a layer,
- * if possible (needs relevant callback in layer's type to be defined).
- *
- * \return True if some errors were found.
- */
bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, const bool do_fixes)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
@@ -4971,7 +4872,6 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
MEM_freeN(tmp_dst);
}
-/* Normals are special, we need to take care of source & destination spaces... */
void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap,
void *data_dst,
const void **sources,
@@ -5118,9 +5018,6 @@ static void write_grid_paint_mask(BlendWriter *writer, int count, GridPaintMask
}
}
-/**
- * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
- */
void CustomData_blend_write(BlendWriter *writer,
CustomData *data,
CustomDataLayer *layers,
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index b83621e8b79..f036f1ced87 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -93,10 +93,6 @@ void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
}
}
-/**
- * Check what can do each layer type
- * (if it is actually handled by transfer-data, if it supports advanced mixing.
- */
bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
bool *r_advanced_mixing,
bool *r_threshold)
@@ -1232,12 +1228,6 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
return false;
}
-/**
- * Transfer data *layout* of selected types from source to destination object.
- * By default, it only creates new data layers if needed on \a ob_dst.
- * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those
- * from \a ob_src, to get (as much as possible) exact copy of source data layout.
- */
void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_src,
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index c5d7dd42cb8..e40b4946f52 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -68,6 +68,10 @@ bool data_transfer_layersmapping_vgroups(struct ListBase *r_map,
const int tolayers);
/* Defined in customdata.c */
+
+/**
+ * Normals are special, we need to take care of source & destination spaces.
+ */
void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap,
void *data_dst,
const void **sources,
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 13222747a52..6b429a146d4 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -107,11 +107,6 @@ bDeformGroup *BKE_defgroup_duplicate(const bDeformGroup *ingroup)
return outgroup;
}
-/**
- * Overwrite weights filtered by vgroup_subset.
- * - do nothing if neither are set.
- * - add destination weight if needed
- */
void BKE_defvert_copy_subset(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const bool *vgroup_subset,
@@ -125,11 +120,6 @@ void BKE_defvert_copy_subset(MDeformVert *dvert_dst,
}
}
-/**
- * Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
- * - do nothing if neither are set.
- * - add destination weight if needed
- */
void BKE_defvert_mirror_subset(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const bool *vgroup_subset,
@@ -168,11 +158,6 @@ void BKE_defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
}
}
-/**
- * Copy an index from one dvert to another.
- * - do nothing if neither are set.
- * - add destination weight if needed.
- */
void BKE_defvert_copy_index(MDeformVert *dvert_dst,
const int defgroup_dst,
const MDeformVert *dvert_src,
@@ -197,10 +182,6 @@ void BKE_defvert_copy_index(MDeformVert *dvert_dst,
}
}
-/**
- * Only sync over matching weights, don't add or remove groups
- * warning, loop within loop.
- */
void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool use_ensure)
{
if (dvert_src->totweight && dvert_dst->totweight) {
@@ -221,9 +202,6 @@ void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, cons
}
}
-/**
- * be sure all flip_map values are valid
- */
void BKE_defvert_sync_mapped(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const int *flip_map,
@@ -250,9 +228,6 @@ void BKE_defvert_sync_mapped(MDeformVert *dvert_dst,
}
}
-/**
- * be sure all flip_map values are valid
- */
void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
{
MDeformWeight *dw = dvert->dw;
@@ -265,9 +240,6 @@ void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
}
}
-/**
- * Same as #BKE_defvert_normalize but takes a bool array.
- */
void BKE_defvert_normalize_subset(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot)
@@ -334,9 +306,6 @@ void BKE_defvert_normalize(MDeformVert *dvert)
}
}
-/**
- * Same as BKE_defvert_normalize() if the locked vgroup is not a member of the subset
- */
void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
@@ -391,9 +360,6 @@ void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
}
}
-/**
- * Same as BKE_defvert_normalize() if no locked vgroup is a member of the subset
- */
void BKE_defvert_normalize_lock_map(MDeformVert *dvert,
const bool *vgroup_subset,
const int vgroup_tot,
@@ -557,11 +523,35 @@ bDeformGroup *BKE_object_defgroup_find_name(const Object *ob, const char *name)
int BKE_id_defgroup_name_index(const ID *id, const char *name)
{
- if (name == NULL || name[0] == '\0') {
+ int index;
+ if (!BKE_id_defgroup_name_find(id, name, &index, NULL)) {
return -1;
}
+ return index;
+}
+
+bool BKE_id_defgroup_name_find(const struct ID *id,
+ const char *name,
+ int *r_index,
+ struct bDeformGroup **r_group)
+{
+ if (name == NULL || name[0] == '\0') {
+ return false;
+ }
const ListBase *defbase = BKE_id_defgroup_list_get(id);
- return BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
+ int index;
+ LISTBASE_FOREACH_INDEX (bDeformGroup *, group, defbase, index) {
+ if (STREQ(name, group->name)) {
+ if (r_index != NULL) {
+ *r_index = index;
+ }
+ if (r_group != NULL) {
+ *r_group = group;
+ }
+ return true;
+ }
+ }
+ return false;
}
const ListBase *BKE_object_defgroup_list(const Object *ob)
@@ -586,17 +576,11 @@ int BKE_object_defgroup_count(const Object *ob)
return BLI_listbase_count(BKE_object_defgroup_list(ob));
}
-/**
- * \note For historical reasons, the index starts at 1 rather than 0.
- */
int BKE_object_defgroup_active_index_get(const Object *ob)
{
return *object_defgroup_active_index_get_p(ob);
}
-/**
- * \note For historical reasons, the index starts at 1 rather than 0.
- */
void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
{
/* Cast away const just for the accessor. */
@@ -604,9 +588,6 @@ void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
*index = new_index;
}
-/**
- * \note caller must free.
- */
int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const bool use_default)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
@@ -646,9 +627,6 @@ int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const boo
return map;
}
-/**
- * \note caller must free.
- */
int *BKE_object_defgroup_flip_map_single(const Object *ob,
int *flip_map_len,
const bool use_default,
@@ -745,13 +723,6 @@ float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgrou
return dw ? dw->weight : 0.0f;
}
-/**
- * Take care with this the rationale is:
- * - if the object has no vertex group. act like vertex group isn't set and return 1.0,
- * - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0
- *
- * This is a bit confusing, just saves some checks from the caller.
- */
float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert,
const int index,
const int defgroup)
@@ -790,11 +761,6 @@ MDeformWeight *BKE_defvert_find_index(const MDeformVert *dvert, const int defgro
return NULL;
}
-/**
- * Ensures that mv has a deform weight entry for the specified defweight group.
- *
- * \note this function is mirrored in editmesh_tools.c, for use for editvertices.
- */
MDeformWeight *BKE_defvert_ensure_index(MDeformVert *dvert, const int defgroup)
{
MDeformWeight *dw_new;
@@ -826,15 +792,10 @@ MDeformWeight *BKE_defvert_ensure_index(MDeformVert *dvert, const int defgroup)
return dw_new;
}
-/* TODO: merge with code above! */
-
-/**
- * Adds the given vertex to the specified vertex group, with given weight.
- *
- * \warning this does NOT check for existing, assume caller already knows its not there.
- */
void BKE_defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weight)
{
+ /* TODO: merge with #BKE_defvert_ensure_index! */
+
MDeformWeight *dw_new;
/* do this check always, this function is used to check for it */
@@ -856,11 +817,6 @@ void BKE_defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float
dvert->totweight++;
}
-/**
- * Removes the given vertex from the vertex group.
- *
- * \warning This function frees the given MDeformWeight, do not use it afterward!
- */
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
{
if (dvert && dw) {
@@ -899,10 +855,6 @@ void BKE_defvert_clear(MDeformVert *dvert)
dvert->totweight = 0;
}
-/**
- * \return The first group index shared by both deform verts
- * or -1 if none are found.
- */
int BKE_defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b)
{
if (dvert_a->totweight && dvert_b->totweight) {
@@ -919,9 +871,6 @@ int BKE_defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert
return -1;
}
-/**
- * return true if has no weights
- */
bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot)
{
MDeformWeight *dw = dvert->dw;
@@ -936,9 +885,6 @@ bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgr
return true;
}
-/**
- * \return The total weight in all groups marked in the selection mask.
- */
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel)
@@ -961,14 +907,6 @@ float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
return total;
}
-/**
- * \return The representative weight of a multipaint group, used for
- * viewport colors and actual painting.
- *
- * Result equal to sum of weights with auto normalize, and average otherwise.
- * Value is not clamped, since painting relies on multiplication being always
- * commutative with the collective weight function.
- */
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
int defbase_tot,
const bool *defbase_sel,
@@ -986,11 +924,6 @@ float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
return total;
}
-/**
- * Computes the display weight for the lock relative weight paint mode.
- *
- * \return weight divided by 1-locked_weight with division by zero check
- */
float BKE_defvert_calc_lock_relative_weight(float weight,
float locked_weight,
float unlocked_weight)
@@ -1019,11 +952,6 @@ float BKE_defvert_calc_lock_relative_weight(float weight,
return weight / (1.0f - locked_weight);
}
-/**
- * Computes the display weight for the lock relative weight paint mode, using weight data.
- *
- * \return weight divided by unlocked, or 1-locked_weight with division by zero check.
- */
float BKE_defvert_lock_relative_weight(float weight,
const struct MDeformVert *dv,
int defbase_tot,
@@ -1115,10 +1043,6 @@ void BKE_defvert_extract_vgroup_to_vertweights(MDeformVert *dvert,
}
}
-/**
- * The following three make basic interpolation,
- * using temp vert_weights array to avoid looking up same weight several times.
- */
void BKE_defvert_extract_vgroup_to_edgeweights(MDeformVert *dvert,
const int defgroup,
const int num_verts,
@@ -1451,7 +1375,7 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map,
* and even have to support NULL data_src in transfer data code
* (we always create a data_dst, though).
*
- * Note: Above comment is outdated, but this function was written when that was true.
+ * NOTE: Above comment is outdated, but this function was written when that was true.
*/
const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 0bf436aa8b2..edf043de63f 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -66,8 +66,6 @@
using blender::IndexRange;
-static void boundbox_displist_object(Object *ob);
-
static void displist_elem_free(DispList *dl)
{
if (dl) {
@@ -404,12 +402,6 @@ static void curve_to_displist(const Curve *cu,
}
}
-/**
- * \param normal_proj: Optional normal that's used to project the scanfill verts into 2d coords.
- * Pass this along if known since it saves time calculating the normal.
- * This is also used to initialize #DispList.nors (one normal per display list).
- * \param flipnormal: Flip the normal (same as passing \a normal_proj negated)
- */
void BKE_displist_fill(const ListBase *dispbase,
ListBase *to,
const float normal_proj[3],
@@ -832,7 +824,7 @@ static bool do_curve_implicit_mesh_conversion(const Curve *curve,
}
/* Curve objects with implicit "tube" meshes should convert implicitly to a mesh. */
- if (curve->ext1 != 0.0f || curve->ext2 != 0.0f) {
+ if (curve->extrude != 0.0f || curve->bevel_radius != 0.0f) {
return true;
}
@@ -1312,11 +1304,11 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
ListBase dlbev = BKE_curve_bevel_make(cu);
/* no bevel or extrude, and no width correction? */
- if (BLI_listbase_is_empty(&dlbev) && cu->width == 1.0f) {
+ if (BLI_listbase_is_empty(&dlbev) && cu->offset == 1.0f) {
curve_to_displist(cu, deformed_nurbs, for_render, r_dispbase);
}
else {
- const float widfac = cu->width - 1.0f;
+ const float widfac = cu->offset - 1.0f;
const BevList *bl = (BevList *)ob->runtime.curve_cache->bev.first;
const Nurb *nu = (Nurb *)deformed_nurbs->first;
@@ -1528,7 +1520,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
ob->runtime.geometry_set_eval = new GeometrySet(std::move(geometry));
}
- boundbox_displist_object(ob);
+ BKE_object_boundbox_calc_from_evaluated_geometry(ob);
}
void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
@@ -1536,7 +1528,7 @@ void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
bool doit = false;
LISTBASE_FOREACH (const DispList *, dl, dispbase) {
- const int tot = (dl->type == DL_INDEX3) ? dl->nr : dl->nr * dl->parts;
+ const int tot = (ELEM(dl->type, DL_INDEX3, DL_INDEX4)) ? dl->nr : dl->nr * dl->parts;
for (const int i : IndexRange(tot)) {
minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
}
@@ -1551,30 +1543,3 @@ void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
zero_v3(max);
}
}
-
-/* this is confusing, there's also min_max_object, applying the obmat... */
-static void boundbox_displist_object(Object *ob)
-{
- BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT));
- /* Curve's BB is already calculated as a part of modifier stack,
- * here we only calculate object BB based on final display list. */
-
- /* object's BB is calculated from final displist */
- if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
- }
-
- const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
- if (mesh_eval) {
- BKE_object_boundbox_calc_from_mesh(ob, mesh_eval);
- }
- else {
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
-
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
- }
-}
diff --git a/source/blender/blenkernel/intern/displist_tangent.c b/source/blender/blenkernel/intern/displist_tangent.c
index 5c969d52aea..4451961ad94 100644
--- a/source/blender/blenkernel/intern/displist_tangent.c
+++ b/source/blender/blenkernel/intern/displist_tangent.c
@@ -29,6 +29,10 @@
/* interface */
#include "mikktspace.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct {
const DispList *dl;
float (*tangent)[4]; /* destination */
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 05f1e9b286f..ce92a34de47 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -327,7 +327,6 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
return 0;
}
-/* get currently active surface (in user interface) */
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
{
return BLI_findlink(&canvas->surfaces, canvas->active_sur);
@@ -420,7 +419,6 @@ void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char
surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
}
-/* change surface data to defaults on new type */
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
{
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
@@ -855,7 +853,6 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/***************************** Freeing data ******************************/
-/* Free brush data */
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
{
if (pmd->brush) {
@@ -992,7 +989,6 @@ void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd, DynamicPaintS
MEM_freeN(surface);
}
-/* Free canvas data */
void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
{
if (pmd->canvas) {
@@ -1011,7 +1007,6 @@ void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
}
}
-/* Free whole dp modifier */
void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
{
if (pmd == NULL) {
@@ -1024,11 +1019,6 @@ void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
/***************************** Initialize and reset ******************************/
-/*
- * Creates a new surface and adds it to the list
- * If scene is null, frame range of 1-250 is used
- * A pointer to this surface is returned
- */
DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas,
Scene *scene)
{
@@ -1106,9 +1096,6 @@ DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *c
return surface;
}
-/*
- * Initialize modifier data
- */
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
{
if (pmd) {
@@ -1721,7 +1708,6 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
}
-/* clears surface data back to zero */
void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
@@ -1751,7 +1737,6 @@ void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
}
}
-/* Completely (re)initializes surface (only for point cache types). */
bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
@@ -2079,7 +2064,6 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
return result;
}
-/* update cache frame range */
void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
{
if (surface->pointcache) {
@@ -2189,7 +2173,6 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd,
}
}
-/* Modifier call. Processes dynamic paint modifier step. */
Mesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd,
struct Depsgraph *depsgraph,
Scene *scene,
@@ -6369,9 +6352,6 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
return ret;
}
-/**
- * Calculate a single frame and included sub-frames for surface.
- */
int dynamicPaint_calculateFrame(DynamicPaintSurface *surface,
struct Depsgraph *depsgraph,
Scene *scene,
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 83e03ef44f5..805d3cdb5e3 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -39,10 +39,6 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_object.h"
-/**
- * \note The caller is responsible for ensuring triangulation data,
- * typically by calling #BKE_editmesh_looptri_calc.
- */
BMEditMesh *BKE_editmesh_create(BMesh *bm)
{
BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
@@ -75,12 +71,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
return em_copy;
}
-/**
- * \brief Return the BMEditMesh for a given object
- *
- * \note this function assumes this is a mesh object,
- * don't add NULL data check here. caller must do that
- */
BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
@@ -158,10 +148,6 @@ void BKE_editmesh_looptri_calc(BMEditMesh *em)
});
}
-/**
- * Performing the face normal calculation at the same time as tessellation
- * gives a reasonable performance boost (approx ~20% faster).
- */
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em)
{
BKE_editmesh_looptri_calc_ex(em,
@@ -221,7 +207,6 @@ void BKE_editmesh_free_derived_caches(BMEditMesh *em)
MEM_SAFE_FREE(em->bb_cage);
}
-/* Does not free the #BMEditMesh struct itself. */
void BKE_editmesh_free_data(BMEditMesh *em)
{
BKE_editmesh_free_derived_caches(em);
@@ -342,7 +327,6 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me)
BM_lnorspace_update(bm);
}
-/* If autosmooth not already set, set it */
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
{
if (!(me->flag & ME_AUTOSMOOTH)) {
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index 5058863912f..e200a504b5d 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -565,9 +565,6 @@ static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSE
((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
}
-/**
- * Overlap indices reference the looptri's
- */
BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a,
const BMBVHTree *bmtree_b,
unsigned int *r_overlap_tot)
@@ -591,9 +588,6 @@ static bool bmbvh_overlap_self_cb(void *userdata, int index_a, int index_b, int
return false;
}
-/**
- * Overlap indices reference the looptri's
- */
BVHTreeOverlap *BKE_bmbvh_overlap_self(const BMBVHTree *bmtree, unsigned int *r_overlap_tot)
{
struct BMBVHTree_OverlapData data;
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index da4ea742656..ff0d47e534e 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.c
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -273,13 +273,6 @@ static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), vo
}
}
-/**
- * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
- *
- * \note This function is not so normal, its using #BMesh.ldata as input,
- * but output's to #Mesh.ldata.
- * This is done because #CD_TANGENT is cache data used only for drawing.
- */
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index a88339082fe..8229228976c 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -221,9 +221,6 @@ static void add_effector_evaluation(ListBase **effectors,
precalculate_effector(depsgraph, eff);
}
-/* Create list of effector relations in the collection or entire scene.
- * This is used by the depsgraph to build relations, as well as faster
- * lookup of effectors during evaluation. */
ListBase *BKE_effector_relations_create(Depsgraph *depsgraph,
ViewLayer *view_layer,
Collection *collection)
@@ -329,7 +326,6 @@ static bool is_effector_relevant(PartDeflect *pd, EffectorWeights *weights, bool
is_effector_nonzero_strength(pd);
}
-/* Create effective list of effectors from relations built beforehand. */
ListBase *BKE_effectors_create(Depsgraph *depsgraph,
Object *ob_src,
ParticleSystem *psys_src,
@@ -656,11 +652,11 @@ float effector_falloff(EffectorCache *eff,
return falloff;
}
-int closest_point_on_surface(SurfaceModifierData *surmd,
- const float co[3],
- float surface_co[3],
- float surface_nor[3],
- float surface_vel[3])
+bool closest_point_on_surface(SurfaceModifierData *surmd,
+ const float co[3],
+ float surface_co[3],
+ float surface_nor[3],
+ float surface_vel[3])
{
BVHTreeNearest nearest;
@@ -687,18 +683,18 @@ int closest_point_on_surface(SurfaceModifierData *surmd,
mul_v3_fl(surface_vel, (1.0f / 3.0f));
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-int get_effector_data(EffectorCache *eff,
- EffectorData *efd,
- EffectedPoint *point,
- int real_velocity)
+bool get_effector_data(EffectorCache *eff,
+ EffectorData *efd,
+ EffectedPoint *point,
+ int real_velocity)
{
float cfra = DEG_get_ctime(eff->depsgraph);
- int ret = 0;
+ bool ret = false;
/* In case surface object is in Edit mode when loading the .blend,
* surface modifier is never executed and bvhtree never built, see T48415. */
@@ -730,7 +726,7 @@ int get_effector_data(EffectorCache *eff,
efd->size = 0.0f;
- ret = 1;
+ ret = true;
}
}
else if (eff->psys) {
@@ -798,7 +794,7 @@ int get_effector_data(EffectorCache *eff,
zero_v3(efd->vel);
efd->size = 0.0f;
- ret = 1;
+ ret = true;
}
if (ret) {
@@ -1130,20 +1126,6 @@ static void do_physical_effector(EffectorCache *eff,
}
}
-/* -------- BKE_effectors_apply() --------
- * generic force/speed system, now used for particles and softbodies
- * scene = scene where it runs in, for time and stuff
- * lb = listbase with objects that take part in effecting
- * opco = global coord, as input
- * force = accumulator for force
- * wind_force = accumulator for force only acting perpendicular to a surface
- * speed = actual current speed which can be altered
- * cur_time = "external" time in frames, is constant for static particles
- * loc_time = "local" time in frames, range <0-1> for the lifetime of particle
- * par_layer = layer the caller is in
- * flags = only used for softbody wind now
- * guide = old speed of particle
- */
void BKE_effectors_apply(ListBase *effectors,
ListBase *colliders,
EffectorWeights *weights,
@@ -1152,6 +1134,22 @@ void BKE_effectors_apply(ListBase *effectors,
float *wind_force,
float *impulse)
{
+ /* WARNING(@campbellbarton): historic comment?
+ * Many of these parameters don't exist!
+ *
+ * scene = scene where it runs in, for time and stuff.
+ * lb = listbase with objects that take part in effecting.
+ * opco = global coord, as input.
+ * force = accumulator for force.
+ * wind_force = accumulator for force only acting perpendicular to a surface.
+ * speed = actual current speed which can be altered.
+ * cur_time = "external" time in frames, is constant for static particles.
+ * loc_time = "local" time in frames, range <0-1> for the lifetime of particle.
+ * par_layer = layer the caller is in.
+ * flags = only used for soft-body wind now.
+ * guide = old speed of particle.
+ */
+
/*
* Modifies the force on a particle according to its
* relation with the effector object
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index bbf61c51bfb..5bbfc0913a1 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -77,7 +77,6 @@ FCurve *BKE_fcurve_create(void)
/** \name F-Curve Data Free
* \{ */
-/* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */
void BKE_fcurve_free(FCurve *fcu)
{
if (fcu == NULL) {
@@ -99,7 +98,6 @@ void BKE_fcurve_free(FCurve *fcu)
MEM_freeN(fcu);
}
-/* Frees a list of F-Curves. */
void BKE_fcurves_free(ListBase *list)
{
FCurve *fcu, *fcn;
@@ -128,7 +126,6 @@ void BKE_fcurves_free(ListBase *list)
/** \name F-Curve Data Copy
* \{ */
-/* Duplicate a F-Curve. */
FCurve *BKE_fcurve_copy(const FCurve *fcu)
{
FCurve *fcu_d;
@@ -161,7 +158,6 @@ FCurve *BKE_fcurve_copy(const FCurve *fcu)
return fcu_d;
}
-/* Duplicate a list of F-Curves. */
void BKE_fcurves_copy(ListBase *dst, ListBase *src)
{
FCurve *dfcu, *sfcu;
@@ -181,10 +177,6 @@ void BKE_fcurves_copy(ListBase *dst, ListBase *src)
}
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
{
ChannelDriver *driver = fcu->driver;
@@ -221,7 +213,6 @@ void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
/* ----------------- Finding F-Curves -------------------------- */
-/* High level function to get an fcurve from C without having the RNA. */
FCurve *id_data_find_fcurve(
ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
{
@@ -273,8 +264,6 @@ FCurve *id_data_find_fcurve(
return fcu;
}
-/* Find the F-Curve affecting the given RNA-access path + index,
- * in the list of F-Curves provided. */
FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index)
{
FCurve *fcu;
@@ -304,7 +293,6 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i
/** \name FCurve Iteration
* \{ */
-/* Quick way to loop over all fcurves of a given 'path'. */
FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
{
FCurve *fcu;
@@ -325,18 +313,6 @@ FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
return NULL;
}
-/**
- * Get list of LinkData's containing pointers to the F-Curves
- * which control the types of data indicated.
- *
- * Lists...
- * - dst: list of LinkData's matching the criteria returned.
- * List must be freed after use, and is assumed to be empty when passed.
- * - src: list of F-Curves to search through
- * Filters...
- * - dataPrefix: i.e. 'pose.bones[' or 'nodes['
- * - dataName: name of entity within "" immediately following the prefix
- */
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName)
{
FCurve *fcu;
@@ -601,9 +577,6 @@ static int BKE_fcurve_bezt_binarysearch_index_ex(const BezTriple array[],
return start;
}
-/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve)
- * Returns the index to insert at (data already at that index will be offset if replace is 0)
- */
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[],
const float frame,
const int arraylen,
@@ -667,7 +640,6 @@ static short get_fcurve_end_keyframes(FCurve *fcu,
return found;
}
-/* Calculate the extents of F-Curve's data. */
bool BKE_fcurve_calc_bounds(FCurve *fcu,
float *xmin,
float *xmax,
@@ -798,7 +770,6 @@ bool BKE_fcurve_calc_bounds(FCurve *fcu,
return foundvert;
}
-/* Calculate the extents of F-Curve's keyframes. */
bool BKE_fcurve_calc_range(
FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
{
@@ -846,14 +817,6 @@ bool BKE_fcurve_calc_range(
return foundvert;
}
-/**
- * Return an array of keyed frames, rounded to `interval`.
- *
- * \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc.
- *
- * \note An interval of zero could be supported (this implies no rounding at all),
- * however this risks very small differences in float values being treated as separate keyframes.
- */
float *BKE_fcurves_calc_keyed_frames_ex(FCurve **fcurve_array,
int fcurve_array_len,
const float interval,
@@ -902,10 +865,6 @@ float *BKE_fcurves_calc_keyed_frames(FCurve **fcurve_array,
/** \name Active Keyframe
* \{ */
-/**
- * Set the index that stores the FCurve's active keyframe, assuming that \a active_bezt
- * is already part of `fcu->bezt`. If NULL, set active keyframe index to "none."
- */
void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
{
if (active_bezt == NULL) {
@@ -927,9 +886,6 @@ void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
fcu->active_keyframe_index = (int)offset;
}
-/**
- * Get the active keyframe index, with sanity checks for point bounds.
- */
int BKE_fcurve_active_keyframe_index(const FCurve *fcu)
{
const int active_keyframe_index = fcu->active_keyframe_index;
@@ -963,10 +919,6 @@ void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, con
/** \name Status Checks
* \{ */
-/* Are keyframes on F-Curve of any use?
- * Usability of keyframes refers to whether they should be displayed,
- * and also whether they will have any influence on the final result.
- */
bool BKE_fcurve_are_keyframes_usable(FCurve *fcu)
{
/* F-Curve must exist. */
@@ -1032,9 +984,6 @@ bool BKE_fcurve_is_protected(FCurve *fcu)
return ((fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)));
}
-/* Can keyframes be added to F-Curve?
- * Keyframes can only be added if they are already visible.
- */
bool BKE_fcurve_is_keyframable(FCurve *fcu)
{
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
@@ -1057,7 +1006,6 @@ bool BKE_fcurve_is_keyframable(FCurve *fcu)
/** \name Keyframe Column Tools
* \{ */
-/* Add a BezTriple to a column. */
static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt)
{
CfraElem *ce, *cen;
@@ -1100,18 +1048,12 @@ static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt
* which BezTriples/Keyframe data are ill equipped to do.
*/
-/* Basic sampling callback which acts as a wrapper for evaluate_fcurve()
- * 'data' arg here is unneeded here...
- */
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime)
{
/* Assume any interference from drivers on the curve is intended... */
return evaluate_fcurve(fcu, evaltime);
}
-/* Main API function for creating a set of sampled curve data, given some callback function
- * used to retrieve the values to store.
- */
void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
{
FPoint *fpt, *new_fpt;
@@ -1159,7 +1101,6 @@ static void init_unbaked_bezt_data(BezTriple *bezt)
bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
}
-/* Convert baked/sampled fcurves into bezt/regular fcurves. */
void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
{
@@ -1235,7 +1176,6 @@ void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
* that the handles are correct.
*/
-/* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
{
FModifier *fcm = fcu->modifiers.first;
@@ -1269,8 +1209,6 @@ eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
return FCU_CYCLE_NONE;
}
-/* Checks if the F-Curve has a Cycles modifier with simple settings
- * that warrant transition smoothing. */
bool BKE_fcurve_is_cyclic(FCurve *fcu)
{
return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
@@ -1299,13 +1237,6 @@ static BezTriple *cycle_offset_triple(
return out;
}
-/**
- * Variant of #calchandles_fcurve() that allows calculating based on a different select flag.
- *
- * \param handle_sel_flag: The flag (bezt.f1/2/3) value to use to determine selection.
- * Usually `SELECT`, but may want to use a different one at times
- * (if caller does not operate on selection).
- */
void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
{
BezTriple *bezt, *prev, *next;
@@ -1389,28 +1320,11 @@ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
}
}
-/**
- * This function recalculates the handles of an F-Curve. Acts based on selection with `SELECT`
- * flag. To use a different flag, use #calchandles_fcurve_ex().
- *
- * If the BezTriples have been rearranged, sort them first before using this.
- */
void calchandles_fcurve(FCurve *fcu)
{
calchandles_fcurve_ex(fcu, SELECT);
}
-/**
- * Update handles, making sure the handle-types are valid (e.g. correctly deduced from an "Auto"
- * type), and recalculating their position vectors.
- * Use when something has changed handle positions.
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- * \param use_handle: Check selection state of individual handles, otherwise always update both
- * handles if the key is selected.
- */
void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle)
{
BezTriple *bezt;
@@ -1430,9 +1344,6 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha
calchandles_fcurve_ex(fcu, sel_flag);
}
-/* This function sorts BezTriples so that they are arranged in chronological order,
- * as tools working on F-Curves expect that the BezTriples are in order.
- */
void sort_time_fcurve(FCurve *fcu)
{
if (fcu->bezt == NULL) {
@@ -1475,7 +1386,6 @@ void sort_time_fcurve(FCurve *fcu)
}
}
-/* This function tests if any BezTriples are out of order, thus requiring a sort. */
bool test_time_fcurve(FCurve *fcu)
{
unsigned int a;
@@ -1517,14 +1427,6 @@ bool test_time_fcurve(FCurve *fcu)
/** \name F-Curve Calculations
* \{ */
-/**
- * The length of each handle is not allowed to be more
- * than the horizontal distance between (v1-v4).
- * This is to prevent curve loops.
- *
- * This function is very similar to BKE_curve_correct_bezpart(), but allows a steeper tangent for
- * more snappy animations. This is not desired for other areas in which curves are used, though.
- */
void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
{
float h1[2], h2[2], len1, len2, len, fac;
@@ -1709,14 +1611,6 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
}
}
-/**
- * Adjust Bezier handles of all three given BezTriples, so that `bezt` can be inserted between
- * `prev` and `next` without changing the resulting curve shape.
- *
- * \param r_pdelta: return Y difference between `bezt` and the original curve value at its X
- * position.
- * \return Whether the split was successful.
- */
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
@@ -2252,14 +2146,12 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna,
return evaluate_fcurve_ex(fcu, evaltime, cvalue);
}
-/* Checks if the curve has valid keys, drivers or modifiers that produce an actual curve. */
bool BKE_fcurve_is_empty(FCurve *fcu)
{
return (fcu->totvert == 0) && (fcu->driver == NULL) &&
!list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE);
}
-/* Calculate the value of the given F-Curve at the given frame, and set its curval. */
float calculate_fcurve(PathResolvedRNA *anim_rna,
FCurve *fcu,
const AnimationEvalContext *anim_eval_context)
diff --git a/source/blender/blenkernel/intern/fcurve_cache.c b/source/blender/blenkernel/intern/fcurve_cache.c
index 8142b871edd..4f27bad5b91 100644
--- a/source/blender/blenkernel/intern/fcurve_cache.c
+++ b/source/blender/blenkernel/intern/fcurve_cache.c
@@ -155,11 +155,6 @@ FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
return NULL;
}
-/**
- * Fill in an array of F-Curve, leave NULL when not found.
- *
- * \return The number of F-Curves found.
- */
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
FCurve **fcurve_result,
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 3ac64dbf84b..5496519e53b 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -199,9 +199,6 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
return value;
}
-/**
- * Same as 'dtar_get_prop_val'. but get the RNA property.
- */
bool driver_get_variable_property(ChannelDriver *driver,
DriverTarget *dtar,
PointerRNA *r_ptr,
@@ -621,7 +618,6 @@ static void quaternion_to_angles(float quat[4], int channel)
}
}
-/* Compute channel values for a rotational Transform Channel driver variable. */
void BKE_driver_target_matrix_to_rot_channels(
float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4])
{
@@ -720,7 +716,6 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
/** \name Driver API
* \{ */
-/* Perform actual freeing driver variable and remove it from the given list */
void driver_free_variable(ListBase *variables, DriverVar *dvar)
{
/* Sanity checks. */
@@ -745,7 +740,6 @@ void driver_free_variable(ListBase *variables, DriverVar *dvar)
BLI_freelinkN(variables, dvar);
}
-/* Free the driver variable and do extra updates */
void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
{
/* Remove and free the driver variable. */
@@ -755,7 +749,6 @@ void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
BKE_driver_invalidate_expression(driver, false, true);
}
-/* Copy driver variables from src_vars list to dst_vars list */
void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
{
BLI_assert(BLI_listbase_is_empty(dst_vars));
@@ -773,7 +766,6 @@ void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
}
}
-/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
@@ -803,7 +795,6 @@ void driver_change_variable_type(DriverVar *dvar, int type)
DRIVER_TARGETS_LOOPER_END;
}
-/* Validate driver name (after being renamed) */
void driver_variable_name_validate(DriverVar *dvar)
{
/* Special character blacklist */
@@ -873,7 +864,6 @@ void driver_variable_name_validate(DriverVar *dvar)
}
}
-/* Add a new driver variable */
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
DriverVar *dvar;
@@ -906,7 +896,6 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
return dvar;
}
-/* This frees the driver itself */
void fcurve_free_driver(FCurve *fcu)
{
ChannelDriver *driver;
@@ -939,7 +928,6 @@ void fcurve_free_driver(FCurve *fcu)
fcu->driver = NULL;
}
-/* This makes a copy of the given driver */
ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
{
ChannelDriver *ndriver;
@@ -1082,7 +1070,6 @@ static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
}
-/* Check if the expression in the driver conforms to the simple subset. */
bool BKE_driver_has_simple_expression(ChannelDriver *driver)
{
return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
@@ -1109,7 +1096,6 @@ static bool python_driver_exression_depends_on_time(const char *expression)
return false;
}
-/* Check if the expression in the driver may depend on the current frame. */
bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
{
if (driver->type != DRIVER_TYPE_PYTHON) {
@@ -1125,7 +1111,6 @@ bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
return python_driver_exression_depends_on_time(driver->expression);
}
-/* Reset cached compiled expression data */
void BKE_driver_invalidate_expression(ChannelDriver *driver,
bool expr_changed,
bool varname_changed)
@@ -1152,7 +1137,6 @@ void BKE_driver_invalidate_expression(ChannelDriver *driver,
/** \name Driver Evaluation
* \{ */
-/* Evaluate a Driver Variable to get a value that contributes to the final */
float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
{
const DriverVarTypeInfo *dvti;
@@ -1269,14 +1253,6 @@ static void evaluate_driver_python(PathResolvedRNA *anim_rna,
}
}
-/**
- * Evaluate an Channel-Driver to get a 'time' value to use
- * instead of `anim_eval_context->eval_time`.
- *
- * - `anim_eval_context->eval_time` is the frame at which F-Curve is being evaluated.
- * - Has to return a float value.
- * - \a driver_orig is where we cache Python expressions, in case of COW
- */
float evaluate_driver(PathResolvedRNA *anim_rna,
ChannelDriver *driver,
ChannelDriver *driver_orig,
@@ -1309,3 +1285,5 @@ float evaluate_driver(PathResolvedRNA *anim_rna,
/* Return value for driver. */
return driver->curval;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 9d26a1528f3..39122b33683 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -4437,8 +4437,6 @@ static void manta_smoke_calc_transparency(FluidDomainSettings *fds, ViewLayer *v
}
}
-/* Get fluid velocity and density at given coordinates
- * Returns fluid density or -1.0f if outside domain. */
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
{
FluidModifierData *fmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
@@ -4575,10 +4573,10 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
}
}
-#endif /* WITH_FLUID */
-
/** \} */
+#endif /* WITH_FLUID */
+
/* -------------------------------------------------------------------- */
/** \name Public Data Access API
*
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 121927513cc..d140e70978a 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1065,10 +1065,6 @@ static void fmods_init_typeinfo(void)
fmodifiersTypeInfo[9] = &FMI_STEPPED; /* Stepped F-Curve Modifier */
}
-/**
- * This function should be used for getting the appropriate type-info when only
- * a F-Curve modifier type is known.
- */
const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
{
/* initialize the type-info list? */
@@ -1088,10 +1084,6 @@ const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
return NULL;
}
-/**
- * This function should always be used to get the appropriate type-info,
- * as it has checks which prevent segfaults in some weird cases.
- */
const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
{
/* only return typeinfo for valid modifiers */
@@ -1108,9 +1100,6 @@ const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
/** \name F-Curve Modifier Public API
* \{ */
-/**
- * Add a new F-Curve Modifier to the given F-Curve of a certain type.
- */
FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
{
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
@@ -1161,9 +1150,6 @@ FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
return fcm;
}
-/**
- * Make a copy of the specified F-Modifier.
- */
FModifier *copy_fmodifier(const FModifier *src)
{
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
@@ -1191,9 +1177,6 @@ FModifier *copy_fmodifier(const FModifier *src)
return dst;
}
-/**
- * Duplicate all of the F-Modifiers in the Modifier stacks.
- */
void copy_fmodifiers(ListBase *dst, const ListBase *src)
{
FModifier *fcm, *srcfcm;
@@ -1220,9 +1203,6 @@ void copy_fmodifiers(ListBase *dst, const ListBase *src)
}
}
-/**
- * Remove and free the given F-Modifier from the given stack.
- */
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
{
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
@@ -1263,9 +1243,6 @@ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
return false;
}
-/**
- * Remove all of a given F-Curve's modifiers.
- */
void free_fmodifiers(ListBase *modifiers)
{
FModifier *fcm, *fmn;
@@ -1282,9 +1259,6 @@ void free_fmodifiers(ListBase *modifiers)
}
}
-/**
- * Find the active F-Modifier.
- */
FModifier *find_active_fmodifier(ListBase *modifiers)
{
FModifier *fcm;
@@ -1305,9 +1279,6 @@ FModifier *find_active_fmodifier(ListBase *modifiers)
return NULL;
}
-/**
- * Set the active F-Modifier.
- */
void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
{
FModifier *fm;
@@ -1328,12 +1299,6 @@ void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
}
}
-/**
- * Do we have any modifiers which match certain criteria.
- *
- * \param mtype: Type of modifier (if 0, doesn't matter).
- * \param acttype: Type of action to perform (if -1, doesn't matter).
- */
bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
{
FModifier *fcm;
@@ -1443,19 +1408,6 @@ static float eval_fmodifier_influence(FModifier *fcm, float evaltime)
return influence;
}
-/**
- * Evaluate time modifications imposed by some F-Curve Modifiers.
- *
- * - This step acts as an optimization to prevent the F-Curve stack being evaluated
- * several times by modifiers requesting the time be modified, as the final result
- * would have required using the modified time
- * - Modifiers only ever receive the unmodified time, as subsequent modifiers should be
- * working on the 'global' result of the modified curve, not some localized segment,
- * so \a evaltime gets set to whatever the last time-modifying modifier likes.
- * - We start from the end of the stack, as only the last one matters for now.
- *
- * \param fcu: Can be NULL.
- */
float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
FCurve *fcu,
@@ -1513,10 +1465,6 @@ float evaluate_time_fmodifiers(FModifiersStackStorage *storage,
return evaltime;
}
-/**
- * Evaluates the given set of F-Curve Modifiers using the given data
- * Should only be called after evaluate_time_fmodifiers() has been called.
- */
void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
ListBase *modifiers,
FCurve *fcu,
@@ -1565,10 +1513,6 @@ void evaluate_value_fmodifiers(FModifiersStackStorage *storage,
/* ---------- */
-/**
- * Bake modifiers for given F-Curve to curve sample data, in the frame range defined
- * by start and end (inclusive).
- */
void fcurve_bake_modifiers(FCurve *fcu, int start, int end)
{
ChannelDriver *driver;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index d9b3faf8623..68b7e274970 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -152,10 +152,6 @@ bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig
return true;
}
-/**
- * Reinsert \a module_conf offset by \a direction from current position.
- * \return if position of \a module_conf changed.
- */
bool BKE_freestyle_module_move(FreestyleConfig *config,
FreestyleModuleConfig *module_conf,
int direction)
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index 598c61fd877..1e24b29038d 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -77,7 +77,6 @@ bool CurveComponent::has_curve() const
return curve_ != nullptr;
}
-/* Clear the component and replace it with the new curve. */
void CurveComponent::replace(CurveEval *curve, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -128,10 +127,6 @@ void CurveComponent::ensure_owns_direct_data()
}
}
-/**
- * Create empty curve data used for rendering the spline's wire edges.
- * \note See comment on #curve_for_render_ for further explanation.
- */
const Curve *CurveComponent::get_curve_for_render() const
{
if (curve_ == nullptr) {
@@ -391,14 +386,14 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen
/** \} */
+namespace blender::bke {
+
/* -------------------------------------------------------------------- */
/** \name Builtin Spline Attributes
*
* Attributes with a value for every spline, stored contiguously or in every spline separately.
* \{ */
-namespace blender::bke {
-
class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
using AsReadAttribute = GVArray (*)(const CurveEval &data);
using AsWriteAttribute = GVMutableArray (*)(CurveEval &data);
@@ -714,46 +709,15 @@ static bool remove_point_attribute(GeometryComponent &component,
}
/**
- * Virtual array for any control point data accessed with spans and an offset array.
- */
-template<typename T> class VArray_For_SplinePoints : public VArrayImpl<T> {
- private:
- const Array<Span<T>> data_;
- Array<int> offsets_;
-
- public:
- VArray_For_SplinePoints(Array<Span<T>> data, Array<int> offsets)
- : VArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
- {
- }
-
- T get(const int64_t index) const final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- return data_[indices.spline_index][indices.point_index];
- }
-
- void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- point_attribute_materialize(data_.as_span(), offsets_, mask, r_span);
- }
-
- void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- point_attribute_materialize_to_uninitialized(data_.as_span(), offsets_, mask, r_span);
- }
-};
-
-/**
* Mutable virtual array for any control point data accessed with spans and an offset array.
*/
-template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArrayImpl<T> {
+template<typename T> class VArrayImpl_For_SplinePoints final : public VMutableArrayImpl<T> {
private:
Array<MutableSpan<T>> data_;
Array<int> offsets_;
public:
- VMutableArray_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets)
+ VArrayImpl_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets)
: VMutableArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
{
}
@@ -791,16 +755,17 @@ template<typename T> class VMutableArray_For_SplinePoints final : public VMutabl
}
};
-template<typename T> VArray<T> point_data_varray(Array<Span<T>> spans, Array<int> offsets)
+template<typename T> VArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets)
{
- return VArray<T>::template For<VArray_For_SplinePoints<T>>(std::move(spans), std::move(offsets));
+ return VArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
+ std::move(offsets));
}
template<typename T>
-VMutableArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets)
+VMutableArray<T> point_data_varray_mutable(Array<MutableSpan<T>> spans, Array<int> offsets)
{
- return VMutableArray<T>::template For<VMutableArray_For_SplinePoints<T>>(std::move(spans),
- std::move(offsets));
+ return VMutableArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
+ std::move(offsets));
}
/**
@@ -811,13 +776,13 @@ VMutableArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offse
* \note There is no need to check the handle type to avoid changing auto handles, since
* retrieving write access to the position data will mark them for recomputation anyway.
*/
-class VMutableArray_For_SplinePosition final : public VMutableArrayImpl<float3> {
+class VArrayImpl_For_SplinePosition final : public VMutableArrayImpl<float3> {
private:
MutableSpan<SplinePtr> splines_;
Array<int> offsets_;
public:
- VMutableArray_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets)
+ VArrayImpl_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets)
: VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets))
{
}
@@ -889,104 +854,16 @@ class VMutableArray_For_SplinePosition final : public VMutableArrayImpl<float3>
}
};
-class VArray_For_BezierHandle final : public VArrayImpl<float3> {
- private:
- Span<SplinePtr> splines_;
- Array<int> offsets_;
- bool is_right_;
-
- public:
- VArray_For_BezierHandle(Span<SplinePtr> splines, Array<int> offsets, const bool is_right)
- : VArrayImpl<float3>(offsets.last()),
- splines_(std::move(splines)),
- offsets_(std::move(offsets)),
- is_right_(is_right)
- {
- }
-
- static float3 get_internal(const int64_t index,
- Span<SplinePtr> splines,
- Span<int> offsets,
- const bool is_right)
- {
- const PointIndices indices = lookup_point_indices(offsets, index);
- const Spline &spline = *splines[indices.spline_index];
- if (spline.type() == Spline::Type::Bezier) {
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
- return is_right ? bezier_spline.handle_positions_right()[indices.point_index] :
- bezier_spline.handle_positions_left()[indices.point_index];
- }
- return float3(0);
- }
-
- float3 get(const int64_t index) const final
- {
- return get_internal(index, splines_, offsets_, is_right_);
- }
-
- /**
- * Utility so we can pass handle positions to the materialize functions above.
- *
- * \note This relies on the ability of the materialize implementations to
- * handle empty spans, since only Bezier splines have handles.
- */
- static Array<Span<float3>> get_handle_spans(Span<SplinePtr> splines, const bool is_right)
- {
- Array<Span<float3>> spans(splines.size());
- for (const int i : spans.index_range()) {
- if (splines[i]->type() == Spline::Type::Bezier) {
- BezierSpline &bezier_spline = static_cast<BezierSpline &>(*splines[i]);
- spans[i] = is_right ? bezier_spline.handle_positions_right() :
- bezier_spline.handle_positions_left();
- }
- else {
- spans[i] = {};
- }
- }
- return spans;
- }
-
- static void materialize_internal(const IndexMask mask,
- Span<SplinePtr> splines,
- Span<int> offsets,
- const bool is_right,
- MutableSpan<float3> r_span)
- {
- Array<Span<float3>> spans = get_handle_spans(splines, is_right);
- point_attribute_materialize(spans.as_span(), offsets, mask, r_span);
- }
-
- static void materialize_to_uninitialized_internal(const IndexMask mask,
- Span<SplinePtr> splines,
- Span<int> offsets,
- const bool is_right,
- MutableSpan<float3> r_span)
- {
- Array<Span<float3>> spans = get_handle_spans(splines, is_right);
- point_attribute_materialize_to_uninitialized(spans.as_span(), offsets, mask, r_span);
- }
-
- void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
- {
- materialize_internal(mask, splines_, offsets_, is_right_, r_span);
- }
-
- void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final
- {
- materialize_to_uninitialized_internal(mask, splines_, offsets_, is_right_, r_span);
- }
-};
-
-class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> {
+class VArrayImpl_For_BezierHandles final : public VMutableArrayImpl<float3> {
private:
MutableSpan<SplinePtr> splines_;
Array<int> offsets_;
bool is_right_;
public:
- VMutableArray_For_BezierHandles(MutableSpan<SplinePtr> splines,
- Array<int> offsets,
- const bool is_right)
+ VArrayImpl_For_BezierHandles(MutableSpan<SplinePtr> splines,
+ Array<int> offsets,
+ const bool is_right)
: VMutableArrayImpl<float3>(offsets.last()),
splines_(splines),
offsets_(std::move(offsets)),
@@ -996,7 +873,14 @@ class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> {
float3 get(const int64_t index) const final
{
- return VArray_For_BezierHandle::get_internal(index, splines_, offsets_, is_right_);
+ const PointIndices indices = lookup_point_indices(offsets_, index);
+ const Spline &spline = *splines_[indices.spline_index];
+ if (spline.type() == Spline::Type::Bezier) {
+ const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
+ return is_right_ ? bezier_spline.handle_positions_right()[indices.point_index] :
+ bezier_spline.handle_positions_left()[indices.point_index];
+ }
+ return float3(0);
}
void set(const int64_t index, float3 value) final
@@ -1040,13 +924,36 @@ class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> {
void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
{
- VArray_For_BezierHandle::materialize_internal(mask, splines_, offsets_, is_right_, r_span);
+ Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
+ point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
}
void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final
{
- VArray_For_BezierHandle::materialize_to_uninitialized_internal(
- mask, splines_, offsets_, is_right_, r_span);
+ Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
+ point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
+ }
+
+ /**
+ * Utility so we can pass handle positions to the materialize functions above.
+ *
+ * \note This relies on the ability of the materialize implementations to
+ * handle empty spans, since only Bezier splines have handles.
+ */
+ static Array<Span<float3>> get_handle_spans(Span<SplinePtr> splines, const bool is_right)
+ {
+ Array<Span<float3>> spans(splines.size());
+ for (const int i : spans.index_range()) {
+ if (splines[i]->type() == Spline::Type::Bezier) {
+ BezierSpline &bezier_spline = static_cast<BezierSpline &>(*splines[i]);
+ spans[i] = is_right ? bezier_spline.handle_positions_right() :
+ bezier_spline.handle_positions_left();
+ }
+ else {
+ spans[i] = {};
+ }
+ }
+ return spans;
}
};
@@ -1102,9 +1009,12 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
}
Array<int> offsets = curve->control_point_offsets();
- Array<Span<T>> spans(splines.size());
+ Array<MutableSpan<T>> spans(splines.size());
for (const int i : splines.index_range()) {
- spans[i] = get_span_(*splines[i]);
+ Span<T> span = get_span_(*splines[i]);
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ spans[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
}
return point_data_varray(spans, offsets);
@@ -1143,7 +1053,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
spans[i] = get_mutable_span_(*splines[i]);
}
- return {point_data_varray(spans, offsets), domain_, tag_modified_fn};
+ return {point_data_varray_mutable(spans, offsets), domain_, tag_modified_fn};
}
bool try_delete(GeometryComponent &component) const final
@@ -1235,8 +1145,8 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
};
Array<int> offsets = curve->control_point_offsets();
- return {VMutableArray<float3>::For<VMutableArray_For_SplinePosition>(curve->splines(),
- std::move(offsets)),
+ return {VMutableArray<float3>::For<VArrayImpl_For_SplinePosition>(curve->splines(),
+ std::move(offsets)),
domain_,
tag_modified_fn};
}
@@ -1270,8 +1180,10 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
}
Array<int> offsets = curve->control_point_offsets();
- return VArray<float3>::For<VArray_For_BezierHandle>(
- curve->splines(), std::move(offsets), is_right_);
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ return VArray<float3>::For<VArrayImpl_For_BezierHandles>(
+ const_cast<CurveEval *>(curve)->splines(), std::move(offsets), is_right_);
}
WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
@@ -1288,7 +1200,7 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); };
Array<int> offsets = curve->control_point_offsets();
- return {VMutableArray<float3>::For<VMutableArray_For_BezierHandles>(
+ return {VMutableArray<float3>::For<VArrayImpl_For_BezierHandles>(
curve->splines(), std::move(offsets), is_right_),
domain_,
tag_modified_fn};
@@ -1377,9 +1289,12 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
Array<int> offsets = curve->control_point_offsets();
attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
using T = decltype(dummy);
- Array<Span<T>> data(splines.size());
+ Array<MutableSpan<T>> data(splines.size());
for (const int i : splines.index_range()) {
- data[i] = spans[i].typed<T>();
+ Span<T> span = spans[i].typed<T>();
+ /* Use const-cast because the underlying virtual array implementation is shared between
+ * const and non const data. */
+ data[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
BLI_assert(data[i].data() != nullptr);
}
attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT};
@@ -1435,7 +1350,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
data[i] = spans[i].typed<T>();
BLI_assert(data[i].data() != nullptr);
}
- attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT};
+ attribute = {point_data_varray_mutable(data, offsets), ATTR_DOMAIN_POINT};
});
return attribute;
}
@@ -1570,6 +1485,8 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
{&spline_custom_data, &point_custom_data});
}
+/** \} */
+
} // namespace blender::bke
const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const
@@ -1578,5 +1495,3 @@ const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_p
blender::bke::create_attribute_providers_for_curve();
return &providers;
}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 9a30c86c1e5..93a7646fed0 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -31,12 +31,17 @@
#include "attribute_access_intern.hh"
+#include "FN_cpp_type_make.hh"
+
using blender::float4x4;
using blender::Map;
using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::VectorSet;
+using blender::fn::GSpan;
+
+MAKE_CPP_TYPE(InstanceReference, InstanceReference, CPPTypeFlags::None)
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -51,8 +56,8 @@ GeometryComponent *InstancesComponent::copy() const
InstancesComponent *new_component = new InstancesComponent();
new_component->instance_reference_handles_ = instance_reference_handles_;
new_component->instance_transforms_ = instance_transforms_;
- new_component->instance_ids_ = instance_ids_;
new_component->references_ = references_;
+ new_component->attributes_ = attributes_;
return new_component;
}
@@ -60,32 +65,21 @@ void InstancesComponent::reserve(int min_capacity)
{
instance_reference_handles_.reserve(min_capacity);
instance_transforms_.reserve(min_capacity);
- if (!instance_ids_.is_empty()) {
- this->instance_ids_ensure();
- }
+ attributes_.reallocate(min_capacity);
}
-/**
- * Resize the transform, handles, and ID vectors to the specified capacity.
- *
- * \note This function should be used carefully, only when it's guaranteed
- * that the data will be filled.
- */
void InstancesComponent::resize(int capacity)
{
instance_reference_handles_.resize(capacity);
instance_transforms_.resize(capacity);
- if (!instance_ids_.is_empty()) {
- this->instance_ids_ensure();
- }
+ attributes_.reallocate(capacity);
}
void InstancesComponent::clear()
{
instance_reference_handles_.clear();
instance_transforms_.clear();
- instance_ids_.clear();
-
+ attributes_.clear();
references_.clear();
}
@@ -95,9 +89,7 @@ void InstancesComponent::add_instance(const int instance_handle, const float4x4
BLI_assert(instance_handle < references_.size());
instance_reference_handles_.append(instance_handle);
instance_transforms_.append(transform);
- if (!instance_ids_.is_empty()) {
- this->instance_ids_ensure();
- }
+ attributes_.reallocate(this->instances_amount());
}
blender::Span<int> InstancesComponent::instance_reference_handles() const
@@ -119,36 +111,6 @@ blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const
return instance_transforms_;
}
-blender::MutableSpan<int> InstancesComponent::instance_ids()
-{
- return instance_ids_;
-}
-blender::Span<int> InstancesComponent::instance_ids() const
-{
- return instance_ids_;
-}
-
-/**
- * Make sure the ID storage size matches the number of instances. By directly resizing the
- * component's vectors internally, it is possible to be in a situation where the IDs are not
- * empty but they do not have the correct size; this function resolves that.
- */
-blender::MutableSpan<int> InstancesComponent::instance_ids_ensure()
-{
- instance_ids_.append_n_times(0, this->instances_amount() - instance_ids_.size());
- return instance_ids_;
-}
-
-void InstancesComponent::instance_ids_clear()
-{
- instance_ids_.clear_and_make_inline();
-}
-
-/**
- * With write access to the instances component, the data in the instanced geometry sets can be
- * changed. This is a function on the component rather than each reference to ensure `const`
- * correctness for that reason.
- */
GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference_index)
{
/* If this assert fails, it means #ensure_geometry_instances must be called first or that the
@@ -160,11 +122,6 @@ GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference
return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
}
-/**
- * Returns a handle for the given reference.
- * If the reference exists already, the handle of the existing reference is returned.
- * Otherwise a new handle is added.
- */
int InstancesComponent::add_reference(const InstanceReference &reference)
{
return references_.index_of_or_add_as(reference);
@@ -347,15 +304,17 @@ static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
blender::Span<int> InstancesComponent::almost_unique_ids() const
{
std::lock_guard lock(almost_unique_ids_mutex_);
- if (instance_ids().is_empty()) {
- almost_unique_ids_.reinitialize(this->instances_amount());
- for (const int i : almost_unique_ids_.index_range()) {
- almost_unique_ids_[i] = i;
+ std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
+ if (instance_ids_gspan) {
+ Span<int> instance_ids = instance_ids_gspan->typed<int>();
+ if (almost_unique_ids_.size() != instance_ids.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
}
}
else {
- if (almost_unique_ids_.size() != instance_ids_.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(instance_ids_);
+ almost_unique_ids_.reinitialize(this->instances_amount());
+ for (const int i : almost_unique_ids_.index_range()) {
+ almost_unique_ids_[i] = i;
}
}
return almost_unique_ids_;
@@ -434,81 +393,21 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
}
};
-class InstanceIDAttributeProvider final : public BuiltinAttributeProvider {
- public:
- InstanceIDAttributeProvider()
- : BuiltinAttributeProvider(
- "id", ATTR_DOMAIN_INSTANCE, CD_PROP_INT32, Creatable, Writable, Deletable)
- {
- }
-
- GVArray try_get_for_read(const GeometryComponent &component) const final
- {
- const InstancesComponent &instances = static_cast<const InstancesComponent &>(component);
- if (instances.instance_ids().is_empty()) {
- return {};
- }
- return VArray<int>::ForSpan(instances.instance_ids());
- }
-
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
- {
- InstancesComponent &instances = static_cast<InstancesComponent &>(component);
- if (instances.instance_ids().is_empty()) {
- return {};
- }
- return {VMutableArray<int>::ForSpan(instances.instance_ids()), domain_};
- }
-
- bool try_delete(GeometryComponent &component) const final
- {
- InstancesComponent &instances = static_cast<InstancesComponent &>(component);
- if (instances.instance_ids().is_empty()) {
- return false;
- }
- instances.instance_ids_clear();
- return true;
- }
-
- bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final
- {
- InstancesComponent &instances = static_cast<InstancesComponent &>(component);
- if (instances.instances_amount() == 0) {
- return false;
- }
- MutableSpan<int> ids = instances.instance_ids_ensure();
- switch (initializer.type) {
- case AttributeInit::Type::Default: {
- ids.fill(0);
- break;
- }
- case AttributeInit::Type::VArray: {
- const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
- varray.materialize_to_uninitialized(varray.index_range(), ids.data());
- break;
- }
- case AttributeInit::Type::MoveArray: {
- void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
- ids.copy_from({static_cast<int *>(source_data), instances.instances_amount()});
- MEM_freeN(source_data);
- break;
- }
- }
- return true;
- }
+template<typename T>
+static GVArray make_array_read_attribute(const void *data, const int domain_size)
+{
+ return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
+}
- bool exists(const GeometryComponent &component) const final
- {
- const InstancesComponent &instances = static_cast<const InstancesComponent &>(component);
- return !instances.instance_ids().is_empty();
- }
-};
+template<typename T>
+static GVMutableArray make_array_write_attribute(void *data, const int domain_size)
+{
+ return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
+}
static ComponentAttributeProviders create_attribute_providers_for_instances()
{
static InstancePositionAttributeProvider position;
- static InstanceIDAttributeProvider id;
-
static CustomDataAccessInfo instance_custom_data_access = {
[](GeometryComponent &component) -> CustomData * {
InstancesComponent &inst = static_cast<InstancesComponent &>(component);
@@ -520,6 +419,24 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
},
nullptr};
+ /**
+ * IDs of the instances. They are used for consistency over multiple frames for things like
+ * motion blur. Proper stable ID data that actually helps when rendering can only be generated
+ * in some situations, so this vector is allowed to be empty, in which case the index of each
+ * instance will be used for the final ID.
+ */
+ static BuiltinCustomDataLayerProvider id("id",
+ ATTR_DOMAIN_INSTANCE,
+ CD_PROP_INT32,
+ CD_PROP_INT32,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ instance_custom_data_access,
+ make_array_read_attribute<int>,
+ make_array_write_attribute<int>,
+ nullptr);
+
static CustomDataAttributeProvider instance_custom_data(ATTR_DOMAIN_INSTANCE,
instance_custom_data_access);
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 86a52b420b6..cc15e6d7b84 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -29,7 +29,6 @@
#include "attribute_access_intern.hh"
-/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
/* -------------------------------------------------------------------- */
@@ -71,7 +70,6 @@ bool MeshComponent::has_mesh() const
return mesh_ != nullptr;
}
-/* Clear the component and replace it with the new mesh. */
void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -80,8 +78,6 @@ void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
ownership_ = ownership;
}
-/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
- * mesh (if the component was responsible before). */
Mesh *MeshComponent::release()
{
BLI_assert(this->is_mutable());
@@ -90,15 +86,11 @@ Mesh *MeshComponent::release()
return mesh;
}
-/* Get the mesh from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
const Mesh *MeshComponent::get_for_read() const
{
return mesh_;
}
-/* Get the mesh from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */
Mesh *MeshComponent::get_for_write()
{
BLI_assert(this->is_mutable());
@@ -996,57 +988,36 @@ static void set_crease(MEdge &edge, float value)
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
}
-class VMutableArray_For_VertexWeights final : public VMutableArrayImpl<float> {
+class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
private:
MDeformVert *dverts_;
const int dvert_index_;
public:
- VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
+ VArrayImpl_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
: VMutableArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
}
float get(const int64_t index) const override
{
- return get_internal(dverts_, dvert_index_, index);
- }
-
- void set(const int64_t index, const float value) override
- {
- MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
- weight->weight = value;
- }
-
- static float get_internal(const MDeformVert *dverts, const int dvert_index, const int64_t index)
- {
- if (dverts == nullptr) {
+ if (dverts_ == nullptr) {
return 0.0f;
}
- const MDeformVert &dvert = dverts[index];
+ const MDeformVert &dvert = dverts_[index];
for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
- if (weight.def_nr == dvert_index) {
+ if (weight.def_nr == dvert_index_) {
return weight.weight;
}
}
return 0.0f;
+ ;
}
-};
-
-class VArray_For_VertexWeights final : public VArrayImpl<float> {
- private:
- const MDeformVert *dverts_;
- const int dvert_index_;
- public:
- VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index)
- : VArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
- {
- }
-
- float get(const int64_t index) const override
+ void set(const int64_t index, const float value) override
{
- return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index);
+ MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
+ weight->weight = value;
}
};
@@ -1077,7 +1048,7 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
static const float default_value = 0.0f;
return {VArray<float>::ForSingle(default_value, mesh->totvert), ATTR_DOMAIN_POINT};
}
- return {VArray<float>::For<VArray_For_VertexWeights>(
+ return {VArray<float>::For<VArrayImpl_For_VertexWeights>(
mesh->dvert, mesh->totvert, vertex_group_index),
ATTR_DOMAIN_POINT};
}
@@ -1109,7 +1080,7 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
&mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
}
- return {VMutableArray<float>::For<VMutableArray_For_VertexWeights>(
+ return {VMutableArray<float>::For<VArrayImpl_For_VertexWeights>(
mesh->dvert, mesh->totvert, vertex_group_index),
ATTR_DOMAIN_POINT};
}
@@ -1127,16 +1098,19 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
}
const std::string name = attribute_id.name();
- const int vertex_group_index = BLI_findstringindex(
- &mesh->vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
- if (vertex_group_index < 0) {
+
+ int index;
+ bDeformGroup *group;
+ if (!BKE_id_defgroup_name_find(&mesh->id, name.c_str(), &index, &group)) {
return false;
}
+ BLI_remlink(&mesh->vertex_group_names, group);
+ MEM_freeN(group);
if (mesh->dvert == nullptr) {
return true;
}
for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
- MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
+ MDeformWeight *weight = BKE_defvert_find_index(&dvert, index);
BKE_defvert_remove_group(&dvert, weight);
}
return true;
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
index c6a1c61a96d..80c09a7ed4a 100644
--- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -62,7 +62,6 @@ bool PointCloudComponent::has_pointcloud() const
return pointcloud_ != nullptr;
}
-/* Clear the component and replace it with the new point cloud. */
void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -71,8 +70,6 @@ void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType
ownership_ = ownership;
}
-/* Return the point cloud and clear the component. The caller takes over responsibility for freeing
- * the point cloud (if the component was responsible before). */
PointCloud *PointCloudComponent::release()
{
BLI_assert(this->is_mutable());
@@ -81,17 +78,11 @@ PointCloud *PointCloudComponent::release()
return pointcloud;
}
-/* Get the point cloud from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned point cloud should not be modified. No ownership is transferred.
- */
const PointCloud *PointCloudComponent::get_for_read() const
{
return pointcloud_;
}
-/* Get the point cloud from this component. This method can only be used when the component is
- * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
- * transferred. */
PointCloud *PointCloudComponent::get_for_write()
{
BLI_assert(this->is_mutable());
diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc
index 94ed07a63de..e9874153b4c 100644
--- a/source/blender/blenkernel/intern/geometry_component_volume.cc
+++ b/source/blender/blenkernel/intern/geometry_component_volume.cc
@@ -59,7 +59,6 @@ bool VolumeComponent::has_volume() const
return volume_ != nullptr;
}
-/* Clear the component and replace it with the new volume. */
void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
@@ -68,8 +67,6 @@ void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership)
ownership_ = ownership;
}
-/* Return the volume and clear the component. The caller takes over responsibility for freeing the
- * volume (if the component was responsible before). */
Volume *VolumeComponent::release()
{
BLI_assert(this->is_mutable());
@@ -78,15 +75,11 @@ Volume *VolumeComponent::release()
return volume;
}
-/* Get the volume from this component. This method can be used by multiple threads at the same
- * time. Therefore, the returned volume should not be modified. No ownership is transferred. */
const Volume *VolumeComponent::get_for_read() const
{
return volume_;
}
-/* Get the volume from this component. This method can only be used when the component is mutable,
- * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */
Volume *VolumeComponent::get_for_write()
{
BLI_assert(this->is_mutable());
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index c250c14f1d7..ef5609ec9a8 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -105,7 +105,6 @@ bool GeometryComponent::is_empty() const
/** \name Geometry Set
* \{ */
-/* The methods are defaulted here so that they are not instantiated in every translation unit. */
GeometrySet::GeometrySet() = default;
GeometrySet::GeometrySet(const GeometrySet &other) = default;
GeometrySet::GeometrySet(GeometrySet &&other) = default;
@@ -113,36 +112,24 @@ GeometrySet::~GeometrySet() = default;
GeometrySet &GeometrySet::operator=(const GeometrySet &other) = default;
GeometrySet &GeometrySet::operator=(GeometrySet &&other) = default;
-/* This method can only be used when the geometry set is mutable. It returns a mutable geometry
- * component of the given type.
- */
GeometryComponent &GeometrySet::get_component_for_write(GeometryComponentType component_type)
{
- return components_.add_or_modify(
- component_type,
- [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & {
- /* If the component did not exist before, create a new one. */
- new (value_ptr) GeometryComponentPtr(GeometryComponent::create(component_type));
- return **value_ptr;
- },
- [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & {
- GeometryComponentPtr &value = *value_ptr;
- if (value->is_mutable()) {
- /* If the referenced component is already mutable, return it directly. */
- return *value;
- }
- /* If the referenced component is shared, make a copy. The copy is not shared and is
- * therefore mutable. */
- GeometryComponent *copied_component = value->copy();
- value = GeometryComponentPtr{copied_component};
- return *copied_component;
- });
+ GeometryComponentPtr &component_ptr = components_[component_type];
+ if (!component_ptr) {
+ /* If the component did not exist before, create a new one. */
+ component_ptr = GeometryComponent::create(component_type);
+ return *component_ptr;
+ }
+ if (component_ptr->is_mutable()) {
+ /* If the referenced component is already mutable, return it directly. */
+ return *component_ptr;
+ }
+ /* If the referenced component is shared, make a copy. The copy is not shared and is
+ * therefore mutable. */
+ component_ptr = component_ptr->copy();
+ return *component_ptr;
}
-/**
- * Retrieve the pointer to a component without creating it if it does not exist,
- * unlike #get_component_for_write.
- */
GeometryComponent *GeometrySet::get_component_ptr(GeometryComponentType type)
{
if (this->has(type)) {
@@ -151,56 +138,47 @@ GeometryComponent *GeometrySet::get_component_ptr(GeometryComponentType type)
return nullptr;
}
-/* Get the component of the given type. Might return null if the component does not exist yet. */
const GeometryComponent *GeometrySet::get_component_for_read(
GeometryComponentType component_type) const
{
- const GeometryComponentPtr *component = components_.lookup_ptr(component_type);
- if (component != nullptr) {
- return component->get();
- }
- return nullptr;
+ return components_[component_type].get();
}
bool GeometrySet::has(const GeometryComponentType component_type) const
{
- return components_.contains(component_type);
+ return components_[component_type].has_value();
}
void GeometrySet::remove(const GeometryComponentType component_type)
{
- components_.remove(component_type);
+ components_[component_type].reset();
}
-/**
- * Remove all geometry components with types that are not in the provided list.
- */
void GeometrySet::keep_only(const blender::Span<GeometryComponentType> component_types)
{
- for (auto it = components_.keys().begin(); it != components_.keys().end(); ++it) {
- const GeometryComponentType type = *it;
- if (!component_types.contains(type)) {
- components_.remove(it);
+ for (GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (!component_types.contains(component_ptr->type())) {
+ component_ptr.reset();
+ }
}
}
}
void GeometrySet::add(const GeometryComponent &component)
{
- BLI_assert(!components_.contains(component.type()));
+ BLI_assert(!components_[component.type()]);
component.user_add();
- GeometryComponentPtr component_ptr{const_cast<GeometryComponent *>(&component)};
- components_.add_new(component.type(), std::move(component_ptr));
+ components_[component.type()] = const_cast<GeometryComponent *>(&component);
}
-/**
- * Get all geometry components in this geometry set for read-only access.
- */
Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
{
Vector<const GeometryComponent *> components;
- for (const GeometryComponentPtr &ptr : components_.values()) {
- components.append(ptr.get());
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ components.append(component_ptr.get());
+ }
}
return components;
}
@@ -233,122 +211,111 @@ std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
return stream;
}
-/* Remove all geometry components from the geometry set. */
void GeometrySet::clear()
{
- components_.clear();
+ for (GeometryComponentPtr &component_ptr : components_) {
+ component_ptr.reset();
+ }
}
-/* Make sure that the geometry can be cached. This does not ensure ownership of object/collection
- * instances. */
void GeometrySet::ensure_owns_direct_data()
{
- for (GeometryComponentType type : components_.keys()) {
- const GeometryComponent *component = this->get_component_for_read(type);
- if (!component->owns_direct_data()) {
- GeometryComponent &component_for_write = this->get_component_for_write(type);
- component_for_write.ensure_owns_direct_data();
+ for (GeometryComponentPtr &component_ptr : components_) {
+ if (!component_ptr) {
+ continue;
}
+ if (component_ptr->owns_direct_data()) {
+ continue;
+ }
+ GeometryComponent &component_for_write = this->get_component_for_write(component_ptr->type());
+ component_for_write.ensure_owns_direct_data();
}
}
bool GeometrySet::owns_direct_data() const
{
- for (const GeometryComponentPtr &component : components_.values()) {
- if (!component->owns_direct_data()) {
- return false;
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (!component_ptr->owns_direct_data()) {
+ return false;
+ }
}
}
return true;
}
-/* Returns a read-only mesh or null. */
const Mesh *GeometrySet::get_mesh_for_read() const
{
const MeshComponent *component = this->get_component_for_read<MeshComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns true when the geometry set has a mesh component that has a mesh. */
bool GeometrySet::has_mesh() const
{
const MeshComponent *component = this->get_component_for_read<MeshComponent>();
return component != nullptr && component->has_mesh();
}
-/* Returns a read-only point cloud of null. */
const PointCloud *GeometrySet::get_pointcloud_for_read() const
{
const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns a read-only volume or null. */
const Volume *GeometrySet::get_volume_for_read() const
{
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns a read-only curve or null. */
const CurveEval *GeometrySet::get_curve_for_read() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
}
-/* Returns true when the geometry set has a point cloud component that has a point cloud. */
bool GeometrySet::has_pointcloud() const
{
const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
return component != nullptr && component->has_pointcloud();
}
-/* Returns true when the geometry set has an instances component that has at least one instance. */
bool GeometrySet::has_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
return component != nullptr && component->instances_amount() >= 1;
}
-/* Returns true when the geometry set has a volume component that has a volume. */
bool GeometrySet::has_volume() const
{
const VolumeComponent *component = this->get_component_for_read<VolumeComponent>();
return component != nullptr && component->has_volume();
}
-/* Returns true when the geometry set has a curve component that has a curve. */
bool GeometrySet::has_curve() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return component != nullptr && component->has_curve();
}
-/* Returns true when the geometry set has any data that is not an instance. */
bool GeometrySet::has_realized_data() const
{
- if (components_.is_empty()) {
- return false;
- }
- if (components_.size() > 1) {
- return true;
+ for (const GeometryComponentPtr &component_ptr : components_) {
+ if (component_ptr) {
+ if (component_ptr->type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return true;
+ }
+ }
}
- /* Check if the only component is an #InstancesComponent. */
- return this->get_component_for_read<InstancesComponent>() == nullptr;
+ return false;
}
-/* Return true if the geometry set has any component that isn't empty. */
bool GeometrySet::is_empty() const
{
- if (components_.is_empty()) {
- return true;
- }
- return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() ||
+ return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() || this->has_volume() ||
this->has_instances());
}
-/* Create a new geometry set that only contains the given mesh. */
GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
@@ -359,7 +326,6 @@ GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType owne
return geometry_set;
}
-/* Create a new geometry set that only contains the given point cloud. */
GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership)
{
@@ -371,7 +337,6 @@ GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
return geometry_set;
}
-/* Create a new geometry set that only contains the given curve. */
GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
@@ -382,76 +347,80 @@ GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipTy
return geometry_set;
}
-/* Clear the existing mesh and replace it with the given one. */
void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
if (mesh == nullptr) {
this->remove<MeshComponent>();
+ return;
}
- else {
- MeshComponent &component = this->get_component_for_write<MeshComponent>();
- component.replace(mesh, ownership);
+ if (mesh == this->get_mesh_for_read()) {
+ return;
}
+ this->remove<MeshComponent>();
+ MeshComponent &component = this->get_component_for_write<MeshComponent>();
+ component.replace(mesh, ownership);
}
-/* Clear the existing curve and replace it with the given one. */
void GeometrySet::replace_curve(CurveEval *curve, GeometryOwnershipType ownership)
{
if (curve == nullptr) {
this->remove<CurveComponent>();
+ return;
}
- else {
- CurveComponent &component = this->get_component_for_write<CurveComponent>();
- component.replace(curve, ownership);
+ if (curve == this->get_curve_for_read()) {
+ return;
}
+ this->remove<CurveComponent>();
+ CurveComponent &component = this->get_component_for_write<CurveComponent>();
+ component.replace(curve, ownership);
}
-/* Clear the existing point cloud and replace with the given one. */
void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
if (pointcloud == nullptr) {
this->remove<PointCloudComponent>();
+ return;
}
- else {
- PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>();
- component.replace(pointcloud, ownership);
+ if (pointcloud == this->get_pointcloud_for_read()) {
+ return;
}
+ this->remove<PointCloudComponent>();
+ PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>();
+ component.replace(pointcloud, ownership);
}
-/* Clear the existing volume and replace with the given one. */
void GeometrySet::replace_volume(Volume *volume, GeometryOwnershipType ownership)
{
if (volume == nullptr) {
this->remove<VolumeComponent>();
+ return;
}
- else {
- VolumeComponent &component = this->get_component_for_write<VolumeComponent>();
- component.replace(volume, ownership);
+ if (volume == this->get_volume_for_read()) {
+ return;
}
+ this->remove<VolumeComponent>();
+ VolumeComponent &component = this->get_component_for_write<VolumeComponent>();
+ component.replace(volume, ownership);
}
-/* Returns a mutable mesh or null. No ownership is transferred. */
Mesh *GeometrySet::get_mesh_for_write()
{
MeshComponent *component = this->get_component_ptr<MeshComponent>();
return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable point cloud or null. No ownership is transferred. */
PointCloud *GeometrySet::get_pointcloud_for_write()
{
PointCloudComponent *component = this->get_component_ptr<PointCloudComponent>();
return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable volume or null. No ownership is transferred. */
Volume *GeometrySet::get_volume_for_write()
{
VolumeComponent *component = this->get_component_ptr<VolumeComponent>();
return component == nullptr ? nullptr : component->get_for_write();
}
-/* Returns a mutable curve or null. No ownership is transferred. */
CurveEval *GeometrySet::get_curve_for_write()
{
CurveComponent *component = this->get_component_ptr<CurveComponent>();
@@ -512,13 +481,18 @@ void GeometrySet::gather_attributes_for_propagation(
return;
}
+ AttributeDomain domain = meta_data.domain;
+ if (dst_component_type != GEO_COMPONENT_TYPE_INSTANCES && domain == ATTR_DOMAIN_INSTANCE) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+
auto add_info = [&](AttributeKind *attribute_kind) {
- attribute_kind->domain = meta_data.domain;
+ attribute_kind->domain = domain;
attribute_kind->data_type = meta_data.data_type;
};
auto modify_info = [&](AttributeKind *attribute_kind) {
attribute_kind->domain = bke::attribute_domain_highest_priority(
- {attribute_kind->domain, meta_data.domain});
+ {attribute_kind->domain, domain});
attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
{attribute_kind->data_type, meta_data.data_type});
};
@@ -581,10 +555,6 @@ static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
}
}
-/**
- * Modify every (recursive) instance separately. This is often more efficient than realizing all
- * instances just to change the same thing on all of them.
- */
void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
{
Vector<GeometrySet *> geometry_sets;
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index c73da7d9659..4d84d5d899d 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -53,9 +53,6 @@ static void add_final_mesh_as_geometry_component(const Object &object, GeometryS
}
}
-/**
- * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
- */
GeometrySet object_get_evaluated_geometry_set(const Object &object)
{
if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
@@ -77,7 +74,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
add_final_mesh_as_geometry_component(object, geometry_set);
}
- /* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
+ /* TODO: Cover the case of point clouds without modifiers-- they may not be covered by the
* #geometry_set_eval case above. */
/* TODO: Add volume support. */
@@ -169,16 +166,6 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
}
}
-/**
- * Return flattened vector of the geometry component's recursive instances. I.e. all collection
- * instances and object instances will be expanded into the instances of their geometry components.
- * Even the instances in those geometry components' will be included.
- *
- * \note For convenience (to avoid duplication in the caller), the returned vector also contains
- * the argument geometry set.
- *
- * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
- */
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups)
{
@@ -220,375 +207,6 @@ void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> se
}
}
-static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGroup> set_groups)
-{
- int totverts = 0;
- int totloops = 0;
- int totedges = 0;
- int totpolys = 0;
- int64_t cd_dirty_vert = 0;
- int64_t cd_dirty_poly = 0;
- int64_t cd_dirty_edge = 0;
- int64_t cd_dirty_loop = 0;
- VectorSet<Material *> materials;
-
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const int tot_transforms = set_group.transforms.size();
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
- totverts += mesh.totvert * tot_transforms;
- totloops += mesh.totloop * tot_transforms;
- totedges += mesh.totedge * tot_transforms;
- totpolys += mesh.totpoly * tot_transforms;
- cd_dirty_vert |= mesh.runtime.cd_dirty_vert;
- cd_dirty_poly |= mesh.runtime.cd_dirty_poly;
- cd_dirty_edge |= mesh.runtime.cd_dirty_edge;
- cd_dirty_loop |= mesh.runtime.cd_dirty_loop;
- for (const int slot_index : IndexRange(mesh.totcol)) {
- Material *material = mesh.mat[slot_index];
- materials.add(material);
- }
- }
- }
-
- /* Don't create an empty mesh. */
- if ((totverts + totloops + totedges + totpolys) == 0) {
- return nullptr;
- }
-
- Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
- /* Copy settings from the first input geometry set with a mesh. */
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
- BKE_mesh_copy_parameters_for_eval(new_mesh, &mesh);
- break;
- }
- }
- for (const int i : IndexRange(materials.size())) {
- Material *material = materials[i];
- BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
- }
- new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
- new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
- new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
- new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
-
- int vert_offset = 0;
- int loop_offset = 0;
- int edge_offset = 0;
- int poly_offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has_mesh()) {
- const Mesh &mesh = *set.get_mesh_for_read();
-
- Array<int> material_index_map(mesh.totcol);
- for (const int i : IndexRange(mesh.totcol)) {
- Material *material = mesh.mat[i];
- const int new_material_index = materials.index_of(material);
- material_index_map[i] = new_material_index;
- }
-
- for (const float4x4 &transform : set_group.transforms) {
- for (const int i : IndexRange(mesh.totvert)) {
- const MVert &old_vert = mesh.mvert[i];
- MVert &new_vert = new_mesh->mvert[vert_offset + i];
-
- new_vert = old_vert;
-
- const float3 new_position = transform * float3(old_vert.co);
- copy_v3_v3(new_vert.co, new_position);
- }
- for (const int i : IndexRange(mesh.totedge)) {
- const MEdge &old_edge = mesh.medge[i];
- MEdge &new_edge = new_mesh->medge[edge_offset + i];
- new_edge = old_edge;
- new_edge.v1 += vert_offset;
- new_edge.v2 += vert_offset;
- }
- for (const int i : IndexRange(mesh.totloop)) {
- const MLoop &old_loop = mesh.mloop[i];
- MLoop &new_loop = new_mesh->mloop[loop_offset + i];
- new_loop = old_loop;
- new_loop.v += vert_offset;
- new_loop.e += edge_offset;
- }
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &old_poly = mesh.mpoly[i];
- MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
- new_poly = old_poly;
- new_poly.loopstart += loop_offset;
- if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh.totcol) {
- new_poly.mat_nr = material_index_map[new_poly.mat_nr];
- }
- else {
- /* The material index was invalid before. */
- new_poly.mat_nr = 0;
- }
- }
-
- vert_offset += mesh.totvert;
- loop_offset += mesh.totloop;
- edge_offset += mesh.totedge;
- poly_offset += mesh.totpoly;
- }
- }
- }
-
- /* A possible optimization is to only tag the normals dirty when there are transforms that change
- * normals. */
- BKE_mesh_normals_tag_dirty(new_mesh);
-
- return new_mesh;
-}
-
-static void join_attributes(Span<GeometryInstanceGroup> set_groups,
- Span<GeometryComponentType> component_types,
- const Map<AttributeIDRef, AttributeKind> &attribute_info,
- GeometryComponent &result)
-{
- for (Map<AttributeIDRef, AttributeKind>::Item entry : attribute_info.items()) {
- const AttributeIDRef attribute_id = entry.key;
- const AttributeDomain domain_output = entry.value.domain;
- const CustomDataType data_type_output = entry.value.data_type;
- const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
- BLI_assert(cpp_type != nullptr);
-
- result.attribute_try_create(
- entry.key, domain_output, data_type_output, AttributeInitDefault());
- WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(attribute_id);
- if (!write_attribute || &write_attribute.varray.type() != cpp_type ||
- write_attribute.domain != domain_output) {
- continue;
- }
-
- fn::GVMutableArray_GSpan dst_span{write_attribute.varray};
-
- int offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- for (const GeometryComponentType component_type : component_types) {
- if (set.has(component_type)) {
- const GeometryComponent &component = *set.get_component_for_read(component_type);
- const int domain_size = component.attribute_domain_size(domain_output);
- if (domain_size == 0) {
- continue; /* Domain size is 0, so no need to increment the offset. */
- }
- GVArray source_attribute = component.attribute_try_get_for_read(
- attribute_id, domain_output, data_type_output);
-
- if (source_attribute) {
- fn::GVArray_GSpan src_span{source_attribute};
- const void *src_buffer = src_span.data();
- for (const int UNUSED(i) : set_group.transforms.index_range()) {
- void *dst_buffer = dst_span[offset];
- cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_size);
- offset += domain_size;
- }
- }
- else {
- offset += domain_size * set_group.transforms.size();
- }
- }
- }
- }
-
- dst_span.save();
- }
-}
-
-static PointCloud *join_pointcloud_position_attribute(Span<GeometryInstanceGroup> set_groups)
-{
- /* Count the total number of points. */
- int totpoint = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has<PointCloudComponent>()) {
- const PointCloudComponent &component = *set.get_component_for_read<PointCloudComponent>();
- totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
- }
- }
- if (totpoint == 0) {
- return nullptr;
- }
-
- PointCloud *new_pointcloud = BKE_pointcloud_new_nomain(totpoint);
- MutableSpan new_positions{(float3 *)new_pointcloud->co, new_pointcloud->totpoint};
-
- /* Transform each instance's point locations into the new point cloud. */
- int offset = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const PointCloud *pointcloud = set.get_pointcloud_for_read();
- if (pointcloud == nullptr) {
- continue;
- }
- for (const float4x4 &transform : set_group.transforms) {
- for (const int i : IndexRange(pointcloud->totpoint)) {
- new_positions[offset + i] = transform * float3(pointcloud->co[i]);
- }
- offset += pointcloud->totpoint;
- }
- }
-
- return new_pointcloud;
-}
-
-static CurveEval *join_curve_splines_and_builtin_attributes(Span<GeometryInstanceGroup> set_groups)
-{
- Vector<SplinePtr> new_splines;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (!set.has_curve()) {
- continue;
- }
-
- const CurveEval &source_curve = *set.get_curve_for_read();
- for (const SplinePtr &source_spline : source_curve.splines()) {
- for (const float4x4 &transform : set_group.transforms) {
- SplinePtr new_spline = source_spline->copy_without_attributes();
- new_spline->transform(transform);
- new_splines.append(std::move(new_spline));
- }
- }
- }
- if (new_splines.is_empty()) {
- return nullptr;
- }
-
- CurveEval *new_curve = new CurveEval();
- for (SplinePtr &new_spline : new_splines) {
- new_curve->add_spline(std::move(new_spline));
- }
-
- new_curve->attributes.reallocate(new_curve->splines().size());
- return new_curve;
-}
-
-static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
-{
- Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups);
- if (new_mesh == nullptr) {
- return;
- }
-
- MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
- dst_component.replace(new_mesh);
-
- /* Don't copy attributes that are stored directly in the mesh data structs. */
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups,
- {GEO_COMPONENT_TYPE_MESH},
- {"position", "material_index", "normal", "shade_smooth", "crease"},
- attributes);
- join_attributes(set_groups,
- {GEO_COMPONENT_TYPE_MESH},
- attributes,
- static_cast<GeometryComponent &>(dst_component));
-}
-
-static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_groups,
- GeometrySet &result)
-{
- PointCloud *new_pointcloud = join_pointcloud_position_attribute(set_groups);
- if (new_pointcloud == nullptr) {
- return;
- }
-
- PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
- dst_component.replace(new_pointcloud);
-
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {"position"}, attributes);
- join_attributes(set_groups,
- {GEO_COMPONENT_TYPE_POINT_CLOUD},
- attributes,
- static_cast<GeometryComponent &>(dst_component));
-}
-
-static void join_instance_groups_volume(Span<GeometryInstanceGroup> set_groups,
- GeometrySet &result)
-{
- /* Not yet supported; for now only return the first volume. Joining volume grids with the same
- * name requires resampling of at least one of the grids. The cell size of the resulting volume
- * has to be determined somehow. */
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- if (set.has<VolumeComponent>()) {
- result.add(*set.get_component_for_read<VolumeComponent>());
- return;
- }
- }
-}
-
-/**
- * Curve point domain attributes must be in the same order on every spline. The order might have
- * been different on separate instances, so ensure that all splines have the same order. Note that
- * because #Map is used, the order is not necessarily consistent every time, but it is the same for
- * every spline, and that's what matters.
- */
-static void sort_curve_point_attributes(const Map<AttributeIDRef, AttributeKind> &info,
- MutableSpan<SplinePtr> splines)
-{
- Vector<AttributeIDRef> new_order;
- for (Map<AttributeIDRef, AttributeKind>::Item item : info.items()) {
- if (item.value.domain == ATTR_DOMAIN_POINT) {
- /* Only sort attributes stored on splines. */
- new_order.append(item.key);
- }
- }
- for (SplinePtr &spline : splines) {
- spline->attributes.reorder(new_order);
- }
-}
-
-static void join_instance_groups_curve(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
-{
- CurveEval *curve = join_curve_splines_and_builtin_attributes(set_groups);
- if (curve == nullptr) {
- return;
- }
-
- CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
- dst_component.replace(curve);
-
- Map<AttributeIDRef, AttributeKind> attributes;
- geometry_set_gather_instances_attribute_info(
- set_groups,
- {GEO_COMPONENT_TYPE_CURVE},
- {"position", "radius", "tilt", "handle_left", "handle_right", "cyclic", "resolution"},
- attributes);
- join_attributes(set_groups,
- {GEO_COMPONENT_TYPE_CURVE},
- attributes,
- static_cast<GeometryComponent &>(dst_component));
- sort_curve_point_attributes(attributes, curve->splines());
- curve->assert_valid_point_attributes();
-}
-
-GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
-{
- if (!geometry_set.has_instances()) {
- return geometry_set;
- }
-
- GeometrySet new_geometry_set;
-
- Vector<GeometryInstanceGroup> set_groups;
- geometry_set_gather_instances(geometry_set, set_groups);
- join_instance_groups_mesh(set_groups, new_geometry_set);
- join_instance_groups_pointcloud(set_groups, new_geometry_set);
- join_instance_groups_volume(set_groups, new_geometry_set);
- join_instance_groups_curve(set_groups, new_geometry_set);
-
- return new_geometry_set;
-}
-
} // namespace blender::bke
void InstancesComponent::foreach_referenced_geometry(
@@ -624,11 +242,6 @@ void InstancesComponent::foreach_referenced_geometry(
}
}
-/**
- * If references have a collection or object type, convert them into geometry instances
- * recursively. After that, the geometry sets can be edited. There may still be instances of other
- * types of they can't be converted to geometry sets.
- */
void InstancesComponent::ensure_geometry_instances()
{
using namespace blender;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index bea65030c06..13338f33bd6 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -320,6 +320,7 @@ IDTypeInfo IDType_ID_GD = {
.name_plural = "grease_pencils",
.translation_context = BLT_I18NCONTEXT_ID_GPENCIL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = greasepencil_copy_data,
@@ -327,6 +328,7 @@ IDTypeInfo IDType_ID_GD = {
.make_local = NULL,
.foreach_id = greasepencil_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = greasepencil_blend_write,
@@ -363,7 +365,6 @@ void BKE_gpencil_batch_cache_free(bGPdata *gpd)
/* ************************************************** */
/* Memory Management */
-/* clean vertex groups weights */
void BKE_gpencil_free_point_weights(MDeformVert *dvert)
{
if (dvert == NULL) {
@@ -402,7 +403,6 @@ void BKE_gpencil_free_stroke_editcurve(bGPDstroke *gps)
gps->editcurve = NULL;
}
-/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(bGPDstroke *gps)
{
if (gps == NULL) {
@@ -426,7 +426,6 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps)
MEM_freeN(gps);
}
-/* Free strokes belonging to a gp-frame */
bool BKE_gpencil_free_strokes(bGPDframe *gpf)
{
bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
@@ -440,7 +439,6 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf)
return changed;
}
-/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
bGPDframe *gpf_next;
@@ -470,7 +468,6 @@ void BKE_gpencil_free_layer_masks(bGPDlayer *gpl)
BLI_freelinkN(&gpl->mask_layers, mask);
}
}
-/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
void BKE_gpencil_free_layers(ListBase *list)
{
bGPDlayer *gpl_next;
@@ -494,7 +491,6 @@ void BKE_gpencil_free_layers(ListBase *list)
}
}
-/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free_data(bGPdata *gpd, bool free_all)
{
/* free layers */
@@ -512,10 +508,6 @@ void BKE_gpencil_free_data(bGPdata *gpd, bool free_all)
}
}
-/**
- * Delete grease pencil evaluated data
- * \param gpd_eval: Grease pencil data-block
- */
void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
{
BKE_gpencil_free_data(gpd_eval, true);
@@ -524,11 +516,6 @@ void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
MEM_freeN(gpd_eval);
}
-/**
- * Tag data-block for depsgraph update.
- * Wrapper to avoid include Depsgraph tag functions in other modules.
- * \param gpd: Grease pencil data-block.
- */
void BKE_gpencil_tag(bGPdata *gpd)
{
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -537,12 +524,6 @@ void BKE_gpencil_tag(bGPdata *gpd)
/* ************************************************** */
/* Container Creation */
-/**
- * Add a new gp-frame to the given layer.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf = NULL, *gf = NULL;
@@ -596,12 +577,6 @@ bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
return gpf;
}
-/**
- * Add a copy of the active gp-frame to the given layer.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
{
bGPDframe *new_frame;
@@ -656,14 +631,6 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
return new_frame;
}
-/**
- * Add a new gp-layer and make it the active layer.
- * \param gpd: Grease pencil data-block
- * \param name: Name of the layer
- * \param setactive: Set as active
- * \param add_to_header: Used to force the layer added at header
- * \return Pointer to new layer
- */
bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd,
const char *name,
const bool setactive,
@@ -748,12 +715,6 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd,
return gpl;
}
-/**
- * Add a new grease pencil data-block.
- * \param bmain: Main pointer
- * \param name: Name of the datablock
- * \return Pointer to new data-block
- */
bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
bGPdata *gpd;
@@ -805,13 +766,6 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
/* Primitive Creation */
/* Utilities for easier bulk-creation of geometry */
-/**
- * Create a new stroke, with pre-allocated data buffers.
- * \param mat_idx: Index of the material
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
{
/* allocate memory for a new stroke */
@@ -848,15 +802,6 @@ bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
return gps;
}
-/**
- * Create a new stroke and add to frame.
- * \param gpf: Grease pencil frame
- * \param mat_idx: Material index
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \param insert_at_head: Add to the head of the strokes list
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_add(
bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head)
{
@@ -875,16 +820,6 @@ bGPDstroke *BKE_gpencil_stroke_add(
return gps;
}
-/**
- * Add a stroke and copy the temporary drawing color value
- * from one of the existing stroke.
- * \param gpf: Grease pencil frame
- * \param existing: Stroke with the style to copy
- * \param mat_idx: Material index
- * \param totpoints: Total points
- * \param thickness: Stroke thickness
- * \return Pointer to new stroke
- */
bGPDstroke *BKE_gpencil_stroke_add_existing_style(
bGPDframe *gpf, bGPDstroke *existing, int mat_idx, int totpoints, short thickness)
{
@@ -909,11 +844,6 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points)
/* ************************************************** */
/* Data Duplication */
-/**
- * Make a copy of a given gpencil weights.
- * \param gps_src: Source grease pencil stroke
- * \param gps_dst: Destination grease pencil stroke
- */
void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
{
if (gps_src == NULL) {
@@ -924,7 +854,6 @@ void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_d
BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
}
-/* Make a copy of a given gpencil stroke editcurve */
bGPDcurve *BKE_gpencil_stroke_curve_duplicate(bGPDcurve *gpc_src)
{
bGPDcurve *gpc_dst = MEM_dupallocN(gpc_src);
@@ -936,13 +865,6 @@ bGPDcurve *BKE_gpencil_stroke_curve_duplicate(bGPDcurve *gpc_src)
return gpc_dst;
}
-/**
- * Make a copy of a given grease-pencil stroke.
- * \param gps_src: Source grease pencil strokes.
- * \param dup_points: Duplicate points data.
- * \param dup_curve: Duplicate curve data.
- * \return Pointer to new stroke.
- */
bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
const bool dup_points,
const bool dup_curve)
@@ -980,11 +902,6 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
return gps_dst;
}
-/**
- * Make a copy of a given gpencil frame.
- * \param gpf_src: Source grease pencil frame
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_strokes)
{
bGPDstroke *gps_dst = NULL;
@@ -1013,11 +930,6 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src, const bool dup_
return gpf_dst;
}
-/**
- * Make a copy of strokes between gpencil frames.
- * \param gpf_src: Source grease pencil frame
- * \param gpf_dst: Destination grease pencil frame
- */
void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst)
{
bGPDstroke *gps_dst = NULL;
@@ -1035,11 +947,6 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds
}
}
-/**
- * Make a copy of a given gpencil layer.
- * \param gpl_src: Source grease pencil layer
- * \return Pointer to new layer
- */
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
const bool dup_frames,
const bool dup_strokes)
@@ -1078,9 +985,6 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src,
return gpl_dst;
}
-/**
- * Make a copy of a given gpencil layer settings.
- */
void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
{
gpl_dst->line_change = gpl_src->line_change;
@@ -1102,11 +1006,6 @@ void BKE_gpencil_layer_copy_settings(const bGPDlayer *gpl_src, bGPDlayer *gpl_ds
gpl_dst->flag = gpl_src->flag;
}
-/**
- * Make a copy of a given gpencil data-block.
- *
- * XXX: Should this be deprecated?
- */
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
bGPdata *gpd_dst;
@@ -1139,10 +1038,6 @@ bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool in
/* ************************************************** */
/* GP Stroke API */
-/**
- * Ensure selection status of stroke is in sync with its points.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_sync_selection(bGPdata *gpd, bGPDstroke *gps)
{
bGPDspoint *pt;
@@ -1206,14 +1101,12 @@ void BKE_gpencil_curve_sync_selection(bGPdata *gpd, bGPDstroke *gps)
}
}
-/* Assign unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_set(bGPdata *gpd, bGPDstroke *gps)
{
gpd->select_last_index++;
gps->select_index = gpd->select_last_index;
}
-/* Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(bGPDstroke *gps)
{
gps->select_index = 0;
@@ -1222,11 +1115,6 @@ void BKE_gpencil_stroke_select_index_reset(bGPDstroke *gps)
/* ************************************************** */
/* GP Frame API */
-/**
- * Delete the last stroke of the given frame.
- * \param gpl: Grease pencil layer
- * \param gpf: Grease pencil frame
- */
void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
{
bGPDstroke *gps = (gpf) ? gpf->strokes.last : NULL;
@@ -1258,11 +1146,6 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* ************************************************** */
/* GP Layer API */
-/**
- * Check if the given layer is able to be edited or not.
- * \param gpl: Grease pencil layer
- * \return True if layer is editable
- */
bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
{
/* Sanity check */
@@ -1279,12 +1162,6 @@ bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
return false;
}
-/**
- * Look up the gp-frame on the requested frame number, but don't add a new one.
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \return Pointer to frame
- */
bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf;
@@ -1301,16 +1178,6 @@ bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
return NULL;
}
-/**
- * Get the appropriate gp-frame from a given layer
- * - this sets the layer's actframe var (if allowed to)
- * - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
- *
- * \param gpl: Grease pencil layer
- * \param cframe: Frame number
- * \param addnew: Add option
- * \return Pointer to new frame
- */
bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
bGPDframe *gpf = NULL;
@@ -1465,12 +1332,6 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_
return gpl->actframe;
}
-/**
- * Delete the given frame from a layer.
- * \param gpl: Grease pencil layer
- * \param gpf: Grease pencil frame
- * \return True if delete was done
- */
bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf)
{
bool changed = false;
@@ -1494,12 +1355,6 @@ bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf)
return changed;
}
-/**
- * Get layer by name
- * \param gpd: Grease pencil data-block
- * \param name: Layer name
- * \return Pointer to layer
- */
bGPDlayer *BKE_gpencil_layer_named_get(bGPdata *gpd, const char *name)
{
if (name[0] == '\0') {
@@ -1508,12 +1363,6 @@ bGPDlayer *BKE_gpencil_layer_named_get(bGPdata *gpd, const char *name)
return BLI_findstring(&gpd->layers, name, offsetof(bGPDlayer, info));
}
-/**
- * Get mask layer by name.
- * \param gpl: Grease pencil layer
- * \param name: Mask name
- * \return Pointer to mask layer
- */
bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(bGPDlayer *gpl, const char *name)
{
if (name[0] == '\0') {
@@ -1522,12 +1371,6 @@ bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(bGPDlayer *gpl, const char *nam
return BLI_findstring(&gpl->mask_layers, name, offsetof(bGPDlayer_Mask, name));
}
-/**
- * Add grease pencil mask layer.
- * \param gpl: Grease pencil layer
- * \param name: Name of the mask
- * \return Pointer to new mask layer
- */
bGPDlayer_Mask *BKE_gpencil_layer_mask_add(bGPDlayer *gpl, const char *name)
{
@@ -1539,11 +1382,6 @@ bGPDlayer_Mask *BKE_gpencil_layer_mask_add(bGPDlayer *gpl, const char *name)
return mask;
}
-/**
- * Remove grease pencil mask layer.
- * \param gpl: Grease pencil layer
- * \param mask: Grease pencil mask layer
- */
void BKE_gpencil_layer_mask_remove(bGPDlayer *gpl, bGPDlayer_Mask *mask)
{
BLI_freelinkN(&gpl->mask_layers, mask);
@@ -1551,11 +1389,6 @@ void BKE_gpencil_layer_mask_remove(bGPDlayer *gpl, bGPDlayer_Mask *mask)
CLAMP_MIN(gpl->act_mask, 0);
}
-/**
- * Remove any reference to mask layer.
- * \param gpd: Grease pencil data-block
- * \param name: Name of the mask layer
- */
void BKE_gpencil_layer_mask_remove_ref(bGPdata *gpd, const char *name)
{
bGPDlayer_Mask *mask_next;
@@ -1587,11 +1420,6 @@ static int gpencil_cb_sort_masks(const void *arg1, const void *arg2)
return val;
}
-/**
- * Sort grease pencil mask layers.
- * \param gpd: Grease pencil data-block
- * \param gpl: Grease pencil layer
- */
void BKE_gpencil_layer_mask_sort(bGPdata *gpd, bGPDlayer *gpl)
{
/* Update sort index. */
@@ -1607,10 +1435,6 @@ void BKE_gpencil_layer_mask_sort(bGPdata *gpd, bGPDlayer *gpl)
BLI_listbase_sort(&gpl->mask_layers, gpencil_cb_sort_masks);
}
-/**
- * Sort all grease pencil mask layer.
- * \param gpd: Grease pencil data-block
- */
void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -1618,9 +1442,6 @@ void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd)
}
}
-/**
- * Make a copy of a given gpencil mask layers.
- */
void BKE_gpencil_layer_mask_copy(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
{
BLI_listbase_clear(&gpl_dst->mask_layers);
@@ -1631,9 +1452,6 @@ void BKE_gpencil_layer_mask_copy(const bGPDlayer *gpl_src, bGPDlayer *gpl_dst)
}
}
-/**
- * Clean any invalid mask layer.
- */
void BKE_gpencil_layer_mask_cleanup(bGPdata *gpd, bGPDlayer *gpl)
{
LISTBASE_FOREACH_MUTABLE (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
@@ -1643,9 +1461,6 @@ void BKE_gpencil_layer_mask_cleanup(bGPdata *gpd, bGPDlayer *gpl)
}
}
-/**
- * Clean any invalid mask layer for all layers.
- */
void BKE_gpencil_layer_mask_cleanup_all_layers(bGPdata *gpd)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -1674,21 +1489,11 @@ static int gpencil_cb_cmp_frame(void *thunk, const void *a, const void *b)
return 0;
}
-/**
- * Sort grease pencil frames.
- * \param gpl: Grease pencil layer
- * \param r_has_duplicate_frames: Duplicated frames flag
- */
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames)
{
BLI_listbase_sort_r(&gpl->frames, gpencil_cb_cmp_frame, r_has_duplicate_frames);
}
-/**
- * Get the active grease pencil layer for editing.
- * \param gpd: Grease pencil data-block
- * \return Pointer to layer
- */
bGPDlayer *BKE_gpencil_layer_active_get(bGPdata *gpd)
{
/* error checking */
@@ -1732,11 +1537,6 @@ bGPDlayer *BKE_gpencil_layer_get_by_name(bGPdata *gpd, char *name, int first_if_
return NULL;
}
-/**
- * Set active grease pencil layer.
- * \param gpd: Grease pencil data-block
- * \param active: Grease pencil layer to set as active
- */
void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active)
{
/* error checking */
@@ -1759,11 +1559,6 @@ void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active)
}
}
-/**
- * Set locked layers for autolock mode.
- * \param gpd: Grease pencil data-block
- * \param unlock: Unlock flag
- */
void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
{
BLI_assert(gpd != NULL);
@@ -1794,11 +1589,6 @@ void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock)
}
}
-/**
- * Delete grease pencil layer.
- * \param gpd: Grease pencil data-block
- * \param gpl: Grease pencil layer
- */
void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
{
/* error checking */
@@ -1821,11 +1611,6 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
BLI_freelinkN(&gpd->layers, gpl);
}
-/**
- * Get grease pencil material from brush.
- * \param brush: Brush
- * \return Pointer to material
- */
Material *BKE_gpencil_brush_material_get(Brush *brush)
{
Material *ma = NULL;
@@ -1838,11 +1623,6 @@ Material *BKE_gpencil_brush_material_get(Brush *brush)
return ma;
}
-/**
- * Set grease pencil brush material.
- * \param brush: Brush
- * \param ma: Material
- */
void BKE_gpencil_brush_material_set(Brush *brush, Material *ma)
{
BLI_assert(brush);
@@ -1858,13 +1638,6 @@ void BKE_gpencil_brush_material_set(Brush *brush, Material *ma)
}
}
-/**
- * Adds the pinned material to the object if necessary.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Pointer to material
- */
Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob, Brush *brush)
{
if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) {
@@ -1883,13 +1656,6 @@ Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob,
return BKE_object_material_get(ob, ob->actcol);
}
-/**
- * Assigns the material to object (if not already present) and returns its index (mat_nr).
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param material: Material
- * \return Index of the material
- */
int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *material)
{
if (!material) {
@@ -1904,14 +1670,6 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi
return index;
}
-/**
- * Creates a new grease-pencil material and assigns it to object.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \param name: Material name
- * \param r_index: value is set to zero based index of the new material if \a r_index is not NULL.
- * \return Material pointer.
- */
Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
{
Material *ma = BKE_gpencil_material_add(bmain, name);
@@ -1926,12 +1684,6 @@ Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *n
return ma;
}
-/**
- * Returns the material for a brush with respect to its pinned state.
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush)
{
if ((brush) && (brush->gpencil_settings) &&
@@ -1943,12 +1695,6 @@ Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush)
return BKE_object_material_get(ob, ob->actcol);
}
-/**
- * Returns the material index for a brush with respect to its pinned state.
- * \param ob: Grease pencil object
- * \param brush: Brush
- * \return Material index.
- */
int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
{
if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
@@ -1958,12 +1704,6 @@ int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
return ob->actcol - 1;
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object
- * \return Material pointer.
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main *bmain,
Object *ob,
ToolSettings *ts)
@@ -1976,13 +1716,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main
return BKE_gpencil_object_material_ensure_from_active_input_brush(bmain, ob, NULL);
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * \param bmain: Main pointer
- * \param ob: Grease pencil object.
- * \param brush: Brush
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain,
Object *ob,
Brush *brush)
@@ -2000,12 +1733,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain
return BKE_gpencil_object_material_ensure_from_active_input_material(ob);
}
-/**
- * Guaranteed to return a material assigned to object. Returns never NULL.
- * Only use this for materials unrelated to user input.
- * \param ob: Grease pencil object
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *ob)
{
Material *ma = BKE_object_material_get(ob, ob->actcol);
@@ -2016,11 +1743,6 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *
return BKE_material_default_gpencil();
}
-/**
- * Get active color, and add all default settings if we don't find anything.
- * \param ob: Grease pencil object
- * \return Material pointer
- */
Material *BKE_gpencil_object_material_ensure_active(Object *ob)
{
Material *ma = NULL;
@@ -2039,11 +1761,6 @@ Material *BKE_gpencil_object_material_ensure_active(Object *ob)
}
/* ************************************************** */
-/**
- * Check if stroke has any point selected
- * \param gps: Grease pencil stroke
- * \return True if selected
- */
bool BKE_gpencil_stroke_select_check(const bGPDstroke *gps)
{
const bGPDspoint *pt;
@@ -2059,11 +1776,6 @@ bool BKE_gpencil_stroke_select_check(const bGPDstroke *gps)
/* ************************************************** */
/* GP Object - Vertex Groups */
-/**
- * Remove a vertex group.
- * \param ob: Grease pencil object
- * \param defgroup: deform group
- */
void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
{
bGPdata *gpd = ob->data;
@@ -2103,10 +1815,6 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
-/**
- * Ensure stroke has vertex group.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
{
if (gps->dvert == NULL) {
@@ -2116,14 +1824,6 @@ void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
/* ************************************************** */
-/**
- * Get range of selected frames in layer.
- * Always the active frame is considered as selected, so if no more selected the range
- * will be equal to the current active frame.
- * \param gpl: Layer.
- * \param r_initframe: Number of first selected frame.
- * \param r_endframe: Number of last selected frame.
- */
void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe)
{
*r_initframe = gpl->actframe->framenum;
@@ -2141,14 +1841,6 @@ void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_e
}
}
-/**
- * Get Falloff factor base on frame range
- * \param gpf: Frame.
- * \param actnum: Number of active frame in layer.
- * \param f_init: Number of first selected frame.
- * \param f_end: Number of last selected frame.
- * \param cur_falloff: Curve with falloff factors.
- */
float BKE_gpencil_multiframe_falloff_calc(
bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
{
@@ -2180,12 +1872,6 @@ float BKE_gpencil_multiframe_falloff_calc(
return value;
}
-/**
- * Reassign strokes using a material.
- * \param gpd: Grease pencil data-block
- * \param totcol: Total materials
- * \param index: Index of the material
- */
void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -2201,12 +1887,6 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
}
}
-/**
- * Remove strokes using a material.
- * \param gpd: Grease pencil data-block
- * \param index: Index of the material
- * \return True if removed
- */
bool BKE_gpencil_material_index_used(bGPdata *gpd, int index)
{
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
@@ -2222,12 +1902,6 @@ bool BKE_gpencil_material_index_used(bGPdata *gpd, int index)
return false;
}
-/**
- * Remap material
- * \param gpd: Grease pencil data-block
- * \param remap: Remap index
- * \param remap_len: Remap length
- */
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len)
@@ -2253,15 +1927,6 @@ void BKE_gpencil_material_remap(struct bGPdata *gpd,
#undef MAT_NR_REMAP
}
-/**
- * Load a table with material conversion index for merged materials.
- * \param ob: Grease pencil object.
- * \param hue_threshold: Threshold for Hue.
- * \param sat_threshold: Threshold for Saturation.
- * \param val_threshold: Threshold for Value.
- * \param r_mat_table: return material table.
- * \return True if done.
- */
bool BKE_gpencil_merge_materials_table_get(Object *ob,
const float hue_threshold,
const float sat_threshold,
@@ -2381,15 +2046,6 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob,
return changed;
}
-/**
- * Merge similar materials
- * \param ob: Grease pencil object
- * \param hue_threshold: Threshold for Hue
- * \param sat_threshold: Threshold for Saturation
- * \param val_threshold: Threshold for Value
- * \param r_removed: Number of materials removed
- * \return True if done
- */
bool BKE_gpencil_merge_materials(Object *ob,
const float hue_threshold,
const float sat_threshold,
@@ -2448,10 +2104,6 @@ bool BKE_gpencil_merge_materials(Object *ob,
return changed;
}
-/**
- * Calc grease pencil statistics functions.
- * \param gpd: Grease pencil data-block
- */
void BKE_gpencil_stats_update(bGPdata *gpd)
{
gpd->totlayer = 0;
@@ -2471,12 +2123,6 @@ void BKE_gpencil_stats_update(bGPdata *gpd)
}
}
-/**
- * Get material index (0-based like mat_nr not actcol).
- * \param ob: Grease pencil object
- * \param ma: Material
- * \return Index of the material
- */
int BKE_gpencil_object_material_index_get(Object *ob, Material *ma)
{
short *totcol = BKE_object_material_len_p(ob);
@@ -2519,11 +2165,6 @@ Material *BKE_gpencil_object_material_ensure_by_name(Main *bmain,
return BKE_gpencil_object_material_new(bmain, ob, name, r_index);
}
-/**
- * Create a default palette.
- * \param bmain: Main pointer
- * \param scene: Scene
- */
void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
{
const char *hexcol[] = {
@@ -2573,15 +2214,6 @@ void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
BKE_paint_palette_set(&ts->gp_vertexpaint->paint, palette);
}
-/**
- * Create grease pencil strokes from image
- * \param sima: Image
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param size: Size
- * \param mask: Mask
- * \return True if done
- */
bool BKE_gpencil_from_image(
SpaceImage *sima, bGPdata *gpd, bGPDframe *gpf, const float size, const bool mask)
{
@@ -2713,6 +2345,8 @@ void BKE_gpencil_visible_stroke_iter(bGPdata *gpd,
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Advanced Iterator
*
@@ -2917,11 +2551,6 @@ void BKE_gpencil_visible_stroke_advanced_iter(ViewLayer *view_layer,
}
}
-/**
- * Update original pointers in evaluated frame.
- * \param gpf_orig: Original grease-pencil frame.
- * \param gpf_eval: Evaluated grease pencil frame.
- */
void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig,
const struct bGPDframe *gpf_eval)
{
@@ -2950,11 +2579,6 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig
}
}
-/**
- * Update pointers of eval data to original data to keep references.
- * \param ob_orig: Original grease pencil object
- * \param ob_eval: Evaluated grease pencil object
- */
void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_eval)
{
bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
@@ -2985,13 +2609,6 @@ void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_ev
}
}
-/**
- * Get parent matrix, including layer parenting.
- * \param depsgraph: Depsgraph
- * \param obact: Grease pencil object
- * \param gpl: Grease pencil layer
- * \param diff_mat: Result parent matrix
- */
void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
Object *obact,
bGPDlayer *gpl,
@@ -3040,11 +2657,6 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph,
unit_m4(diff_mat); /* not defined type */
}
-/**
- * Update parent matrix and local transforms.
- * \param depsgraph: Depsgraph
- * \param ob: Grease pencil object
- */
void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
{
if (ob->type != OB_GPENCIL) {
@@ -3104,12 +2716,6 @@ void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob)
}
}
-/**
- * Find material by name prefix.
- * \param ob: Object pointer
- * \param name_prefix: Prefix name of the material
- * \return Index
- */
int BKE_gpencil_material_find_index_by_name_prefix(Object *ob, const char *name_prefix)
{
const int name_prefix_len = strlen(name_prefix);
@@ -3124,7 +2730,6 @@ int BKE_gpencil_material_find_index_by_name_prefix(Object *ob, const char *name_
return -1;
}
-/* Create a hash with the list of selected frame number. */
void BKE_gpencil_frame_selected_hash(bGPdata *gpd, struct GHash *r_list)
{
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 98e481e6ea8..d633678b873 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -477,17 +477,6 @@ static void gpencil_editstroke_deselect_all(bGPDcurve *gpc)
gpc->flag &= ~GP_CURVE_SELECT;
}
-/**
- * Convert a curve object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_cu: Curve to convert.
- * \param use_collections: Create layers using collection names.
- * \param scale_thickness: Scale thickness factor.
- * \param sample: Sample distance, zero to disable.
- */
void BKE_gpencil_convert_curve(Main *bmain,
Scene *scene,
Object *ob_gp,
@@ -639,9 +628,6 @@ static bGPDcurve *gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps,
return NULL;
}
-/**
- * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
- */
bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
const float error_threshold,
const float corner_angle,
@@ -753,9 +739,6 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
return editcurve;
}
-/**
- * Updates the editcurve for a stroke. Frees the old curve if one exists and generates a new one.
- */
void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
{
if (gps == NULL || gps->totpoints < 0) {
@@ -778,9 +761,6 @@ void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstrok
gps->editcurve = editcurve;
}
-/**
- * Sync the selection from stroke to editcurve
- */
void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata *UNUSED(gpd),
bGPDstroke *gps,
bGPDcurve *gpc)
@@ -807,9 +787,6 @@ void BKE_gpencil_editcurve_stroke_sync_selection(bGPdata *UNUSED(gpd),
}
}
-/**
- * Sync the selection from editcurve to stroke
- */
void BKE_gpencil_stroke_editcurve_sync_selection(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gpc)
{
if (gpc->flag & GP_CURVE_SELECT) {
@@ -1055,9 +1032,6 @@ static float *gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point
return (float(*))r_points;
}
-/**
- * Recalculate stroke points with the editcurve of the stroke.
- */
void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
const uint resolution,
const bool adaptive)
@@ -1142,9 +1116,6 @@ void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
MEM_freeN(points);
}
-/**
- * Recalculate the handles of the edit curve of a grease pencil stroke
- */
void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke *gps)
{
if (gps == NULL || gps->editcurve == NULL) {
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index fffc13c49a8..b5190f598c6 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -67,15 +67,10 @@
using blender::float3;
using blender::Span;
-/* GP Object - Boundbox Support */
-/**
- *Get min/max coordinate bounds for single stroke.
- * \param gps: Grease pencil stroke
- * \param use_select: Include only selected points
- * \param r_min: Result minimum coordinates
- * \param r_max: Result maximum coordinates
- * \return True if it was possible to calculate
- */
+/* -------------------------------------------------------------------- */
+/** \name Grease Pencil Object: Bound-box Support
+ * \{ */
+
bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
const bool use_select,
float r_min[3],
@@ -104,13 +99,6 @@ bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
return changed;
}
-/**
- * Get min/max bounds of all strokes in grease pencil data-block.
- * \param gpd: Grease pencil datablock
- * \param r_min: Result minimum coordinates
- * \param r_max: Result maximum coordinates
- * \return True if it was possible to calculate
- */
bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
{
bool changed = false;
@@ -134,11 +122,6 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
return changed;
}
-/**
- * Compute center of bounding box.
- * \param gpd: Grease pencil data-block
- * \param r_centroid: Location of the center
- */
void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
{
float3 min;
@@ -149,10 +132,6 @@ void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
mul_v3_v3fl(r_centroid, tot, 0.5f);
}
-/**
- * Compute stroke bounding box.
- * \param gps: Grease pencil Stroke
- */
void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)
{
INIT_MINMAX(gps->boundbox_min, gps->boundbox_max);
@@ -184,11 +163,6 @@ static void boundbox_gpencil(Object *ob)
bb->flag &= ~BOUNDBOX_DIRTY;
}
-/**
- * Get grease pencil object bounding box.
- * \param ob: Grease pencil object
- * \return Bounding box
- */
BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
if (ELEM(nullptr, ob, ob->data)) {
@@ -218,7 +192,11 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob)
return ob->runtime.bb;
}
-/* ************************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Sample
+ * \{ */
static int stroke_march_next_point(const bGPDstroke *gps,
const int index_next_pt,
@@ -431,12 +409,6 @@ static void stroke_interpolate_deform_weights(
}
}
-/**
- * Resample a stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Stroke to sample
- * \param dist: Distance of one segment
- */
bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select)
{
bGPDspoint *pt = gps->points;
@@ -594,15 +566,6 @@ static bool BKE_gpencil_stroke_extra_points(bGPDstroke *gps,
return true;
}
-/**
- * Backbone stretch similar to Freestyle.
- * \param gps: Stroke to sample.
- * \param dist: Length of the added section.
- * \param overshoot_fac: Relative length of the curve which is used to determine the extension.
- * \param mode: Affect to Start, End or Both extremes (0->Both, 1->Start, 2->End)
- * \param follow_curvature: True for approximating curvature of given overshoot.
- * \param extra_point_count: When follow_curvature is true, use this amount of extra points
- */
bool BKE_gpencil_stroke_stretch(bGPDstroke *gps,
const float dist,
const float overshoot_fac,
@@ -779,12 +742,12 @@ bool BKE_gpencil_stroke_stretch(bGPDstroke *gps,
return true;
}
-/**
- * Trim stroke to needed segments
- * \param gps: Target stroke
- * \param index_from: the index of the first point to be used in the trimmed result
- * \param index_to: the index of the last point to be used in the trimmed result
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Trim
+ * \{ */
+
bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to)
{
bGPDspoint *pt = gps->points, *new_pt;
@@ -837,15 +800,12 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const
return true;
}
-/**
- * Split stroke.
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param gps: Grease pencil original stroke
- * \param before_index: Position of the point to split
- * \param remaining_gps: Secondary stroke after split.
- * \return True if the split was done
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Split
+ * \{ */
+
bool BKE_gpencil_stroke_split(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
@@ -898,12 +858,12 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd,
return true;
}
-/**
- * Shrink the stroke by length.
- * \param gps: Stroke to shrink
- * \param dist: delta length
- * \param mode: 1->Start, 2->End
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Shrink
+ * \{ */
+
bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mode)
{
#define START 1
@@ -976,13 +936,14 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo
return true;
}
-/**
- * Apply smooth position to stroke point.
- * \param gps: Stroke to smooth
- * \param i: Point index
- * \param inf: Amount of smoothing to apply
- */
-bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Positions
+ * \{ */
+
+bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf, const bool smooth_caps)
{
bGPDspoint *pt = &gps->points[i];
float sco[3] = {0.0f};
@@ -996,7 +957,7 @@ bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
/* Only affect endpoints by a fraction of the normal strength,
* to prevent the stroke from shrinking too much
*/
- if (!is_cyclic && ELEM(i, 0, gps->totpoints - 1)) {
+ if ((!smooth_caps) && (!is_cyclic && ELEM(i, 0, gps->totpoints - 1))) {
inf *= 0.1f;
}
@@ -1054,12 +1015,12 @@ bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf)
return true;
}
-/**
- * Apply smooth strength to stroke point.
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Strength
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1132,12 +1093,12 @@ bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float
return true;
}
-/**
- * Apply smooth for thickness to stroke point (use pressure).
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Thickness
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1209,12 +1170,12 @@ bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float
return true;
}
-/**
- * Apply smooth for UV rotation to stroke point (use pressure).
- * \param gps: Stroke to smooth
- * \param point_index: Point index
- * \param influence: Amount of smoothing to apply
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth UV
+ * \{ */
+
bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence)
{
bGPDspoint *ptb = &gps->points[point_index];
@@ -1266,14 +1227,6 @@ bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influe
return true;
}
-/**
- * Get points of stroke always flat to view not affected
- * by camera view or view position.
- * \param points: Array of grease pencil points (3D)
- * \param totpoints: Total of points
- * \param points2d: Result array of 2D points
- * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
- */
void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
int totpoints,
float (*points2d)[2],
@@ -1348,17 +1301,6 @@ void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
*r_direction = (cross >= 0.0f) ? 1 : -1;
}
-/**
- * Get points of stroke always flat to view not affected by camera view or view position
- * using another stroke as reference.
- * \param ref_points: Array of reference points (3D)
- * \param ref_totpoints: Total reference points
- * \param points: Array of points to flat (3D)
- * \param totpoints: Total points
- * \param points2d: Result array of 2D points
- * \param scale: Scale factor
- * \param r_direction: Return Concave (-1), Convex (1), or Auto-detect (0)
- */
void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
int ref_totpoints,
const bGPDspoint *points,
@@ -1482,10 +1424,12 @@ static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
}
}
-/**
- * Triangulate stroke to generate data for filling areas.
- * \param gps: Grease pencil stroke
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Fill Triangulate
+ * \{ */
+
void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
{
BLI_assert(gps->totpoints >= 3);
@@ -1545,10 +1489,6 @@ void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
MEM_SAFE_FREE(uv);
}
-/**
- * Update Stroke UV data.
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
{
if (gps == nullptr || gps->totpoints == 0) {
@@ -1564,11 +1504,6 @@ void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
}
}
-/**
- * Recalc all internal geometry data for the stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps)
{
if (gps == nullptr) {
@@ -1606,12 +1541,6 @@ void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps)
BKE_gpencil_stroke_boundingbox_calc(gps);
}
-/**
- * Calculate grease pencil stroke length.
- * \param gps: Grease pencil stroke
- * \param use_3d: Set to true to use 3D points
- * \return Length of the stroke
- */
float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
{
if (!gps->points || gps->totpoints < 2) {
@@ -1632,7 +1561,6 @@ float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
return total_length;
}
-/** Calculate grease pencil stroke length between points. */
float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
const int start_index,
const int end_index,
@@ -1660,10 +1588,6 @@ float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
return total_length;
}
-/**
- * Trim stroke to the first intersection or loop.
- * \param gps: Stroke data
- */
bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
{
if (gps->totpoints < 4) {
@@ -1756,10 +1680,6 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
return intersect;
}
-/**
- * Close grease pencil stroke.
- * \param gps: Stroke to close
- */
bool BKE_gpencil_stroke_close(bGPDstroke *gps)
{
bGPDspoint *pt1 = nullptr;
@@ -1845,13 +1765,12 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps)
return true;
}
-/**
- * Dissolve points in stroke.
- * \param gpd: Grease pencil data-block
- * \param gpf: Grease pencil frame
- * \param gps: Grease pencil stroke
- * \param tag: Type of tag for point
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Points
+ * \{ */
+
void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, const short tag)
{
bGPDspoint *pt;
@@ -1934,11 +1853,12 @@ void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps,
}
}
-/**
- * Calculate stroke normals.
- * \param gps: Grease pencil stroke
- * \param r_normal: Return Normal vector normalized
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Normal Calculation
+ * \{ */
+
void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
{
if (gps->totpoints < 3) {
@@ -1969,18 +1889,12 @@ void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
normalize_v3(r_normal);
}
-/* Stroke Simplify ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Simplify
+ * \{ */
-/**
- * Reduce a series of points to a simplified version, but
- * maintains the general shape of the series
- *
- * Ramer - Douglas - Peucker algorithm
- * by http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- * \param epsilon: Epsilon value to define precision of the algorithm
- */
void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float epsilon)
{
bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points);
@@ -2085,11 +1999,6 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e
MEM_SAFE_FREE(marked);
}
-/**
- * Simplify alternate vertex of stroke except extremes.
- * \param gpd: Grease pencil data-block
- * \param gps: Grease pencil stroke
- */
void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
{
if (gps->totpoints < 5) {
@@ -2150,13 +2059,6 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
MEM_SAFE_FREE(old_dvert);
}
-/**
- * Subdivide a stroke
- * \param gpd: Grease pencil data-block
- * \param gps: Stroke
- * \param level: Level of subdivision
- * \param type: Type of subdivision
- */
void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int type)
{
bGPDspoint *temp_points;
@@ -2269,19 +2171,12 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/* Merge by distance ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge by Distance
+ * \{ */
-/**
- * Reduce a series of points when the distance is below a threshold.
- * Special case for first and last points (both are kept) for other points,
- * the merge point always is at first point.
- *
- * \param gpd: Grease pencil data-block.
- * \param gpf: Grease Pencil frame.
- * \param gps: Grease Pencil stroke.
- * \param threshold: Distance between points.
- * \param use_unselected: Set to true to analyze all stroke and not only selected points.
- */
void BKE_gpencil_stroke_merge_distance(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
@@ -2639,22 +2534,6 @@ static void make_element_name(const char *obname, const char *name, const int ma
BLI_strncpy_utf8(r_name, str, maxlen);
}
-/**
- * Convert a mesh object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer.
- * \param depsgraph: Original depsgraph.
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_mesh: Mesh to convert.
- * \param angle: Limit angle to consider a edge-loop ends.
- * \param thickness: Thickness of the strokes.
- * \param offset: Offset along the normals.
- * \param matrix: Transformation matrix.
- * \param frame_offset: Destination frame number offset.
- * \param use_seams: Only export seam edges.
- * \param use_faces: Export faces as filled strokes.
- */
bool BKE_gpencil_convert_mesh(Main *bmain,
Depsgraph *depsgraph,
Scene *scene,
@@ -2807,11 +2686,6 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
return true;
}
-/**
- * Apply grease pencil Transforms.
- * \param gpd: Grease pencil data-block
- * \param mat: Transformation matrix
- */
void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4])
{
if (gpd == nullptr) {
@@ -2845,7 +2719,6 @@ void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4])
}
}
-/* Used for "move only origins" in object_data_transform.c */
int BKE_gpencil_stroke_point_count(const bGPdata *gpd)
{
int total_points = 0;
@@ -2872,7 +2745,6 @@ int BKE_gpencil_stroke_point_count(const bGPdata *gpd)
return total_points;
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_data)
{
if (gpd == nullptr) {
@@ -2903,7 +2775,6 @@ void BKE_gpencil_point_coords_get(bGPdata *gpd, GPencilPointCoordinates *elem_da
}
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates *elem_data)
{
if (gpd == nullptr) {
@@ -2937,7 +2808,6 @@ void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates
}
}
-/* Used for "move only origins" in object_data_transform.c */
void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd,
const GPencilPointCoordinates *elem_data,
const float mat[4][4])
@@ -2974,10 +2844,6 @@ void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd,
}
}
-/**
- * Set a random color to stroke using vertex color.
- * \param gps: Stroke
- */
void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
{
BLI_assert(gps->totpoints > 0);
@@ -2993,7 +2859,6 @@ void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
}
}
-/* Flip stroke. */
void BKE_gpencil_stroke_flip(bGPDstroke *gps)
{
/* Reverse points. */
@@ -3103,20 +2968,6 @@ static void gpencil_stroke_join_islands(bGPdata *gpd,
BKE_gpencil_free_stroke(gps_last);
}
-/* Split the given stroke into several new strokes, partitioning
- * it based on whether the stroke points have a particular flag
- * is set (e.g. "GP_SPOINT_SELECT" in most cases, but not always)
- *
- * The algorithm used here is as follows:
- * 1) We firstly identify the number of "islands" of non-tagged points
- * which will all end up being in new strokes.
- * - In the most extreme case (i.e. every other vert is a 1-vert island),
- * we have at most n / 2 islands
- * - Once we start having larger islands than that, the number required
- * becomes much less
- * 2) Each island gets converted to a new stroke
- * If the number of points is <= limit, the stroke is deleted
- */
bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
@@ -3126,6 +2977,16 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
const bool flat_cap,
const int limit)
{
+ /* The algorithm used here is as follows:
+ * 1) We firstly identify the number of "islands" of non-tagged points
+ * which will all end up being in new strokes.
+ * - In the most extreme case (i.e. every other vert is a 1-vert island),
+ * we have at most `n / 2` islands
+ * - Once we start having larger islands than that, the number required
+ * becomes much less
+ * 2) Each island gets converted to a new stroke
+ * If the number of points is <= limit, the stroke is deleted. */
+
tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN(
sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
bool in_island = false;
@@ -3430,7 +3291,6 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
}
}
-/* Join two strokes using the shortest distance (reorder stroke if necessary ) */
void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
bGPDstroke *gps_b,
const bool leave_gaps,
@@ -3548,7 +3408,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
for (i = start; i < end; i++) {
pt = &gps_a->points[i];
pt->pressure += (avg_pressure - pt->pressure) * ratio;
- BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f);
+ BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f, false);
ratio += step;
/* In the center, reverse the ratio. */
@@ -3560,7 +3420,6 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
}
}
-/* Copy the stroke of the frame to all frames selected (except current). */
void BKE_gpencil_stroke_copy_to_keyframes(
bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const bool tail)
{
@@ -3599,7 +3458,11 @@ void BKE_gpencil_stroke_copy_to_keyframes(
BLI_ghash_free(frame_list, nullptr, nullptr);
}
-/* Stroke Uniform Subdivide ------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Uniform Subdivide
+ * \{ */
struct tSamplePoint {
struct tSamplePoint *next, *prev;
@@ -3649,15 +3512,6 @@ static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamp
return new_edge;
}
-/**
- * Subdivide the grease pencil stroke so the number of points is target_number.
- * Does not change the shape of the stroke. The new points will be distributed as
- * uniformly as possible by repeatedly subdividing the current longest edge.
- *
- * \param gps: The stroke to be up-sampled.
- * \param target_number: The number of points the up-sampled stroke should have.
- * \param select: Select/Deselect the stroke.
- */
void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
bGPDstroke *gps,
const uint32_t target_number,
@@ -3793,12 +3647,6 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/**
- * Stroke to view space
- * Transforms a stroke to view space. This allows for manipulations in 2D but also easy conversion
- * back to 3D.
- * NOTE: also takes care of parent space transform
- */
void BKE_gpencil_stroke_to_view_space(RegionView3D *rv3d,
bGPDstroke *gps,
const float diff_mat[4][4])
@@ -3812,12 +3660,6 @@ void BKE_gpencil_stroke_to_view_space(RegionView3D *rv3d,
}
}
-/**
- * Stroke from view space
- * Transforms a stroke from view space back to world space. Inverse of
- * BKE_gpencil_stroke_to_view_space
- * NOTE: also takes care of parent space transform
- */
void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d,
bGPDstroke *gps,
const float diff_mat[4][4])
@@ -3832,8 +3674,11 @@ void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d,
}
}
-/* ----------------------------------------------------------------------------- */
-/* Stroke to perimeter */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke to Perimeter
+ * \{ */
struct tPerimeterPoint {
struct tPerimeterPoint *next, *prev;
@@ -4238,12 +4083,6 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
return perimeter_list;
}
-/**
- * Calculates the perimeter of a stroke projected from the view and
- * returns it as a new stroke.
- * \param subdivisions: Number of subdivisions for the start and end caps
- * \return: bGPDstroke pointer to stroke perimeter
- */
bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
bGPdata *gpd,
const bGPDlayer *gpl,
@@ -4310,7 +4149,6 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
return perimeter_stroke;
}
-/** Get average pressure. */
float BKE_gpencil_stroke_average_pressure_get(bGPDstroke *gps)
{
@@ -4327,7 +4165,6 @@ float BKE_gpencil_stroke_average_pressure_get(bGPDstroke *gps)
return tot / (float)gps->totpoints;
}
-/** Check if the thickness of the stroke is constant. */
bool BKE_gpencil_stroke_is_pressure_constant(bGPDstroke *gps)
{
if (gps->totpoints == 1) {
@@ -4344,4 +4181,5 @@ bool BKE_gpencil_stroke_is_pressure_constant(bGPDstroke *gps)
return true;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index a6164340477..62604286b43 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -36,6 +36,7 @@
#include "DNA_armature_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -50,7 +51,9 @@
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_material.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_shrinkwrap.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -77,43 +80,83 @@ static GpencilVirtualModifierData virtualModifierCommonData;
*/
/**
- * Init grease pencil lattice deform data.
+ * Init grease pencil cache deform data.
* \param ob: Grease pencil object
*/
-void BKE_gpencil_lattice_init(Object *ob)
+void BKE_gpencil_cache_data_init(Depsgraph *depsgraph, Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
- if (md->type == eGpencilModifierType_Lattice) {
- LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
- Object *latob = NULL;
+ switch (md->type) {
+ case eGpencilModifierType_Lattice: {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Object *latob = NULL;
+
+ latob = mmd->object;
+ if ((!latob) || (latob->type != OB_LATTICE)) {
+ return;
+ }
+ if (mmd->cache_data) {
+ BKE_lattice_deform_data_destroy(mmd->cache_data);
+ }
- latob = mmd->object;
- if ((!latob) || (latob->type != OB_LATTICE)) {
- return;
+ /* init deform data */
+ mmd->cache_data = BKE_lattice_deform_data_create(latob, ob);
+ break;
}
- if (mmd->cache_data) {
- BKE_lattice_deform_data_destroy(mmd->cache_data);
+ case eGpencilModifierType_Shrinkwrap: {
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ ob = mmd->target;
+ if (!ob) {
+ return;
+ }
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ Object *ob_target = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__);
+ if (BKE_shrinkwrap_init_tree(
+ mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) {
+ }
+ else {
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ break;
}
- /* init deform data */
- mmd->cache_data = BKE_lattice_deform_data_create(latob, ob);
+ default:
+ break;
}
}
}
/**
- * Clear grease pencil lattice deform data.
+ * Clear grease pencil cache deform data.
* \param ob: Grease pencil object
*/
-void BKE_gpencil_lattice_clear(Object *ob)
+void BKE_gpencil_cache_data_clear(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
- if (md->type == eGpencilModifierType_Lattice) {
- LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
- if ((mmd) && (mmd->cache_data)) {
- BKE_lattice_deform_data_destroy(mmd->cache_data);
- mmd->cache_data = NULL;
+ switch (md->type) {
+ case eGpencilModifierType_Lattice: {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ BKE_lattice_deform_data_destroy(mmd->cache_data);
+ mmd->cache_data = NULL;
+ }
+ break;
}
+ case eGpencilModifierType_Shrinkwrap: {
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ break;
+ }
+ default:
+ break;
}
}
}
@@ -121,8 +164,6 @@ void BKE_gpencil_lattice_clear(Object *ob)
/* *************************************************** */
/* Modifier Methods - Evaluation Loops, etc. */
-/* This is to include things that are not modifiers in the evaluation of the modifier stack, for
- * example parenting to an armature or lattice without having a real modifier. */
GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
const Object *ob, GpencilVirtualModifierData *UNUSED(virtualModifierData))
{
@@ -150,11 +191,6 @@ GpencilModifierData *BKE_gpencil_modifiers_get_virtual_modifierlist(
return md;
}
-/**
- * Check if object has grease pencil Geometry modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_geometry_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -167,11 +203,6 @@ bool BKE_gpencil_has_geometry_modifiers(Object *ob)
return false;
}
-/**
- * Check if object has grease pencil Time modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_time_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -184,11 +215,6 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
return false;
}
-/**
- * Check if object has grease pencil transform stroke modifiers.
- * \param ob: Grease pencil object
- * \return True if exist
- */
bool BKE_gpencil_has_transform_modifiers(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -258,7 +284,6 @@ bool BKE_gpencil_is_first_lineart_in_stack(const Object *ob, const GpencilModifi
return false;
}
-/* Get Time modifier frame number. */
int BKE_gpencil_time_modifier_cfra(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -292,11 +317,6 @@ int BKE_gpencil_time_modifier_cfra(Depsgraph *depsgraph,
return nfra;
}
-/**
- * Set current grease pencil active frame.
- * \param depsgraph: Current depsgraph
- * \param gpd: Grease pencil data-block.
- */
void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
{
DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
@@ -320,9 +340,6 @@ void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
}
}
-/**
- * Initialize grease pencil modifier.
- */
void BKE_gpencil_modifier_init(void)
{
/* Initialize modifier types */
@@ -346,11 +363,6 @@ void BKE_gpencil_modifier_init(void)
#endif
}
-/**
- * Create new grease pencil modifier.
- * \param type: Type of modifier
- * \return New modifier pointer
- */
GpencilModifierData *BKE_gpencil_modifier_new(int type)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
@@ -386,11 +398,6 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData),
}
}
-/**
- * Free grease pencil modifier data
- * \param md: Modifier data
- * \param flag: Flags
- */
void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
@@ -411,16 +418,11 @@ void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
MEM_freeN(md);
}
-/**
- * Free grease pencil modifier data
- * \param md: Modifier data
- */
void BKE_gpencil_modifier_free(GpencilModifierData *md)
{
BKE_gpencil_modifier_free_ex(md, 0);
}
-/* check unique name */
bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
{
if (modifiers && gmd) {
@@ -435,11 +437,6 @@ bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *
return false;
}
-/**
- * Check if grease pencil modifier depends on time.
- * \param md: Modifier data
- * \return True if depends on time
- */
bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
@@ -447,11 +444,6 @@ bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
return mti->dependsOnTime && mti->dependsOnTime(md);
}
-/**
- * Get grease pencil modifier information.
- * \param type: Type of modifier
- * \return Pointer to type
- */
const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type)
{
/* type unsigned, no need to check < 0 */
@@ -463,12 +455,6 @@ const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType
return NULL;
}
-/**
- * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
- *
- * \param type: Type of modifier
- * \param r_idname: ID name
- */
void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
@@ -482,11 +468,6 @@ void BKE_gpencil_modifier_panel_expand(GpencilModifierData *md)
md->ui_expand_flag |= UI_PANEL_DATA_EXPAND_ROOT;
}
-/**
- * Generic grease pencil modifier copy data.
- * \param md_src: Source modifier data
- * \param md_dst: Target modifier data
- */
void BKE_gpencil_modifier_copydata_generic(const GpencilModifierData *md_src,
GpencilModifierData *md_dst)
{
@@ -516,12 +497,6 @@ static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-/**
- * Copy grease pencil modifier data.
- * \param md: Source modifier data
- * \param target: Target modifier data
- * \param flag: Flags
- */
void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
GpencilModifierData *target,
const int flag)
@@ -543,11 +518,6 @@ void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
}
}
-/**
- * Copy grease pencil modifier data.
- * \param md: Source modifier data
- * \param target: Target modifier data
- */
void BKE_gpencil_modifier_copydata(GpencilModifierData *md, GpencilModifierData *target)
{
BKE_gpencil_modifier_copydata_ex(md, target, 0);
@@ -566,19 +536,14 @@ GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifi
return md;
}
-/**
- * Set grease pencil modifier error.
- * \param md: Modifier data
- * \param _format: Format
- */
-void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format, ...)
+void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *format, ...)
{
char buffer[512];
va_list ap;
- const char *format = TIP_(_format);
+ const char *format_tip = TIP_(format);
- va_start(ap, _format);
- vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format_tip, ap);
va_end(ap);
buffer[sizeof(buffer) - 1] = '\0';
@@ -591,12 +556,6 @@ void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format
CLOG_STR_ERROR(&LOG, md->error);
}
-/**
- * Check whether given modifier is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param gmd: May be NULL, in which case we consider it as a non-local modifier case.
- */
bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const Object *ob,
const GpencilModifierData *gmd)
{
@@ -604,12 +563,6 @@ bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const Object *ob,
(gmd == NULL || (gmd->flag & eGpencilModifierFlag_OverrideLibrary_Local) == 0));
}
-/**
- * Link grease pencil modifier related IDs.
- * \param ob: Grease pencil object
- * \param walk: Walk option
- * \param userData: User data
- */
void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
@@ -623,12 +576,6 @@ void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc wa
}
}
-/**
- * Link grease pencil modifier related Texts.
- * \param ob: Grease pencil object
- * \param walk: Walk option
- * \param userData: User data
- */
void BKE_gpencil_modifiers_foreach_tex_link(Object *ob,
GreasePencilTexWalkFunc walk,
void *userData)
@@ -644,12 +591,6 @@ void BKE_gpencil_modifiers_foreach_tex_link(Object *ob,
}
}
-/**
- * Find grease pencil modifier by name.
- * \param ob: Grease pencil object
- * \param name: Name to find
- * \return Pointer to modifier
- */
GpencilModifierData *BKE_gpencil_modifiers_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
@@ -677,14 +618,6 @@ static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob
return remap_cfra;
}
-/**
- * Get the current frame re-timed with time modifiers.
- * \param depsgraph: Current depsgraph.
- * \param scene: Current scene
- * \param ob: Grease pencil object
- * \param gpl: Grease pencil layer
- * \return New frame number
- */
bGPDframe *BKE_gpencil_frame_retime_get(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -753,12 +686,6 @@ static bGPdata *gpencil_copy_for_eval(bGPdata *gpd)
return result;
}
-/**
- * Prepare grease pencil eval data for modifiers
- * \param depsgraph: Current depsgraph
- * \param scene: Current scene
- * \param ob: Grease pencil object
- */
void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bGPdata *gpd_eval = (bGPdata *)ob->data;
@@ -808,12 +735,6 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o
BKE_gpencil_update_orig_pointers(ob_orig, ob);
}
-/**
- * Calculate gpencil modifiers.
- * \param depsgraph: Current depsgraph
- * \param scene: Current scene
- * \param ob: Grease pencil object
- */
void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -829,7 +750,7 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
}
/* Init general modifiers data. */
- BKE_gpencil_lattice_init(ob);
+ BKE_gpencil_cache_data_init(depsgraph, ob);
const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
bool is_first_lineart = true;
@@ -872,8 +793,8 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
}
}
- /* Clear any lattice data. */
- BKE_gpencil_lattice_clear(ob);
+ /* Clear any cache data. */
+ BKE_gpencil_cache_data_clear(ob);
MOD_lineart_clear_cache(&gpd->runtime.lineart_cache);
}
@@ -1031,6 +952,10 @@ void BKE_gpencil_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
gpmd->segments[i].dmd = gpmd;
}
}
+ if (md->type == eGpencilModifierType_Shrinkwrap) {
+ ShrinkwrapGpencilModifierData *gpmd = (ShrinkwrapGpencilModifierData *)md;
+ gpmd->cache_data = NULL;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index 7433ee7ac29..f2a5146422e 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -80,7 +80,7 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
{
Hair *hair_dst = (Hair *)id_dst;
const Hair *hair_src = (const Hair *)id_src;
- hair_dst->mat = MEM_dupallocN(hair_dst->mat);
+ hair_dst->mat = MEM_dupallocN(hair_src->mat);
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint);
@@ -182,6 +182,7 @@ IDTypeInfo IDType_ID_HA = {
.name_plural = "hairs",
.translation_context = BLT_I18NCONTEXT_ID_HAIR,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = hair_init_data,
.copy_data = hair_copy_data,
@@ -189,6 +190,7 @@ IDTypeInfo IDType_ID_HA = {
.make_local = NULL,
.foreach_id = hair_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = hair_blend_write,
@@ -406,6 +408,7 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje
}
/* Draw Cache */
+
void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = NULL;
void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = NULL;
diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc
index ffc39028400..059caaa27f9 100644
--- a/source/blender/blenkernel/intern/icons.cc
+++ b/source/blender/blenkernel/intern/icons.cc
@@ -210,7 +210,7 @@ void BKE_icons_init(int first_dyn_id)
}
}
-void BKE_icons_free(void)
+void BKE_icons_free()
{
BLI_assert(BLI_thread_is_main());
@@ -227,7 +227,7 @@ void BKE_icons_free(void)
BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
}
-void BKE_icons_deferred_free(void)
+void BKE_icons_deferred_free()
{
std::scoped_lock lock(gIconMutex);
@@ -251,7 +251,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
}
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- prv_img->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
}
return prv_img;
@@ -271,7 +271,7 @@ static PreviewImage *previewimg_deferred_create(const char *path, int source)
return prv;
}
-PreviewImage *BKE_previewimg_create(void)
+PreviewImage *BKE_previewimg_create()
{
return previewimg_create_ex(0);
}
@@ -308,7 +308,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
GPU_texture_free(prv->gputexture[size]);
}
prv->h[size] = prv->w[size] = 0;
- prv->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv->flag[size] |= PRV_CHANGED;
prv->flag[size] &= ~PRV_USER_EDITED;
prv->changed_timestamp[size] = 0;
}
@@ -336,10 +336,6 @@ PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
return prv_img;
}
-/**
- * Duplicate preview image from \a id and clear icon_id,
- * to be used by datablock copy functions.
- */
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
{
PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
@@ -360,31 +356,23 @@ void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
PreviewImage **BKE_previewimg_id_get_p(const ID *id)
{
switch (GS(id->name)) {
- case ID_OB: {
- Object *ob = (Object *)id;
- /* Currently, only object types with real geometry can be rendered as preview. */
- if (!OB_TYPE_IS_GEOMETRY(ob->type)) {
- return nullptr;
- }
- return &ob->preview;
- }
-
#define ID_PRV_CASE(id_code, id_struct) \
case id_code: { \
return &((id_struct *)id)->preview; \
} \
((void)0)
- ID_PRV_CASE(ID_MA, Material);
- ID_PRV_CASE(ID_TE, Tex);
- ID_PRV_CASE(ID_WO, World);
- ID_PRV_CASE(ID_LA, Light);
- ID_PRV_CASE(ID_IM, Image);
- ID_PRV_CASE(ID_BR, Brush);
- ID_PRV_CASE(ID_GR, Collection);
- ID_PRV_CASE(ID_SCE, Scene);
- ID_PRV_CASE(ID_SCR, bScreen);
- ID_PRV_CASE(ID_AC, bAction);
- ID_PRV_CASE(ID_NT, bNodeTree);
+ ID_PRV_CASE(ID_OB, Object);
+ ID_PRV_CASE(ID_MA, Material);
+ ID_PRV_CASE(ID_TE, Tex);
+ ID_PRV_CASE(ID_WO, World);
+ ID_PRV_CASE(ID_LA, Light);
+ ID_PRV_CASE(ID_IM, Image);
+ ID_PRV_CASE(ID_BR, Brush);
+ ID_PRV_CASE(ID_GR, Collection);
+ ID_PRV_CASE(ID_SCE, Scene);
+ ID_PRV_CASE(ID_SCR, bScreen);
+ ID_PRV_CASE(ID_AC, bAction);
+ ID_PRV_CASE(ID_NT, bNodeTree);
#undef ID_PRV_CASE
default:
break;
@@ -468,9 +456,6 @@ PreviewImage *BKE_previewimg_cached_get(const char *name)
return (PreviewImage *)BLI_ghash_lookup(gCachedPreviews, name);
}
-/**
- * Generate an empty PreviewImage, if not yet existing.
- */
PreviewImage *BKE_previewimg_cached_ensure(const char *name)
{
BLI_assert(BLI_thread_is_main());
@@ -488,10 +473,6 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name)
return prv;
}
-/**
- * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
- * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that.
- */
PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
const int source,
@@ -546,10 +527,6 @@ void BKE_previewimg_cached_release(const char *name)
BKE_previewimg_deferred_release(prv);
}
-/**
- * Handle deferred (lazy) loading/generation of preview image, if needed.
- * For now, only used with file thumbnails.
- */
void BKE_previewimg_ensure(PreviewImage *prv, const int size)
{
if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
@@ -573,7 +550,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
prv->w[ICON_SIZE_PREVIEW] = thumb->x;
prv->h[ICON_SIZE_PREVIEW] = thumb->y;
prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_RENDERING);
}
if (do_icon) {
if (thumb->x > thumb->y) {
@@ -592,7 +569,7 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
prv->w[ICON_SIZE_ICON] = icon_w;
prv->h[ICON_SIZE_ICON] = icon_h;
prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_RENDERING);
}
IMB_freeImBuf(thumb);
}
@@ -600,10 +577,6 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
}
}
-/**
- * Create an #ImBuf holding a copy of the preview image buffer in \a prv.
- * \note The returned image buffer has to be free'd (#IMB_freeImBuf()).
- */
ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
{
const unsigned int w = prv->w[size];
@@ -624,12 +597,12 @@ ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
void BKE_previewimg_finish(PreviewImage *prv, const int size)
{
/* Previews may be calculated on a thread. */
- atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_UNFINISHED);
+ atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_RENDERING);
}
bool BKE_previewimg_is_finished(const PreviewImage *prv, const int size)
{
- return (prv->flag[size] & PRV_UNFINISHED) == 0;
+ return (prv->flag[size] & PRV_RENDERING) == 0;
}
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
@@ -663,16 +636,11 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
BLO_read_data_address(reader, &prv->rect[i]);
}
prv->gputexture[i] = nullptr;
- /* For now consider previews read from file as finished to not confuse File Browser preview
- * loading. That could be smarter and check if there's a preview job running instead.
- * If the preview is tagged as changed, it needs to be updated anyway, so don't remove the tag.
- */
- if ((prv->flag[i] & PRV_CHANGED) == 0) {
- BKE_previewimg_finish(prv, i);
- }
- else {
- /* Only for old files that didn't write the flag. */
- prv->flag[i] |= PRV_UNFINISHED;
+
+ /* PRV_RENDERING is a runtime only flag currently, but don't mess with it on undo! It gets
+ * special handling in #memfile_undosys_restart_unfinished_id_previews() then. */
+ if (!BLO_read_data_is_undo(reader)) {
+ prv->flag[i] &= ~PRV_RENDERING;
}
}
prv->icon_id = 0;
@@ -702,7 +670,7 @@ void BKE_icon_changed(const int icon_id)
/* If we have previews, they all are now invalid changed. */
if (p_prv && *p_prv) {
for (int i = 0; i < NUM_ICON_SIZES; i++) {
- (*p_prv)->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED);
+ (*p_prv)->flag[i] |= PRV_CHANGED;
(*p_prv)->changed_timestamp[i]++;
}
}
@@ -809,9 +777,6 @@ int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
return icon_gplayer_color_ensure_create_icon(gpl);
}
-/**
- * Return icon id of given preview, or create new icon if not found.
- */
int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
if (!preview || G.background) {
@@ -852,11 +817,6 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return preview->icon_id;
}
-/**
- * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf, it needs to be stored
- * separately.
- * \note Transforms ownership of \a ibuf to the newly created icon.
- */
int BKE_icon_imbuf_create(ImBuf *ibuf)
{
int icon_id = get_next_free_id();
@@ -938,9 +898,6 @@ void BKE_icon_id_delete(struct ID *id)
BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), nullptr, icon_free);
}
-/**
- * Remove icon and free data.
- */
bool BKE_icon_delete(const int icon_id)
{
if (icon_id == 0) {
@@ -1065,4 +1022,5 @@ int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
icon->id_type = id_type;
return icon_id;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index f7411f541b7..bb6458331da 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -76,10 +76,6 @@ static size_t idp_size_table[] = {
/* --------- property array type -------------*/
-/**
- * \note as a start to move away from the stupid IDP_New function, this type
- * has its own allocation function.
- */
IDProperty *IDP_NewIDPArray(const char *name)
{
IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
@@ -127,7 +123,6 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
}
}
-/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
BLI_assert(prop->type == IDP_IDPARRAY);
@@ -229,7 +224,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
}
}
-/* This function works for strings too! */
void IDP_ResizeArray(IDProperty *prop, int newlen)
{
const bool is_grow = newlen >= prop->len;
@@ -351,19 +345,13 @@ static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
return newp;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Functions (IDProperty String API)
* \{ */
-/**
- *
- * \param st: The string to assign.
- * \param name: The property name.
- * \param maxlen: The size of the new string (including the \0 terminator).
- * \return The new string property.
- */
IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
{
IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
@@ -457,6 +445,7 @@ void IDP_FreeString(IDProperty *prop)
MEM_freeN(prop->data.pointer);
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -514,8 +503,6 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
return newp;
}
-/* use for syncing proxies.
- * When values name and types match, copy the values, else ignore */
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
{
BLI_assert(dest->type == IDP_GROUP);
@@ -565,9 +552,6 @@ void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_a
}
}
-/**
- * Replaces all properties with the same name in a destination group from a source group.
- */
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
{
BLI_assert(dest->type == IDP_GROUP);
@@ -592,10 +576,6 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
}
}
-/**
- * Checks if a property with the same name as prop exists, and if so replaces it.
- * Use this to preserve order!
- */
void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
{
BLI_assert(group->type == IDP_GROUP);
@@ -618,10 +598,6 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
IDP_ReplaceInGroup_ex(group, prop, prop_exist);
}
-/**
- * If a property is missing in \a dest, add it.
- * Do it recursively.
- */
void IDP_MergeGroup_ex(IDProperty *dest,
const IDProperty *src,
const bool do_overwrite,
@@ -663,25 +639,11 @@ void IDP_MergeGroup_ex(IDProperty *dest,
}
}
-/**
- * If a property is missing in \a dest, add it.
- * Do it recursively.
- */
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
{
IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
}
-/**
- * This function has a sanity check to make sure ID properties with the same name don't
- * get added to the group.
- *
- * The sanity check just means the property is not added to the group if another property
- * exists with the same name; the client code using ID properties then needs to detect this
- * (the function that adds new properties to groups, #IDP_AddToGroup,
- * returns false if a property can't be added to the group, and true if it can)
- * and free the property.
- */
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
{
BLI_assert(group->type == IDP_GROUP);
@@ -695,10 +657,6 @@ bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
return false;
}
-/**
- * This is the same as IDP_AddToGroup, only you pass an item
- * in the group list to be inserted after.
- */
bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
{
BLI_assert(group->type == IDP_GROUP);
@@ -712,12 +670,6 @@ bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew
return false;
}
-/**
- * \note this does not free the property!!
- *
- * To free the property, you have to do:
- * IDP_FreeProperty(prop);
- */
void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
{
BLI_assert(group->type == IDP_GROUP);
@@ -727,9 +679,6 @@ void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
BLI_remlink(&group->data.group, prop);
}
-/**
- * Removes the property from the group and frees it.
- */
void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
{
IDP_RemoveFromGroup(group, prop);
@@ -742,7 +691,6 @@ IDProperty *IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name)
return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
}
-/** same as above but ensure type match */
IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *name, const char type)
{
IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
@@ -762,16 +710,13 @@ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
}
BLI_freelistN(&prop->data.group);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Main Functions (IDProperty Main API)
* \{ */
-/**
- * Return an int from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
int IDP_coerce_to_int_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -786,10 +731,6 @@ int IDP_coerce_to_int_or_zero(const IDProperty *prop)
}
}
-/**
- * Return a double from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
double IDP_coerce_to_double_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -804,10 +745,6 @@ double IDP_coerce_to_double_or_zero(const IDProperty *prop)
}
}
-/**
- * Return a float from an IDProperty with a compatible type. This should be avoided, but
- * it's sometimes necessary, for example when legacy files have incorrect property types.
- */
float IDP_coerce_to_float_or_zero(const IDProperty *prop)
{
switch (prop->type) {
@@ -845,10 +782,6 @@ IDProperty *IDP_CopyProperty(const IDProperty *prop)
return IDP_CopyProperty_ex(prop, 0);
}
-/**
- * Copy content from source IDProperty into destination one, freeing destination property's content
- * first.
- */
void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src)
{
IDProperty *idprop_tmp = IDP_CopyProperty(src);
@@ -858,11 +791,6 @@ void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src)
IDP_FreeProperty(idprop_tmp);
}
-/**
- * Get the Group property that contains the id properties for ID id. Set create_if_needed
- * to create the Group property and attach it to id if it doesn't exist; otherwise
- * the function will return NULL if there's no Group property attached to the ID.
- */
IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
{
if (id->properties) {
@@ -880,8 +808,6 @@ IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
return id->properties;
}
-/**
- * \param is_strict: When false treat missing items as a match */
bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict)
{
if (prop1 == NULL && prop2 == NULL) {
@@ -974,33 +900,6 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
return IDP_EqualsProperties_ex(prop1, prop2, true);
}
-/**
- * Allocate a new ID.
- *
- * This function takes three arguments: the ID property type, a union which defines
- * its initial value, and a name.
- *
- * The union is simple to use; see the top of BKE_idprop.h for its definition.
- * An example of using this function:
- *
- * \code{.c}
- * IDPropertyTemplate val;
- * IDProperty *group, *idgroup, *color;
- * group = IDP_New(IDP_GROUP, val, "group1"); // groups don't need a template.
- *
- * val.array.len = 4
- * val.array.type = IDP_FLOAT;
- * color = IDP_New(IDP_ARRAY, val, "color1");
- *
- * idgroup = IDP_GetProperties(some_id, 1);
- * IDP_AddToGroup(idgroup, color);
- * IDP_AddToGroup(idgroup, group);
- * \endcode
- *
- * Note that you MUST either attach the id property to an id property group with
- * IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
- * a memory leak.
- */
IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name)
{
IDProperty *prop = NULL;
@@ -1096,11 +995,6 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
return prop;
}
-/**
- * Free allocated pointers in the UI data that isn't shared with the UI data in the #other
- * argument. Useful for returning early on failure when updating UI data in place, or when
- * replacing a subset of the UI data's allocated pointers.
- */
void IDP_ui_data_free_unique_contents(IDPropertyUIData *ui_data,
const eIDPropertyUIDataType type,
const IDPropertyUIData *other)
@@ -1175,10 +1069,6 @@ void IDP_ui_data_free(IDProperty *prop)
prop->ui_data = NULL;
}
-/**
- * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs!
- * But it does not free the actual IDProperty struct itself.
- */
void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user)
{
switch (prop->type) {
@@ -1241,14 +1131,6 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference)
}
}
-/**
- * Loop through all ID properties in hierarchy of given \a id_property_root included.
- *
- * \note Container types (groups and arrays) are processed after applying the callback on them.
- *
- * \param type_filter: If not 0, only apply callback on properties of matching types, see
- * IDP_TYPE_FILTER_ enum in DNA_ID.h.
- */
void IDP_foreach_property(IDProperty *id_property_root,
const int type_filter,
IDPForeachPropertyCallback callback,
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index d9dc68b1a4f..e6fd6c14d42 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -158,13 +158,6 @@ static const IDTypeInfo *idtype_get_info_from_name(const char *idtype_name)
/* Various helpers/wrappers around #IDTypeInfo structure. */
-/**
- * Convert an \a idcode into a name.
- *
- * \param idcode: The code to convert.
- * \return A static string representing the name of
- * the code.
- */
const char *BKE_idtype_idcode_to_name(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -172,13 +165,6 @@ const char *BKE_idtype_idcode_to_name(const short idcode)
return id_type != NULL ? id_type->name : NULL;
}
-/**
- * Convert an \a idcode into a name (plural).
- *
- * \param idcode: The code to convert.
- * \return A static string representing the name of
- * the code.
- */
const char *BKE_idtype_idcode_to_name_plural(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -186,12 +172,6 @@ const char *BKE_idtype_idcode_to_name_plural(const short idcode)
return id_type != NULL ? id_type->name_plural : NULL;
}
-/**
- * Convert an \a idcode into its translations' context.
- *
- * \param idcode: The code to convert.
- * \return A static string representing the i18n context of the code.
- */
const char *BKE_idtype_idcode_to_translation_context(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -199,12 +179,6 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode)
return id_type != NULL ? id_type->translation_context : BLT_I18NCONTEXT_DEFAULT;
}
-/**
- * Convert an ID-type name into an \a idcode (ie. #ID_SCE)
- *
- * \param idtype_name: The ID-type's "user visible name" to convert.
- * \return The \a idcode for the name, or 0 if invalid.
- */
short BKE_idtype_idcode_from_name(const char *idtype_name)
{
const IDTypeInfo *id_type = idtype_get_info_from_name(idtype_name);
@@ -212,23 +186,11 @@ short BKE_idtype_idcode_from_name(const char *idtype_name)
return id_type != NULL ? id_type->id_code : 0;
}
-/**
- * Return if the ID code is a valid ID code.
- *
- * \param idcode: The code to check.
- * \return Boolean, 0 when invalid.
- */
bool BKE_idtype_idcode_is_valid(const short idcode)
{
return BKE_idtype_get_info_from_idcode(idcode) != NULL ? true : false;
}
-/**
- * Check if an ID type is linkable.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when non linkable, true otherwise.
- */
bool BKE_idtype_idcode_is_linkable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -236,12 +198,6 @@ bool BKE_idtype_idcode_is_linkable(const short idcode)
return id_type != NULL ? (id_type->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0 : false;
}
-/**
- * Check if an ID type is only appendable.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when also linkable, true when only appendable.
- */
bool BKE_idtype_idcode_is_only_appendable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -254,12 +210,6 @@ bool BKE_idtype_idcode_is_only_appendable(const short idcode)
return false;
}
-/**
- * Check if an ID type can try to reuse and existing matching local one when being appended again.
- *
- * \param idcode: The IDType code to check.
- * \return Boolean, false when it cannot be re-used, true otherwise.
- */
bool BKE_idtype_idcode_append_is_reusable(const short idcode)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(idcode);
@@ -272,9 +222,6 @@ bool BKE_idtype_idcode_append_is_reusable(const short idcode)
return false;
}
-/**
- * Convert an \a idcode into an \a idfilter (e.g. ID_OB -> FILTER_ID_OB).
- */
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
{
#define CASE_IDFILTER(_id) \
@@ -324,9 +271,6 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
#undef CASE_IDFILTER
}
-/**
- * Convert an \a idfilter into an \a idcode (e.g. #FILTER_ID_OB -> #ID_OB).
- */
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
{
#define CASE_IDFILTER(_id) \
@@ -375,9 +319,6 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
#undef CASE_IDFILTER
}
-/**
- * Convert an \a idcode into an index (e.g. #ID_OB -> #INDEX_ID_OB).
- */
int BKE_idtype_idcode_to_index(const short idcode)
{
#define CASE_IDINDEX(_id) \
@@ -437,9 +378,6 @@ int BKE_idtype_idcode_to_index(const short idcode)
#undef CASE_IDINDEX
}
-/**
- * Get an \a idcode from an index (e.g. #INDEX_ID_OB -> #ID_OB).
- */
short BKE_idtype_idcode_from_index(const int index)
{
#define CASE_IDCODE(_id) \
@@ -499,20 +437,11 @@ short BKE_idtype_idcode_from_index(const int index)
#undef CASE_IDCODE
}
-/**
- * Return an ID code and steps the index forward 1.
- *
- * \param index: start as 0.
- * \return the code, 0 when all codes have been returned.
- */
short BKE_idtype_idcode_iter_step(int *index)
{
return (*index < ARRAY_SIZE(id_types)) ? BKE_idtype_idcode_from_index((*index)++) : 0;
}
-/**
- * Wrapper around #IDTypeInfo foreach_cache that also handles embedded IDs.
- */
void BKE_idtype_id_foreach_cache(struct ID *id,
IDTypeForeachCacheFunctionCallback function_callback,
void *user_data)
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index c0efc246567..f43cf00a310 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -75,6 +75,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -252,6 +253,34 @@ static void image_foreach_cache(ID *id,
}
}
+static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Image *ima = (Image *)id;
+ const eBPathForeachFlag flag = bpath_data->flag;
+
+ if (BKE_image_has_packedfile(ima) && (flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+ /* Skip empty file paths, these are typically from generated images and
+ * don't make sense to add directories to until the image has been saved
+ * once to give it a meaningful value. */
+ /* TODO re-assess whether this behavior is desired in the new generic code context. */
+ if (!ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) ||
+ ima->filepath[0] == '\0') {
+ return;
+ }
+
+ if (BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath)) {
+ if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) {
+ if (!BKE_image_has_packedfile(ima) &&
+ /* Image may have been painted onto (and not saved, T44543). */
+ !BKE_image_is_dirty(ima)) {
+ BKE_image_signal(bpath_data->bmain, ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+ }
+ }
+}
+
static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Image *ima = (Image *)id;
@@ -369,6 +398,7 @@ IDTypeInfo IDType_ID_IM = {
.name_plural = "images",
.translation_context = BLT_I18NCONTEXT_ID_IMAGE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = image_init_data,
.copy_data = image_copy_data,
@@ -376,6 +406,7 @@ IDTypeInfo IDType_ID_IM = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = image_foreach_cache,
+ .foreach_path = image_foreach_path,
.owner_get = NULL,
.blend_write = image_blend_write,
@@ -518,10 +549,6 @@ static void image_free_anims(Image *ima)
}
}
-/**
- * Simply free the image data from memory,
- * on display the image can load again (except for render buffers).
- */
void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
{
if (do_lock) {
@@ -548,7 +575,6 @@ void BKE_image_free_buffers(Image *ima)
BKE_image_free_buffers_ex(ima, false);
}
-/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free_data(Image *ima)
{
image_free_data(&ima->id);
@@ -675,9 +701,11 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source)
}
}
-/* NOTE: We could be clever and scale all imbuf's but since some are mipmaps its not so simple. */
bool BKE_image_scale(Image *image, int width, int height)
{
+ /* NOTE: We could be clever and scale all imbuf's
+ * but since some are mipmaps its not so simple. */
+
ImBuf *ibuf;
void *lock;
@@ -776,9 +804,6 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
return tile_number;
}
-/**
- * Return the tile_number for the closest UDIM tile.
- */
int BKE_image_find_nearest_tile(const Image *image, const float co[2])
{
const float co_floor[2] = {floorf(co[0]), floorf(co[1])};
@@ -877,17 +902,13 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
return ima;
}
-/* checks if image was already loaded, then returns same image */
-/* otherwise creates new. */
-/* does not load ibuf itself */
-/* pass on optional frame for #name images */
Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
{
Image *ima;
char str[FILE_MAX], strtest[FILE_MAX];
STRNCPY(str, filepath);
- BLI_path_abs(str, bmain->name);
+ BLI_path_abs(str, bmain->filepath);
/* first search an identical filepath */
for (ima = bmain->images.first; ima; ima = ima->id.next) {
@@ -1027,7 +1048,6 @@ static ImBuf *add_ibuf_size(unsigned int width,
return ibuf;
}
-/* adds new image block, creates ImBuf and initializes color */
Image *BKE_image_add_generated(Main *bmain,
unsigned int width,
unsigned int height,
@@ -1088,11 +1108,6 @@ Image *BKE_image_add_generated(Main *bmain,
return ima;
}
-/**
- * Create an image from ibuf. The refcount of ibuf is increased,
- * caller should take care to drop its reference by calling
- * #IMB_freeImBuf if needed.
- */
Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
{
/* on save, type is changed to FILE in editsima.c */
@@ -1144,7 +1159,6 @@ static bool image_memorypack_imbuf(Image *ima, ImBuf *ibuf, const char *filepath
return true;
}
-/* Pack image to memory. */
bool BKE_image_memorypack(Image *ima)
{
bool ok = true;
@@ -1377,7 +1391,6 @@ static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void
(except_frame != IMA_INDEX_ENTRY(ibuf->index));
}
-/* except_frame is weak, only works for seqs without offset... */
void BKE_image_free_anim_ibufs(Image *ima, int except_frame)
{
BLI_mutex_lock(ima->runtime.cache_mutex);
@@ -1639,8 +1652,6 @@ char BKE_imtype_valid_depths(const char imtype)
}
}
-/* string is from command line --render-format arg, keep in sync with
- * creator_args.c help info */
char BKE_imtype_from_arg(const char *imtype_arg)
{
if (STREQ(imtype_arg, "TGA")) {
@@ -2051,9 +2062,10 @@ static void stampdata(
time_t t;
if (scene->r.stamp & R_STAMP_FILENAME) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
SNPRINTF(stamp_data->file,
do_prefix ? "File %s" : "%s",
- G.relbase_valid ? BKE_main_blendfile_path_from_global() : "<untitled>");
+ (blendfile_path[0] != '\0') ? blendfile_path : "<untitled>");
}
else {
stamp_data->file[0] = '\0';
@@ -2744,8 +2756,6 @@ static const char *stamp_metadata_fields[] = {
NULL,
};
-/* Check whether the given metadata field name translates to a known field of
- * a stamp. */
bool BKE_stamp_is_known_field(const char *field_name)
{
int i = 0;
@@ -2907,8 +2917,6 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf)
return false;
}
-/* NOTE: imf->planes is ignored here, its assumed the image channels
- * are already set */
void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
{
char imtype = imf->imtype;
@@ -3085,8 +3093,6 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, const ImageFormatData *imf)
return ok;
}
-/* same as BKE_imbuf_write() but crappy workaround not to permanently modify
- * _some_, values in the imbuf */
int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, const bool save_copy)
{
ImBuf ibuf_back = *ibuf;
@@ -3185,7 +3191,6 @@ struct anim *openanim_noload(const char *name,
return anim;
}
-/* used by sequencer too */
struct anim *openanim(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
{
struct anim *anim;
@@ -3231,8 +3236,6 @@ struct anim *openanim(const char *name, int flags, int streamindex, char colorsp
* -> comes from packedfile or filename or generated
*/
-/* forces existence of 1 Image for renderout or nodes, returns Image */
-/* name is only for default, when making new one */
Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
{
Image *ima;
@@ -3273,7 +3276,6 @@ static void image_viewer_create_views(const RenderData *rd, Image *ima)
}
}
-/* Reset the image cache and views when the Viewer Nodes views don't match the scene views */
void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
{
bool do_reset;
@@ -3928,7 +3930,6 @@ bool BKE_image_fill_tile(struct Image *ima,
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
-/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
{
RenderLayer *rl;
@@ -3983,7 +3984,6 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
-/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
bool BKE_image_is_multilayer(Image *ima)
{
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
@@ -4233,13 +4233,16 @@ static int image_num_files(Image *ima)
return BLI_listbase_count(&ima->views);
}
-static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const int view_id)
+static ImBuf *load_sequence_single(
+ Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_cache_ibuf)
{
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
ImageUser iuser_t = {0};
+ *r_cache_ibuf = true;
+
ima->lastframe = frame;
if (iuser) {
@@ -4279,6 +4282,9 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
ima->type = IMA_TYPE_MULTILAYER;
IMB_freeImBuf(ibuf);
ibuf = NULL;
+ /* NULL ibuf in the cache means the image failed to load. However for multilayer we load
+ * pixels into RenderResult instead and intentionally leave ibuf NULL. */
+ *r_cache_ibuf = false;
}
}
else {
@@ -4299,17 +4305,21 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
const int totfiles = image_num_files(ima);
if (!is_multiview) {
- ibuf = load_sequence_single(ima, iuser, frame, 0);
- image_assign_ibuf(ima, ibuf, 0, entry);
+ bool put_in_cache;
+ ibuf = load_sequence_single(ima, iuser, frame, 0, &put_in_cache);
+ if (put_in_cache) {
+ image_assign_ibuf(ima, ibuf, 0, entry);
+ }
}
else {
const int totviews = BLI_listbase_count(&ima->views);
struct ImBuf **ibuf_arr;
ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+ bool *cache_ibuf_arr = MEM_mallocN(sizeof(bool) * totviews, "Image View Put In Cache");
for (int i = 0; i < totfiles; i++) {
- ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i);
+ ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, cache_ibuf_arr + i);
}
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) {
@@ -4320,7 +4330,9 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
for (int i = 0; i < totviews; i++) {
- image_assign_ibuf(ima, ibuf_arr[i], i, entry);
+ if (cache_ibuf_arr[i]) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, entry);
+ }
}
/* "remove" the others (decrease their refcount) */
@@ -4332,6 +4344,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int entry,
/* cleanup */
MEM_freeN(ibuf_arr);
+ MEM_freeN(cache_ibuf_arr);
}
return ibuf;
@@ -4493,13 +4506,19 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
return ibuf;
}
-static ImBuf *load_image_single(
- Image *ima, ImageUser *iuser, int cfra, const int view_id, const bool has_packed)
+static ImBuf *load_image_single(Image *ima,
+ ImageUser *iuser,
+ int cfra,
+ const int view_id,
+ const bool has_packed,
+ bool *r_cache_ibuf)
{
char filepath[FILE_MAX];
struct ImBuf *ibuf = NULL;
int flag;
+ *r_cache_ibuf = true;
+
/* is there a PackedFile with this image ? */
if (has_packed) {
ImagePackedFile *imapf;
@@ -4550,6 +4569,9 @@ static ImBuf *load_image_single(
ima->type = IMA_TYPE_MULTILAYER;
IMB_freeImBuf(ibuf);
ibuf = NULL;
+ /* NULL ibuf in the cache means the image failed to load. However for multilayer we load
+ * pixels into RenderResult instead and intentionally leave ibuf NULL. */
+ *r_cache_ibuf = false;
}
}
else
@@ -4594,8 +4616,11 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
}
if (!is_multiview) {
- ibuf = load_image_single(ima, iuser, cfra, 0, has_packed);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ bool put_in_cache;
+ ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &put_in_cache);
+ if (put_in_cache) {
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ }
}
else {
struct ImBuf **ibuf_arr;
@@ -4603,9 +4628,10 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
BLI_assert(totviews > 0);
ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+ bool *cache_ibuf_arr = MEM_mallocN(sizeof(bool) * totviews, "Image Views Put In Cache");
for (int i = 0; i < totfiles; i++) {
- ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed);
+ ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, cache_ibuf_arr + i);
}
/* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */
@@ -4619,7 +4645,9 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
ibuf = ibuf_arr[i];
for (i = 0; i < totviews; i++) {
- image_assign_ibuf(ima, ibuf_arr[i], i, 0);
+ if (cache_ibuf_arr[i]) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, 0);
+ }
}
/* "remove" the others (decrease their refcount) */
@@ -4631,6 +4659,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
/* cleanup */
MEM_freeN(ibuf_arr);
+ MEM_freeN(cache_ibuf_arr);
}
return ibuf;
@@ -4986,9 +5015,10 @@ BLI_INLINE bool image_quick_test(Image *ima, const ImageUser *iuser)
return true;
}
-/* Checks optional ImageUser and verifies/creates ImBuf.
+/**
+ * Checks optional #ImageUser and verifies/creates #ImBuf.
*
- * not thread-safe, so callee should worry about thread locks
+ * \warning Not thread-safe, so callee should worry about thread locks.
*/
static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
@@ -5109,15 +5139,15 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
return ibuf;
}
-/* return image buffer for given image and user
- *
- * - will lock render result if image type is render result and lock is not NULL
- * - will return NULL if image type if render or composite result and lock is NULL
- *
- * references the result, BKE_image_release_ibuf should be used to de-reference
- */
ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
+ /* NOTE: same as #image_acquire_ibuf, but can be used to retrieve images being rendered in
+ * a thread safe way, always call both acquire and release. */
+
+ if (ima == NULL) {
+ return NULL;
+ }
+
ImBuf *ibuf;
BLI_mutex_lock(ima->runtime.cache_mutex);
@@ -5149,7 +5179,6 @@ void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
}
}
-/* checks whether there's an image buffer for given image and user */
bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
{
ImBuf *ibuf;
@@ -5657,19 +5686,16 @@ bool BKE_image_has_filepath(Image *ima)
return ima->filepath[0] != '\0';
}
-/* Checks the image buffer changes with time (not keyframed values). */
bool BKE_image_is_animated(Image *image)
{
return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
}
-/* Checks whether the image consists of multiple buffers. */
bool BKE_image_has_multiple_ibufs(Image *image)
{
return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED);
}
-/* Image modifications */
bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
{
bool is_dirty = false;
@@ -5745,8 +5771,12 @@ bool BKE_image_has_loaded_ibuf(Image *image)
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
while (!IMB_moviecacheIter_done(iter)) {
- has_loaded_ibuf = true;
- break;
+ ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+ if (ibuf != NULL) {
+ has_loaded_ibuf = true;
+ break;
+ }
+ IMB_moviecacheIter_step(iter);
}
IMB_moviecacheIter_free(iter);
}
@@ -5755,10 +5785,6 @@ bool BKE_image_has_loaded_ibuf(Image *image)
return has_loaded_ibuf;
}
-/**
- * References the result, #BKE_image_release_ibuf is to be called to de-reference.
- * Use lock=NULL when calling #BKE_image_release_ibuf().
- */
ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
{
ImBuf *ibuf = NULL;
@@ -5783,15 +5809,6 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
return ibuf;
}
-/**
- * References the result, #BKE_image_release_ibuf is to be called to de-reference.
- * Use lock=NULL when calling #BKE_image_release_ibuf().
- *
- * TODO(sergey): This is actually "get first item from the cache", which is
- * not so much predictable. But using first loaded image buffer
- * was also malicious logic and all the areas which uses this
- * function are to be re-considered.
- */
ImBuf *BKE_image_get_first_ibuf(Image *image)
{
ImBuf *ibuf = NULL;
diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.cc
index 330af1cc505..4440e4b101a 100644
--- a/source/blender/blenkernel/intern/image_gpu.c
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -47,7 +47,7 @@
#include "PIL_time.h"
/* Prototypes. */
-static void gpu_free_unused_buffers(void);
+static void gpu_free_unused_buffers();
static void image_free_gpu(Image *ima, const bool immediate);
static void image_free_gpu_limited_scale(Image *ima);
static void image_update_gputexture_ex(
@@ -55,13 +55,12 @@ static void image_update_gputexture_ex(
/* Internal structs. */
#define IMA_PARTIAL_REFRESH_TILE_SIZE 256
-typedef struct ImagePartialRefresh {
+struct ImagePartialRefresh {
struct ImagePartialRefresh *next, *prev;
int tile_x;
int tile_y;
-} ImagePartialRefresh;
+};
-/* Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied. */
bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
{
if (image) {
@@ -71,7 +70,7 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
}
/* Generated images use pre multiplied float buffer, but straight alpha for byte buffers. */
if (image->type == IMA_TYPE_UV_TEST && ibuf) {
- return ibuf->rect_float != NULL;
+ return ibuf->rect_float != nullptr;
}
}
if (ibuf) {
@@ -85,8 +84,9 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf)
}
/* -------------------------------------------------------------------- */
-/** \name UDIM gpu texture
+/** \name UDIM GPU Texture
* \{ */
+
static bool is_over_resolution_limit(int w, int h, bool limit_gl_texture_size)
{
return (w > GPU_texture_size_with_limit(w, limit_gl_texture_size) ||
@@ -104,8 +104,8 @@ static GPUTexture *gpu_texture_create_tile_mapping(
const int resolution = (texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED) ? 1 : 0;
GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye][resolution];
- if (tilearray == NULL) {
- return 0;
+ if (tilearray == nullptr) {
+ return nullptr;
}
float array_w = GPU_texture_width(tilearray);
@@ -142,11 +142,11 @@ static GPUTexture *gpu_texture_create_tile_mapping(
return tex;
}
-typedef struct PackTile {
+struct PackTile {
FixedSizeBoxPack boxpack;
ImageTile *tile;
float pack_score;
-} PackTile;
+};
static int compare_packtile(const void *a, const void *b)
{
@@ -163,13 +163,13 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
const bool limit_gl_texture_size = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED;
const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
int arraywidth = 0, arrayheight = 0;
- ListBase boxes = {NULL};
+ ListBase boxes = {nullptr};
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.tile = tile->tile_number;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
if (ibuf) {
PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__);
@@ -190,7 +190,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
float w = packtile->boxpack.w, h = packtile->boxpack.h;
packtile->pack_score = max_ff(w, h) / min_ff(w, h) * w * h;
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
BLI_addtail(&boxes, packtile);
}
}
@@ -200,10 +200,10 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
BLI_listbase_sort(&boxes, compare_packtile);
int arraylayers = 0;
/* Keep adding layers until all tiles are packed. */
- while (boxes.first != NULL) {
- ListBase packed = {NULL};
+ while (boxes.first != nullptr) {
+ ListBase packed = {nullptr};
BLI_box_pack_2d_fixedarea(&boxes, arraywidth, arrayheight, &packed);
- BLI_assert(packed.first != NULL);
+ BLI_assert(packed.first != nullptr);
LISTBASE_FOREACH (PackTile *, packtile, &packed) {
ImageTile *tile = packtile->tile;
@@ -241,7 +241,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.tile = tile->tile_number;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
if (ibuf) {
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
@@ -254,7 +254,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
store_premultiplied);
}
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
if (GPU_mipmap_enabled()) {
@@ -305,7 +305,7 @@ static GPUTexture **get_image_gpu_texture_ptr(Image *ima,
if (in_range) {
return &(ima->gputexture[textarget][multiview_eye][resolution]);
}
- return NULL;
+ return nullptr;
}
static GPUTexture *image_gpu_texture_error_create(eGPUTextureTarget textarget)
@@ -342,8 +342,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
ImBuf *ibuf,
eGPUTextureTarget textarget)
{
- if (ima == NULL) {
- return NULL;
+ if (ima == nullptr) {
+ return nullptr;
}
/* Free any unused GPU textures, since we know we are in a thread with OpenGL
@@ -373,7 +373,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
/* Check if image has been updated and tagged to be updated (full or partial). */
ImageTile *tile = BKE_image_get_tile(ima, 0);
if (((ima->gpuflag & IMA_GPU_REFRESH) != 0) ||
- ((ibuf == NULL || tile == NULL) && ((ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) != 0))) {
+ ((ibuf == nullptr || tile == nullptr) && ((ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) != 0))) {
image_free_gpu(ima, true);
BLI_freelistN(&ima->gpu_refresh_areas);
ima->gpuflag &= ~(IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH);
@@ -382,7 +382,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
BLI_assert(ibuf);
BLI_assert(tile);
ImagePartialRefresh *refresh_area;
- while ((refresh_area = BLI_pophead(&ima->gpu_refresh_areas))) {
+ while ((
+ refresh_area = static_cast<ImagePartialRefresh *>(BLI_pophead(&ima->gpu_refresh_areas)))) {
const int tile_offset_x = refresh_area->tile_x * IMA_PARTIAL_REFRESH_TILE_SIZE;
const int tile_offset_y = refresh_area->tile_y * IMA_PARTIAL_REFRESH_TILE_SIZE;
const int tile_width = MIN2(IMA_PARTIAL_REFRESH_TILE_SIZE, ibuf->x - tile_offset_x);
@@ -404,7 +405,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
const bool limit_resolution = U.glreslimit != 0 &&
((iuser && (iuser->flag & IMA_SHOW_MAX_RESOLUTION) == 0) ||
- (iuser == NULL)) &&
+ (iuser == nullptr)) &&
((ima->gpuflag & IMA_GPU_REUSE_MAX_RESOLUTION) == 0);
const eImageTextureResolution texture_resolution = limit_resolution ?
IMA_TEXTURE_RESOLUTION_LIMITED :
@@ -416,16 +417,16 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
/* Check if we have a valid image. If not, we return a dummy
* texture with zero bind-code so we don't keep trying. */
- if (tile == NULL) {
+ if (tile == nullptr) {
*tex = image_gpu_texture_error_create(textarget);
return *tex;
}
/* check if we have a valid image buffer */
ImBuf *ibuf_intern = ibuf;
- if (ibuf_intern == NULL) {
- ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf_intern == NULL) {
+ if (ibuf_intern == nullptr) {
+ ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, nullptr);
+ if (ibuf_intern == nullptr) {
*tex = image_gpu_texture_error_create(textarget);
return *tex;
}
@@ -477,8 +478,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
}
/* if `ibuf` was given, we don't own the `ibuf_intern` */
- if (ibuf == NULL) {
- BKE_image_release_ibuf(ima, ibuf_intern, NULL);
+ if (ibuf == nullptr) {
+ BKE_image_release_ibuf(ima, ibuf_intern, nullptr);
}
if (*tex) {
@@ -512,19 +513,19 @@ GPUTexture *BKE_image_get_gpu_tilemap(Image *image, ImageUser *iuser, ImBuf *ibu
* In that case we push them into a queue and free the buffers later.
* \{ */
-static LinkNode *gpu_texture_free_queue = NULL;
+static LinkNode *gpu_texture_free_queue = nullptr;
static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
-static void gpu_free_unused_buffers(void)
+static void gpu_free_unused_buffers()
{
- if (gpu_texture_free_queue == NULL) {
+ if (gpu_texture_free_queue == nullptr) {
return;
}
BLI_mutex_lock(&gpu_texture_queue_mutex);
- while (gpu_texture_free_queue != NULL) {
- GPUTexture *tex = BLI_linklist_pop(&gpu_texture_free_queue);
+ while (gpu_texture_free_queue != nullptr) {
+ GPUTexture *tex = static_cast<GPUTexture *>(BLI_linklist_pop(&gpu_texture_free_queue));
GPU_texture_free(tex);
}
@@ -549,7 +550,7 @@ static void image_free_gpu(Image *ima, const bool immediate)
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
- if (ima->gputexture[i][eye][resolution] != NULL) {
+ if (ima->gputexture[i][eye][resolution] != nullptr) {
if (immediate) {
GPU_texture_free(ima->gputexture[i][eye][resolution]);
}
@@ -559,7 +560,7 @@ static void image_free_gpu(Image *ima, const bool immediate)
BLI_mutex_unlock(&gpu_texture_queue_mutex);
}
- ima->gputexture[i][eye][resolution] = NULL;
+ ima->gputexture[i][eye][resolution] = nullptr;
}
}
}
@@ -573,9 +574,9 @@ static void image_free_gpu_limited_scale(Image *ima)
const eImageTextureResolution resolution = IMA_TEXTURE_RESOLUTION_LIMITED;
for (int eye = 0; eye < 2; eye++) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i][eye][resolution] != NULL) {
+ if (ima->gputexture[i][eye][resolution] != nullptr) {
GPU_texture_free(ima->gputexture[i][eye][resolution]);
- ima->gputexture[i][eye][resolution] = NULL;
+ ima->gputexture[i][eye][resolution] = nullptr;
}
}
}
@@ -597,7 +598,6 @@ void BKE_image_free_all_gputextures(Main *bmain)
}
}
-/* same as above but only free animated images */
void BKE_image_free_anim_gputextures(Main *bmain)
{
if (bmain) {
@@ -644,6 +644,7 @@ void BKE_image_free_old_gputextures(Main *bmain)
}
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -769,7 +770,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
{
const int resolution = texture_resolution == IMA_TEXTURE_RESOLUTION_LIMITED ? 1 : 0;
bool scaled;
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tilesize = tile_runtime->tilearray_size;
scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
@@ -796,14 +797,14 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
int tex_offset = ibuf->channels * (y * ibuf->x + x);
const bool store_premultiplied = BKE_image_has_gpu_texture_premultiplied_alpha(ima, ibuf);
- if (rect_float == NULL) {
+ if (rect_float == nullptr) {
/* Byte pixels. */
if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(
ibuf->rect_colorspace);
rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__);
- if (rect == NULL) {
+ if (rect == nullptr) {
return;
}
@@ -820,7 +821,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
/* Float pixels. */
if (ibuf->channels != 4 || scaled || !store_premultiplied) {
rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
- if (rect_float == NULL) {
+ if (rect_float == nullptr) {
return;
}
@@ -834,7 +835,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
if (scaled) {
/* Slower update where we first have to scale the input pixels. */
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int *tilesize = tile_runtime->tilearray_size;
@@ -844,12 +845,12 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
}
else {
gpu_texture_update_scaled(
- tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, NULL, NULL, w, h);
+ tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, nullptr, nullptr, w, h);
}
}
else {
/* Fast update at same resolution. */
- if (tile != NULL) {
+ if (tile != nullptr) {
ImageTile_RuntimeTextureSlot *tile_runtime = &tile->runtime.slots[resolution];
int *tileoffset = tile_runtime->tilearray_offset;
int tilelayer = tile_runtime->tilearray_layer;
@@ -858,7 +859,7 @@ static void gpu_texture_update_from_ibuf(GPUTexture *tex,
}
else {
gpu_texture_update_unscaled(
- tex, rect, rect_float, x, y, -1, NULL, w, h, tex_stride, tex_offset);
+ tex, rect, rect_float, x, y, -1, nullptr, w, h, tex_stride, tex_offset);
}
}
@@ -886,39 +887,33 @@ static void image_update_gputexture_ex(
const int eye = 0;
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
GPUTexture *tex = ima->gputexture[TEXTARGET_2D][eye][resolution];
- eImageTextureResolution texture_resolution = resolution;
+ eImageTextureResolution texture_resolution = static_cast<eImageTextureResolution>(resolution);
/* Check if we need to update the main gputexture. */
- if (tex != NULL && tile == ima->tiles.first) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h, texture_resolution);
+ if (tex != nullptr && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, nullptr, x, y, w, h, texture_resolution);
}
/* Check if we need to update the array gputexture. */
tex = ima->gputexture[TEXTARGET_2D_ARRAY][eye][resolution];
- if (tex != NULL) {
+ if (tex != nullptr) {
gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h, texture_resolution);
}
}
}
-/* Partial update of texture for texture painting. This is often much
- * quicker than fully updating the texture for high resolution images. */
void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, nullptr);
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
- if ((ibuf == NULL) || (w == 0) || (h == 0)) {
+ if ((ibuf == nullptr) || (w == 0) || (h == 0)) {
/* Full reload of texture. */
BKE_image_free_gputextures(ima);
}
image_update_gputexture_ex(ima, tile, ibuf, x, y, w, h);
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
-/* Mark areas on the GPUTexture that needs to be updated. The areas are marked in chunks.
- * The next time the GPUTexture is used these tiles will be refreshes. This saves time
- * when writing to the same place multiple times This happens for during foreground
- * rendering. */
void BKE_image_update_gputexture_delayed(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h)
{
@@ -946,7 +941,7 @@ void BKE_image_update_gputexture_delayed(
const int num_tiles_y = (end_tile_y + 1) - (start_tile_y);
const int num_tiles = num_tiles_x * num_tiles_y;
const bool allocate_on_heap = BLI_BITMAP_SIZE(num_tiles) > 16;
- BLI_bitmap *requested_tiles = NULL;
+ BLI_bitmap *requested_tiles = nullptr;
if (allocate_on_heap) {
requested_tiles = BLI_BITMAP_NEW(num_tiles, __func__);
}
@@ -976,7 +971,8 @@ void BKE_image_update_gputexture_delayed(
for (int tile_y = start_tile_y; tile_y <= end_tile_y; tile_y++) {
for (int tile_x = start_tile_x; tile_x <= end_tile_x; tile_x++) {
if (!BLI_BITMAP_TEST_BOOL(requested_tiles, tile_index)) {
- ImagePartialRefresh *area = MEM_mallocN(sizeof(ImagePartialRefresh), __func__);
+ ImagePartialRefresh *area = static_cast<ImagePartialRefresh *>(
+ MEM_mallocN(sizeof(ImagePartialRefresh), __func__));
area->tile_x = tile_x;
area->tile_y = tile_y;
BLI_addtail(&ima->gpu_refresh_areas, area);
@@ -991,10 +987,6 @@ void BKE_image_update_gputexture_delayed(
}
}
-/* these two functions are called on entering and exiting texture paint mode,
- * temporary disabling/enabling mipmapping on all images for quick texture
- * updates with glTexSubImage2D. images that didn't change don't have to be
- * re-uploaded to OpenGL */
void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
{
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
@@ -1005,7 +997,7 @@ void BKE_image_paint_set_mipmap(Main *bmain, bool mipmap)
for (int eye = 0; eye < 2; eye++) {
for (int resolution = 0; resolution < IMA_TEXTURE_RESOLUTION_LEN; resolution++) {
GPUTexture *tex = ima->gputexture[a][eye][resolution];
- if (tex != NULL) {
+ if (tex != nullptr) {
GPU_texture_mipmap_mode(tex, mipmap, true);
}
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 26a1240080f..d87331fd65c 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -185,6 +185,7 @@ IDTypeInfo IDType_ID_IP = {
.name_plural = "ipos",
.translation_context = "",
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -192,6 +193,7 @@ IDTypeInfo IDType_ID_IP = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = NULL,
@@ -2093,17 +2095,6 @@ static bool seq_convert_callback(Sequence *seq, void *userdata)
/* *************************************************** */
/* External API - Only Called from do_versions() */
-/* Called from do_versions() in readfile.c to convert the old 'IPO/adrcode' system
- * to the new 'Animato/RNA' system.
- *
- * The basic method used here, is to loop over data-blocks which have IPO-data,
- * and add those IPO's to new AnimData blocks as Actions.
- * Action/NLA data only works well for Objects, so these only need to be checked for there.
- *
- * Data that has been converted should be freed immediately, which means that it is immediately
- * clear which data-blocks have yet to be converted, and also prevent freeing errors when we exit.
- */
-/* XXX currently done after all file reading... */
void do_versions_ipos_to_animato(Main *bmain)
{
ListBase drivers = {NULL, NULL};
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index c09fcf0715e..ff199794ab3 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -213,6 +213,7 @@ IDTypeInfo IDType_ID_KE = {
.name_plural = "shape_keys",
.translation_context = BLT_I18NCONTEXT_ID_SHAPEKEY,
.flags = IDTYPE_FLAGS_NO_LIBLINKING,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = shapekey_copy_data,
@@ -220,6 +221,7 @@ IDTypeInfo IDType_ID_KE = {
.make_local = NULL,
.foreach_id = shapekey_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
/* A bit weird, due to shapekeys not being strictly speaking embedded data... But they also
* share a lot with those (non linkable, only ever used by one owner ID, etc.). */
.owner_get = shapekey_owner_get,
@@ -244,7 +246,6 @@ typedef struct WeightsArrayCache {
float **defgroup_weights;
} WeightsArrayCache;
-/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free_data(Key *key)
{
shapekey_free_data(&key->id);
@@ -314,11 +315,6 @@ Key *BKE_key_add(Main *bmain, ID *id) /* common function */
return key;
}
-/**
- * Sort shape keys after a change.
- * This assumes that at most one key was moved,
- * which is a valid assumption for the places it's currently being called.
- */
void BKE_key_sort(Key *key)
{
KeyBlock *kb;
@@ -392,7 +388,6 @@ void key_curve_position_weights(float t, float data[4], int type)
}
}
-/* first derivative */
void key_curve_tangent_weights(float t, float data[4], int type)
{
float t2, fc;
@@ -431,7 +426,6 @@ void key_curve_tangent_weights(float t, float data[4], int type)
}
}
-/* second derivative */
void key_curve_normal_weights(float t, float data[4], int type)
{
float fc;
@@ -1522,7 +1516,6 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
}
}
-/* returns key coordinates (+ tilt) when key applied, NULL otherwise */
float *BKE_key_evaluate_object_ex(Object *ob, int *r_totelem, float *arr, size_t arr_size)
{
Key *key = BKE_key_from_object(ob);
@@ -1624,9 +1617,6 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
-/**
- * \param shape_index: The index to use or all (when -1).
- */
int BKE_keyblock_element_count_from_shape(const Key *key, const int shape_index)
{
int result = 0;
@@ -1644,9 +1634,6 @@ int BKE_keyblock_element_count(const Key *key)
return BKE_keyblock_element_count_from_shape(key, -1);
}
-/**
- * \param shape_index: The index to use or all (when -1).
- */
size_t BKE_keyblock_element_calc_size_from_shape(const Key *key, const int shape_index)
{
return (size_t)BKE_keyblock_element_count_from_shape(key, shape_index) * key->elemsize;
@@ -1664,9 +1651,6 @@ size_t BKE_keyblock_element_calc_size(const Key *key)
* use #BKE_keyblock_element_calc_size to allocate the size of the data needed.
* \{ */
-/**
- * \param shape_index: The index to use or all (when -1).
- */
void BKE_keyblock_data_get_from_shape(const Key *key, float (*arr)[3], const int shape_index)
{
uint8_t *elements = (uint8_t *)arr;
@@ -1685,9 +1669,6 @@ void BKE_keyblock_data_get(const Key *key, float (*arr)[3])
BKE_keyblock_data_get_from_shape(key, arr, -1);
}
-/**
- * Set the data to all key-blocks (or shape_index if != -1).
- */
void BKE_keyblock_data_set_with_mat4(Key *key,
const int shape_index,
const float (*coords)[3],
@@ -1715,10 +1696,6 @@ void BKE_keyblock_data_set_with_mat4(Key *key,
}
}
-/**
- * Set the data for all key-blocks (or shape_index if != -1),
- * transforming by \a mat.
- */
void BKE_keyblock_curve_data_set_with_mat4(
Key *key, const ListBase *nurb, const int shape_index, const void *data, const float mat[4][4])
{
@@ -1734,9 +1711,6 @@ void BKE_keyblock_curve_data_set_with_mat4(
}
}
-/**
- * Set the data for all key-blocks (or shape_index if != -1).
- */
void BKE_keyblock_data_set(Key *key, const int shape_index, const void *data)
{
const uint8_t *elements = data;
@@ -1868,14 +1842,6 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
return kb;
}
-/**
- * \note sorting is a problematic side effect in some cases,
- * better only do this explicitly by having its own function,
- *
- * \param key: The key datablock to add to.
- * \param name: Optional name for the new keyblock.
- * \param do_force: always use ctime even for relative keys.
- */
KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force)
{
KeyBlock *kb = BKE_keyblock_add(key, name);
@@ -1904,7 +1870,6 @@ KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force
return kb;
}
-/* Only the active key-block. */
KeyBlock *BKE_keyblock_from_object(Object *ob)
{
Key *key = BKE_key_from_object(ob);
@@ -1928,7 +1893,6 @@ KeyBlock *BKE_keyblock_from_object_reference(Object *ob)
return NULL;
}
-/* get the appropriate KeyBlock given an index */
KeyBlock *BKE_keyblock_from_key(Key *key, int index)
{
if (key) {
@@ -1946,15 +1910,11 @@ KeyBlock *BKE_keyblock_from_key(Key *key, int index)
return NULL;
}
-/* get the appropriate KeyBlock given a name to search for */
KeyBlock *BKE_keyblock_find_name(Key *key, const char name[])
{
return BLI_findstring(&key->block, name, offsetof(KeyBlock, name));
}
-/**
- * \brief copy shape-key attributes, but not key data.or name/uid
- */
void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
{
kb_dst->pos = kb_src->pos;
@@ -1966,9 +1926,6 @@ void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
kb_dst->slidermax = kb_src->slidermax;
}
-/* Get RNA-Path for 'value' setting of the given ShapeKey
- * NOTE: the user needs to free the returned string once they're finish with it
- */
char *BKE_keyblock_curval_rnapath_get(Key *key, KeyBlock *kb)
{
PointerRNA ptr;
@@ -1991,6 +1948,7 @@ char *BKE_keyblock_curval_rnapath_get(Key *key, KeyBlock *kb)
/* conversion functions */
/************************* Lattice ************************/
+
void BKE_keyblock_update_from_lattice(Lattice *lt, KeyBlock *kb)
{
BPoint *bp;
@@ -2191,6 +2149,7 @@ void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nu
}
/************************* Mesh ************************/
+
void BKE_keyblock_update_from_mesh(Mesh *me, KeyBlock *kb)
{
MVert *mvert;
@@ -2243,15 +2202,6 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
}
}
-/**
- * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
- *
- * \param kb: the KeyBlock to use to compute normals.
- * \param mesh: the Mesh to apply key-block to.
- * \param r_vertnors: if non-NULL, an array of vectors, same length as number of vertices.
- * \param r_polynors: if non-NULL, an array of vectors, same length as number of polygons.
- * \param r_loopnors: if non-NULL, an array of vectors, same length as number of loops.
- */
void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
struct Mesh *mesh,
float (*r_vertnors)[3],
@@ -2316,6 +2266,7 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
}
/************************* raw coords ************************/
+
void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
{
const float(*co)[3] = vertCos;
@@ -2469,6 +2420,7 @@ float (*BKE_keyblock_convert_to_vertcos(Object *ob, KeyBlock *kb))[3]
}
/************************* raw coord offsets ************************/
+
void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, const float (*ofs)[3])
{
int a;
@@ -2506,15 +2458,6 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, const float (*ofs
/* ==========================================================*/
-/**
- * Move shape key from org_index to new_index. Safe, clamps index to valid range,
- * updates reference keys, the object's active shape index,
- * the 'frame' value in case of absolute keys, etc.
- * Note indices are expected in real values (not 'fake' shapenr +1 ones).
- *
- * \param org_index: if < 0, current object's active shape will be used as skey to move.
- * \return true if something was done, else false.
- */
bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
{
Key *key = BKE_key_from_object(ob);
@@ -2593,9 +2536,6 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
return true;
}
-/**
- * Check if given key-block (as index) is used as basis by others in given key.
- */
bool BKE_keyblock_is_basis(Key *key, const int index)
{
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/keyconfig.c b/source/blender/blenkernel/intern/keyconfig.c
index d25f475c140..84e11c1166e 100644
--- a/source/blender/blenkernel/intern/keyconfig.c
+++ b/source/blender/blenkernel/intern/keyconfig.c
@@ -121,7 +121,6 @@ void BKE_keyconfig_pref_type_free(void)
/** \name Key-Config Versioning
* \{ */
-/* Set select mouse, for versioning code. */
void BKE_keyconfig_pref_set_select_mouse(UserDef *userdef, int value, bool override)
{
wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(userdef, WM_KEYCONFIG_STR_DEFAULT);
@@ -201,10 +200,6 @@ void BKE_keyconfig_keymap_filter_item(wmKeyMap *keymap,
}
}
-/**
- * Filter & optionally remove key-map items,
- * intended for versioning, but may be used in other situations too.
- */
void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
const struct wmKeyConfigFilterItemParams *params,
bool (*filter_fn)(wmKeyMapItem *kmi, void *user_data),
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index a2da59bca58..af0d91d29fc 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -197,6 +197,7 @@ IDTypeInfo IDType_ID_LT = {
.name_plural = "lattices",
.translation_context = BLT_I18NCONTEXT_ID_LATTICE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = lattice_init_data,
.copy_data = lattice_copy_data,
@@ -204,6 +205,7 @@ IDTypeInfo IDType_ID_LT = {
.make_local = NULL,
.foreach_id = lattice_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = lattice_blend_write,
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 6aa8e78c4f6..1484d35f28a 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -77,7 +77,9 @@ static const short g_base_collection_flags = (BASE_VISIBLE_DEPSGRAPH | BASE_VISI
/* prototype */
static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
-/*********************** Layer Collections and bases *************************/
+/* -------------------------------------------------------------------- */
+/** \name Layer Collections and Bases
+ * \{ */
static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection)
{
@@ -113,12 +115,14 @@ static Base *object_base_new(Object *ob)
return base;
}
-/********************************* View Layer ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Layer
+ * \{ */
/* RenderLayer */
-/* Returns the default view layer to view in workspaces if there is
- * none linked to the workspace yet. */
ViewLayer *BKE_view_layer_default_view(const Scene *scene)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -131,7 +135,6 @@ ViewLayer *BKE_view_layer_default_view(const Scene *scene)
return scene->view_layers.first;
}
-/* Returns the default view layer to render if we need to render just one. */
ViewLayer *BKE_view_layer_default_render(const Scene *scene)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -144,7 +147,6 @@ ViewLayer *BKE_view_layer_default_render(const Scene *scene)
return scene->view_layers.first;
}
-/* Returns view layer with matching name, or NULL if not found. */
ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -156,11 +158,6 @@ ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
return NULL;
}
-/**
- * This is a placeholder to know which areas of the code need to be addressed
- * for the Workspace changes. Never use this, you should typically get the
- * active layer from the context or window.
- */
ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
{
BLI_assert(scene->view_layers.first);
@@ -198,10 +195,6 @@ static void layer_collection_exclude_all(LayerCollection *layer_collection)
}
}
-/**
- * Add a new view layer
- * by default, a view layer has the master collection
- */
ViewLayer *BKE_view_layer_add(Scene *scene,
const char *name,
ViewLayer *view_layer_source,
@@ -261,9 +254,6 @@ void BKE_view_layer_free(ViewLayer *view_layer)
BKE_view_layer_free_ex(view_layer, true);
}
-/**
- * Free (or release) any data used by this ViewLayer.
- */
void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
{
view_layer->basact = NULL;
@@ -304,9 +294,6 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
MEM_freeN(view_layer);
}
-/**
- * Tag all the selected objects of a render-layer.
- */
void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
{
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
@@ -332,13 +319,6 @@ static bool find_scene_collection_in_scene_collections(ListBase *lb, const Layer
return false;
}
-/**
- * Fallback for when a Scene has no camera to use
- *
- * \param view_layer: in general you want to use the same ViewLayer that is used
- * for depsgraph. If rendering you pass the scene active layer, when viewing in the viewport
- * you want to get ViewLayer from context.
- */
Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
{
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
@@ -350,9 +330,6 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
return NULL;
}
-/**
- * Find the ViewLayer a LayerCollection belongs to
- */
ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -422,7 +399,12 @@ void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Bas
}
}
-/**************************** Copy View Layer and Layer Collections ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy View Layer and Layer Collections
+ * \{ */
+
static void layer_aov_copy_data(ViewLayer *view_layer_dst,
const ViewLayer *view_layer_src,
ListBase *aovs_dst,
@@ -471,11 +453,6 @@ static void layer_collections_copy_data(ViewLayer *view_layer_dst,
}
}
-/**
- * Only copy internal data of ViewLayer from source to already allocated/initialized destination.
- *
- * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
- */
void BKE_view_layer_copy_data(Scene *scene_dst,
const Scene *UNUSED(scene_src),
ViewLayer *view_layer_dst,
@@ -620,26 +597,17 @@ static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc)
return false;
}
-/**
- * Get the collection for a given index
- */
LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index)
{
int i = 0;
return collection_from_index(&view_layer->layer_collections, index, &i);
}
-/**
- * Get the active collection
- */
LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer)
{
return view_layer->active_collection;
}
-/*
- * Activate collection
- */
bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
{
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
@@ -650,9 +618,6 @@ bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
return true;
}
-/**
- * Activate first parent collection
- */
LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc)
{
CollectionParent *parent = lc->collection->parents.first;
@@ -690,10 +655,6 @@ static int collection_count(const ListBase *lb)
return i;
}
-/**
- * Get the total number of collections
- * (including all the nested collections)
- */
int BKE_layer_collection_count(const ViewLayer *view_layer)
{
return collection_count(&view_layer->layer_collections);
@@ -721,16 +682,16 @@ static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i
return -1;
}
-/**
- * Return -1 if not found
- */
int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection *lc)
{
int i = 0;
return index_from_collection(&view_layer->layer_collections, lc, &i);
}
-/*********************************** Syncing *********************************
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Syncing
*
* The layer collection tree mirrors the scene collection tree. Whenever that
* changes we need to synchronize them so that there is a corresponding layer
@@ -740,9 +701,9 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
*
* The view layer also contains a list of bases for each object that exists
* in at least one layer collection. That list is also synchronized here, and
- * stores state like selection. */
-
-/* This API allows to temporarily forbid resync of LayerCollections.
+ * stores state like selection.
+ *
+ * This API allows to temporarily forbid resync of LayerCollections.
*
* This can greatly improve performances in cases where those functions get
* called a lot (e.g. during massive remappings of IDs).
@@ -751,19 +712,20 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
* code must ensures it resync LayerCollections before any UI/Event loop
* handling can happen.
*
- * WARNING: This is not threadsafe at all, only use from main thread.
+ * \warning This is not threadsafe at all, only use from main thread.
*
- * NOTE: It is probably needed to use #BKE_main_collection_sync_remap instead
+ * \note It is probably needed to use #BKE_main_collection_sync_remap instead
* of just #BKE_main_collection_sync after disabling LayerCollection resync,
* unless it is absolutely certain that no ID remapping (or any other process
* that may invalidate the caches) will happen while it is disabled.
*
- * NOTE: This is a quick and safe band-aid around the long-known issue
+ * \note This is a quick and safe band-aid around the long-known issue
* regarding this resync process.
* Proper fix would be to make resync itself lazy, i.e. only happen
* when actually needed.
* See also T73411.
- */
+ * \{ */
+
static bool no_resync = false;
void BKE_layer_collection_resync_forbid(void)
@@ -1220,11 +1182,6 @@ static bool view_layer_objects_base_cache_validate(ViewLayer *UNUSED(view_layer)
}
#endif
-/**
- * Update view layer collection tree from collections used in the scene.
- * This is used when collections are removed or added, both while editing
- * and on file loaded in case linked data changed or went missing.
- */
void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
{
if (no_resync) {
@@ -1377,14 +1334,12 @@ void BKE_main_collection_sync_remap(const Main *bmain)
BKE_main_collection_sync(bmain);
}
-/* ---------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Selection
+ * \{ */
-/**
- * Select all the objects of this layer collection
- *
- * It also select the objects that are in nested collections.
- * \note Recursive
- */
bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect)
{
if (lc->collection->flag & COLLECTION_HIDE_SELECT) {
@@ -1461,9 +1416,12 @@ bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent,
return false;
}
-/* ---------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Visibility
+ * \{ */
-/* Update after toggling visibility of an object base. */
void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool extend)
{
if (!extend) {
@@ -1536,6 +1494,12 @@ bool BKE_object_is_visible_in_viewport(const View3D *v3d, const struct Object *o
return true;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Collection Isolation & Local View
+ * \{ */
+
static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag)
{
lc->flag |= flag;
@@ -1552,14 +1516,6 @@ static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int
}
}
-/**
- * Isolate the collection - hide all other collections but this one.
- * Make sure to show all the direct parents and all children of the layer collection as well.
- * When extending we simply show the collections and its direct family.
- *
- * If the collection or any of its parents is disabled, make it enabled.
- * Don't change the children disable state though.
- */
void BKE_layer_collection_isolate_global(Scene *scene,
ViewLayer *view_layer,
LayerCollection *lc,
@@ -1668,9 +1624,6 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, const View3D *v3d)
}
}
-/**
- * Sync the local collection for all the 3D Viewports.
- */
void BKE_layer_collection_local_sync_all(const Main *bmain)
{
if (no_resync) {
@@ -1694,11 +1647,6 @@ void BKE_layer_collection_local_sync_all(const Main *bmain)
}
}
-/**
- * Isolate the collection locally
- *
- * Same as BKE_layer_collection_isolate_local but for a viewport
- */
void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
const View3D *v3d,
LayerCollection *lc,
@@ -1771,11 +1719,6 @@ static void layer_collection_bases_hide_recursive(ViewLayer *view_layer, LayerCo
}
}
-/**
- * Hide/show all the elements of a collection.
- * Don't change the collection children enable/disable state,
- * but it may change it for the collection itself.
- */
void BKE_layer_collection_set_visible(ViewLayer *view_layer,
LayerCollection *lc,
const bool visible,
@@ -1862,9 +1805,6 @@ static LayerCollection *find_layer_collection_by_scene_collection(LayerCollectio
return NULL;
}
-/**
- * Return the first matching LayerCollection in the ViewLayer for the Collection.
- */
LayerCollection *BKE_layer_collection_first_from_scene_collection(const ViewLayer *view_layer,
const Collection *collection)
{
@@ -1878,17 +1818,11 @@ LayerCollection *BKE_layer_collection_first_from_scene_collection(const ViewLaye
return NULL;
}
-/**
- * See if view layer has the scene collection linked directly, or indirectly (nested)
- */
bool BKE_view_layer_has_collection(const ViewLayer *view_layer, const Collection *collection)
{
return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL;
}
-/**
- * See if the object is in any of the scene layers of the scene
- */
bool BKE_scene_has_object(Scene *scene, Object *ob)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -1999,6 +1933,8 @@ static void objects_iterator_end(BLI_Iterator *iter)
object_bases_iterator_end(iter);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name BKE_view_layer_selected_objects_iterator
* See: #FOREACH_SELECTED_OBJECT_BEGIN
@@ -2188,11 +2124,10 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
/** \} */
-/* Evaluation. */
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
-/* Applies object's restrict flags on top of flags coming from the collection
- * and stores those in base->flag. BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility
- * (i.e., restriction and local collection). */
void BKE_base_eval_flags(Base *base)
{
/* Apply collection flags. */
@@ -2251,6 +2186,12 @@ void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph,
layer_eval_view_layer(depsgraph, scene, view_layer);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend File I/O
+ * \{ */
+
static void write_layer_collections(BlendWriter *writer, ListBase *lb)
{
LISTBASE_FOREACH (LayerCollection *, lc, lb) {
@@ -2371,6 +2312,8 @@ void BKE_view_layer_blend_read_lib(BlendLibReader *reader, Library *lib, ViewLay
IDP_BlendReadLib(reader, view_layer->id_properties);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Shader AOV
* \{ */
@@ -2455,12 +2398,6 @@ static void bke_view_layer_verify_aov_cb(void *userdata,
}
}
-/* Update the naming and conflicts of the AOVs.
- *
- * Name must be unique between all AOVs.
- * Conflicts with render passes will show a conflict icon. Reason is that switching a render
- * engine or activating a render pass could lead to other conflicts that wouldn't be that clear
- * for the user. */
void BKE_view_layer_verify_aov(struct RenderEngine *engine,
struct Scene *scene,
struct ViewLayer *view_layer)
@@ -2478,7 +2415,6 @@ void BKE_view_layer_verify_aov(struct RenderEngine *engine,
BLI_ghash_free(name_count, MEM_freeN, NULL);
}
-/* Check if the given view layer has at least one valid AOV. */
bool BKE_view_layer_has_valid_aov(ViewLayer *view_layer)
{
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
index 48179e0c3bf..3760fe8a976 100644
--- a/source/blender/blenkernel/intern/layer_utils.c
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -193,13 +193,6 @@ bool BKE_view_layer_filter_edit_mesh_has_edges(const Object *ob, void *UNUSED(us
return false;
}
-/**
- * Use this in rare cases we need to detect a pair of objects (active, selected).
- * This returns the other non-active selected object.
- *
- * Returns NULL with it finds multiple other selected objects
- * as behavior in this case would be random from the user perspective.
- */
Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
const struct View3D *v3d)
{
@@ -221,4 +214,5 @@ Object *BKE_view_layer_non_active_selected_object(struct ViewLayer *view_layer,
FOREACH_SELECTED_OBJECT_END;
return ob_result;
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index cd5b266eb75..692e27731c5 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -89,7 +89,6 @@
static CLG_LogRef LOG = {.identifier = "bke.lib_id"};
-/* Empty shell mostly, but needed for read code. */
IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.id_code = ID_LINK_PLACEHOLDER,
.id_filter = 0,
@@ -99,6 +98,7 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.name_plural = "link_placeholders",
.translation_context = BLT_I18NCONTEXT_ID_ID,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -106,6 +106,8 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
+ .owner_get = NULL,
.blend_write = NULL,
.blend_read_data = NULL,
@@ -124,18 +126,56 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
/* ************* general ************************ */
/**
+ * Rewrites a relative path to be relative to the main file - unless the path is
+ * absolute, in which case it is not altered.
+ */
+static bool lib_id_library_local_paths_callback(BPathForeachPathData *bpath_data,
+ char *r_path_dst,
+ const char *path_src)
+{
+ const char **data = bpath_data->user_data;
+ /* be sure there is low chance of the path being too short */
+ char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
+ const char *base_new = data[0];
+ const char *base_old = data[1];
+
+ if (BLI_path_is_rel(base_old)) {
+ CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
+ return false;
+ }
+
+ /* Make referenced file absolute. This would be a side-effect of
+ * BLI_path_normalize, but we do it explicitly so we know if it changed. */
+ BLI_strncpy(filepath, path_src, FILE_MAX);
+ if (BLI_path_abs(filepath, base_old)) {
+ /* Path was relative and is now absolute. Remap.
+ * Important BLI_path_normalize runs before the path is made relative
+ * because it won't work for paths that start with "//../" */
+ BLI_path_normalize(base_new, filepath);
+ BLI_path_rel(filepath, base_new);
+ BLI_strncpy(r_path_dst, filepath, FILE_MAX);
+ return true;
+ }
+
+ /* Path was not relative to begin with. */
+ return false;
+}
+
+/**
* This has to be called from each make_local_* func, we could call from BKE_lib_id_make_local()
* but then the make local functions would not be self contained.
* Also note that the id _must_ have a library - campbell */
+/* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase. */
static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
{
const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
- BKE_bpath_traverse_id(bmain,
- id,
- BKE_bpath_relocate_visitor,
- BKE_BPATH_TRAVERSE_SKIP_MULTIFILE,
- (void *)bpath_user_data);
+ BKE_bpath_foreach_path_id(
+ &(BPathForeachPathData){.bmain = bmain,
+ .callback_function = lib_id_library_local_paths_callback,
+ .flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE,
+ .user_data = (void *)bpath_user_data},
+ id);
}
static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *cb_data)
@@ -149,12 +189,6 @@ static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *
return IDWALK_RET_NOP;
}
-/**
- * Pull an ID out of a library (make it local). Only call this for IDs that
- * don't have other library users.
- *
- * \param flags Same set of `LIB_ID_MAKELOCAL_` flags as passed to `BKE_lib_id_make_local`.
- */
void BKE_lib_id_clear_library_data(Main *bmain, ID *id, const int flags)
{
const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 &&
@@ -179,8 +213,14 @@ void BKE_lib_id_clear_library_data(Main *bmain, ID *id, const int flags)
BKE_lib_libblock_session_uuid_renew(id);
}
- if ((flags & LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR) != 0 && id->asset_data != NULL) {
- BKE_asset_metadata_free(&id->asset_data);
+ if (ID_IS_ASSET(id)) {
+ if ((flags & LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR) != 0) {
+ BKE_asset_metadata_free(&id->asset_data);
+ }
+ else {
+ /* Assets should always have a fake user. Ensure this is the case after "Make Local". */
+ id_fake_user_set(id);
+ }
}
/* We need to tag this IDs and all of its users, conceptually new local ID and original linked
@@ -228,14 +268,6 @@ void id_lib_indirect_weak_link(ID *id)
}
}
-/**
- * Ensure we have a real user
- *
- * \note Now that we have flags, we could get rid of the 'fake_user' special case,
- * flags are enough to ensure we always have a real user.
- * However, #ID_REAL_USERS is used in several places outside of core lib.c,
- * so think we can wait later to make this change.
- */
void id_us_ensure_real(ID *id)
{
if (id) {
@@ -266,10 +298,6 @@ void id_us_clear_real(ID *id)
}
}
-/**
- * Same as \a id_us_plus, but does not handle lib indirect -> extern.
- * Only used by readfile.c so far, but simpler/safer to keep it here nonetheless.
- */
void id_us_plus_no_lib(ID *id)
{
if (id) {
@@ -294,7 +322,6 @@ void id_us_plus(ID *id)
}
}
-/* decrements the user count for *id. */
void id_us_min(ID *id)
{
if (id) {
@@ -410,10 +437,6 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/**
- * Expand ID usages of given id as 'extern' (and no more indirect) linked data.
- * Used by ID copy/make_local functions.
- */
void BKE_lib_id_expand_local(Main *bmain, ID *id, const int flags)
{
BKE_library_foreach_ID_link(
@@ -431,9 +454,6 @@ static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id,
}
}
-/**
- * Generic 'make local' function, works for most of data-block types...
- */
void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
{
if (!ID_IS_LINKED(id)) {
@@ -503,15 +523,6 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
}
}
-/**
- * Calls the appropriate make_local method for the block, unless test is set.
- *
- * \note Always set #ID.newid pointer in case it gets duplicated.
- *
- * \param flags: Special flag used when making a whole library's content local,
- * it needs specific handling.
- * \return true is the ID has successfully been made local.
- */
bool BKE_lib_id_make_local(Main *bmain, ID *id, const int flags)
{
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
@@ -586,27 +597,6 @@ bool BKE_id_copy_is_allowed(const ID *id)
#undef LIB_ID_TYPES_NOCOPY
}
-/**
- * Generic entry point for copying a data-block (new API).
- *
- * \note Copy is generally only affecting the given data-block
- * (no ID used by copied one will be affected, besides usercount).
- * There are exceptions though:
- * - Embedded IDs (root node trees and master collections) are always copied with their owner.
- * - If #LIB_ID_COPY_ACTIONS is defined, actions used by animdata will be duplicated.
- * - If #LIB_ID_COPY_SHAPEKEY is defined, shapekeys will be duplicated.
- * - If #LIB_ID_CREATE_LOCAL is defined, root node trees will be deep-duplicated recursively.
- *
- * \note Usercount of new copy is always set to 1.
- *
- * \param bmain: Main database, may be NULL only if LIB_ID_CREATE_NO_MAIN is specified.
- * \param id: Source data-block.
- * \param r_newid: Pointer to new (copied) ID pointer, may be NULL. Used to allow copying into
- * already allocated memory.
- * \param flag: Set of copy options, see DNA_ID.h enum for details (leave to zero for default,
- * full copy).
- * \return NULL when copying that ID type is not supported, the new copy otherwise.
- */
ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
{
ID *newid = (r_newid != NULL) ? *r_newid : NULL;
@@ -669,19 +659,11 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
return newid;
}
-/**
- * Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true if the block can be copied.
- */
ID *BKE_id_copy(Main *bmain, const ID *id)
{
return BKE_id_copy_ex(bmain, id, NULL, LIB_ID_COPY_DEFAULT);
}
-/**
- * Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true if the block can be copied.
- */
ID *BKE_id_copy_for_duplicate(Main *bmain,
ID *id,
const eDupli_ID_Flags duplicate_flags,
@@ -762,31 +744,16 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id)
}
}
-/**
- * Does a mere memory swap over the whole IDs data (including type-specific memory).
- * \note Most internal ID data itself is not swapped (only IDProperties are).
- *
- * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
- * itself.
- */
void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
{
id_swap(bmain, id_a, id_b, false);
}
-/**
- * Does a mere memory swap over the whole IDs data (including type-specific memory).
- * \note All internal ID data itself is also swapped.
- *
- * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
- * itself.
- */
void BKE_lib_id_swap_full(Main *bmain, ID *id_a, ID *id_b)
{
id_swap(bmain, id_a, id_b, true);
}
-/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -851,7 +818,6 @@ static int libblock_management_us_min(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/** Add a 'NO_MAIN' data-block to given main (also sets usercounts of its IDs if needed). */
void BKE_libblock_management_main_add(Main *bmain, void *idv)
{
ID *id = idv;
@@ -885,7 +851,6 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv)
BKE_lib_libblock_session_uuid_ensure(id);
}
-/** Remove a data-block from given main (set it to 'NO_MAIN' status). */
void BKE_libblock_management_main_remove(Main *bmain, void *idv)
{
ID *id = idv;
@@ -930,9 +895,6 @@ void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
id->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
-/**
- * Clear or set given tags for all ids in listbase (runtime tags).
- */
void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
{
ID *id;
@@ -949,9 +911,6 @@ void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
}
}
-/**
- * Clear or set given tags for all ids of given type in bmain (runtime tags).
- */
void BKE_main_id_tag_idcode(struct Main *mainvar,
const short type,
const int tag,
@@ -962,9 +921,6 @@ void BKE_main_id_tag_idcode(struct Main *mainvar,
BKE_main_id_tag_listbase(lb, tag, value);
}
-/**
- * Clear or set given tags for all ids in bmain (runtime tags).
- */
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -976,9 +932,6 @@ void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
}
}
-/**
- * Clear or set given flags for all ids in listbase (persistent flags).
- */
void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
{
ID *id;
@@ -995,9 +948,6 @@ void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
}
}
-/**
- * Clear or set given flags for all ids in bmain (persistent flags).
- */
void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -1063,9 +1013,6 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
*
* **************************** */
-/**
- * Get allocation size of a given data-block type and optionally allocation name.
- */
size_t BKE_libblock_get_alloc_info(short type, const char **name)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(type);
@@ -1083,10 +1030,6 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
return id_type->struct_size;
}
-/**
- * Allocates and returns memory of the right size for the specified block type,
- * initialized to zero.
- */
void *BKE_libblock_alloc_notest(short type)
{
const char *name;
@@ -1098,12 +1041,6 @@ void *BKE_libblock_alloc_notest(short type)
return NULL;
}
-/**
- * Allocates and returns a block of the specified type, with the specified name
- * (adjusted as necessary to ensure uniqueness), and appended to the specified list.
- * The user count is set to 1, all other content (apart from name and links) being
- * initialized to zero.
- */
void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag)
{
BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
@@ -1166,10 +1103,6 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
return id;
}
-/**
- * Initialize an ID of given type, such that it has valid 'empty' data.
- * ID is assumed to be just calloc'ed.
- */
void BKE_libblock_init_empty(ID *id)
{
const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_id(id);
@@ -1187,12 +1120,6 @@ void BKE_libblock_init_empty(ID *id)
/* ********** ID session-wise UUID management. ********** */
static uint global_session_uuid = 0;
-/**
- * Generate a session-wise uuid for the given \a id.
- *
- * \note "session-wise" here means while editing a given .blend file. Once a new .blend file is
- * loaded or created, undo history is cleared/reset, and so is the uuid counter.
- */
void BKE_lib_libblock_session_uuid_ensure(ID *id)
{
if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
@@ -1206,25 +1133,12 @@ void BKE_lib_libblock_session_uuid_ensure(ID *id)
}
}
-/**
- * Re-generate a new session-wise uuid for the given \a id.
- *
- * \warning This has a few very specific use-cases, no other usage is expected currently:
- * - To handle UI-related data-blocks that are kept across new file reading, when we do keep
- * existing UI.
- * - For IDs that are made local without needing any copying.
- */
void BKE_lib_libblock_session_uuid_renew(ID *id)
{
id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
BKE_lib_libblock_session_uuid_ensure(id);
}
-/**
- * Generic helper to create a new empty data-block of given type in given \a bmain database.
- *
- * \param name: can be NULL, in which case we get default name for this ID type.
- */
void *BKE_id_new(Main *bmain, const short type, const char *name)
{
BLI_assert(bmain != NULL);
@@ -1239,11 +1153,6 @@ void *BKE_id_new(Main *bmain, const short type, const char *name)
return id;
}
-/**
- * Generic helper to create a new temporary empty data-block of given type,
- * *outside* of any Main database.
- *
- * \param name: can be NULL, in which case we get default name for this ID type. */
void *BKE_id_new_nomain(const short type, const char *name)
{
if (name == NULL) {
@@ -1357,7 +1266,6 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
*r_newid = new_id;
}
-/* used everywhere in blenkernel */
void *BKE_libblock_copy(Main *bmain, const ID *id)
{
ID *idn;
@@ -1368,6 +1276,7 @@ void *BKE_libblock_copy(Main *bmain, const ID *id)
}
/* ***************** ID ************************ */
+
ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name)
{
ListBase *lb = which_libbase(bmain, type);
@@ -1389,14 +1298,6 @@ struct ID *BKE_libblock_find_session_uuid(Main *bmain,
return NULL;
}
-/**
- * Sort given \a id into given \a lb list, using case-insensitive comparison of the id names.
- *
- * \note All other IDs beside given one are assumed already properly sorted in the list.
- *
- * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
- * immediately before or after that pointer. It must always be into given \a lb list.
- */
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
{
#define ID_SORT_STEP_SIZE 512
@@ -1754,16 +1655,6 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name, ID **r_id_sorting_
#undef MIN_NUMBER
#undef MAX_NUMBER
-/**
- * Ensures given ID has a unique name in given listbase.
- *
- * Only for local IDs (linked ones already have a unique ID in their library).
- *
- * \param do_linked_data: if true, also ensure a unique name in case the given \a id is linked
- * (otherwise, just ensure that it is properly sorted).
- *
- * \return true if a new name had to be created.
- */
bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const bool do_linked_data)
{
bool result = false;
@@ -1813,7 +1704,6 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const boo
return result;
}
-/* next to indirect usage in read/writefile also in editobject.c scene.c */
void BKE_main_id_newptr_and_tag_clear(Main *bmain)
{
ID *id;
@@ -1936,30 +1826,20 @@ static void library_make_local_copying_check(ID *id,
BLI_gset_remove(loop_tags, id, NULL);
}
-/**
- * Make linked data-blocks local.
- *
- * \param bmain: Almost certainly global main.
- * \param lib: If not NULL, only make local data-blocks from this library.
- * \param untagged_only: If true, only make local data-blocks not tagged with
- * LIB_TAG_PRE_EXISTING.
- * \param set_fake: If true, set fake user on all localized data-blocks
- * (except group and objects ones).
- */
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
* without actually making any check whether they were also indirectly used or not...
*
* Current version uses regular id_make_local callback, with advanced pre-processing step to
* detect all cases of IDs currently indirectly used, but which will be used by local data only
* once this function is finished. This allows to avoid any unneeded duplication of IDs, and
- * hence all time lost afterwards to remove orphaned linked data-blocks...
- */
+ * hence all time lost afterwards to remove orphaned linked data-blocks. */
void BKE_library_make_local(Main *bmain,
const Library *lib,
GHash *old_to_new_ids,
const bool untagged_only,
const bool set_fake)
{
+
ListBase *lbarray[INDEX_ID_MAX];
LinkNode *todo_ids = NULL;
@@ -2233,10 +2113,6 @@ void BKE_library_make_local(Main *bmain,
#endif
}
-/**
- * Use after setting the ID's name
- * When name exists: call 'new_id'
- */
void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
{
ListBase *lb;
@@ -2256,9 +2132,6 @@ void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
}
}
-/**
- * Sets the name of a block to name, suitably adjusted for uniqueness.
- */
void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
{
BLI_assert(!ID_IS_LINKED(id));
@@ -2268,16 +2141,6 @@ void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
}
}
-/**
- * Generate full name of the data-block (without ID code, but with library if any).
- *
- * \note Result is unique to a given ID type in a given Main database.
- *
- * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME,
- * will be filled with generated string.
- * \param separator_char: Character to use for separating name and library name. Can be 0 to use
- * default (' ').
- */
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separator_char)
{
strcpy(name, id->name + 2);
@@ -2294,19 +2157,6 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separa
}
}
-/**
- * Generate full name of the data-block (without ID code, but with library if any),
- * with a 2 to 3 character prefix prepended indicating whether it comes from a library,
- * is overriding, has a fake or no user, etc.
- *
- * \note Result is unique to a given ID type in a given Main database.
- *
- * \param name: An allocated string of minimal length #MAX_ID_FULL_NAME_UI,
- * will be filled with generated string.
- * \param separator_char: Character to use for separating name and library name. Can be 0 to use
- * default (' ').
- * \param r_prefix_len: The length of the prefix added.
- */
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
const ID *id,
const bool add_lib_hint,
@@ -2328,11 +2178,6 @@ void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
}
}
-/**
- * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any.
- *
- * \return A unique allocated string key for any ID in the whole Main database.
- */
char *BKE_id_to_unique_string_key(const struct ID *id)
{
if (!ID_IS_LINKED(id)) {
@@ -2356,10 +2201,6 @@ void BKE_id_tag_clear_atomic(ID *id, int tag)
atomic_fetch_and_and_int32(&id->tag, ~tag);
}
-/**
- * Check that given ID pointer actually is in G_MAIN.
- * Main intended use is for debug asserts in places we cannot easily get rid of G_Main...
- */
bool BKE_id_is_in_global_main(ID *id)
{
/* We do not want to fail when id is NULL here, even though this is a bit strange behavior...
@@ -2406,10 +2247,6 @@ static int id_order_compare(const void *a, const void *b)
return strcmp(id_a->name, id_b->name);
}
-/**
- * Returns ordered list of data-blocks for display in the UI.
- * Result is list of LinkData of IDs that must be freed.
- */
void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
{
BLI_listbase_clear(ordered_lb);
@@ -2429,9 +2266,6 @@ void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
}
}
-/**
- * Reorder ID in the list, before or after the "relative" ID.
- */
void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
{
int *id_order = id_order_get(id);
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 502a1197616..1922a54addb 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -90,23 +90,6 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
BLI_assert_msg(0, "IDType Missing IDTypeInfo");
}
-/**
- * Complete ID freeing, extended version for corner cases.
- * Can override default (and safe!) freeing process, to gain some speed up.
- *
- * At that point, given id is assumed to not be used by any other data-block already
- * (might not be actually true, in case e.g. several inter-related IDs get freed together...).
- * However, they might still be using (referencing) other IDs, this code takes care of it if
- * #LIB_TAG_NO_USER_REFCOUNT is not defined.
- *
- * \param bmain: #Main database containing the freed #ID,
- * can be NULL in case it's a temp ID outside of any #Main.
- * \param idv: Pointer to ID to be freed.
- * \param flag: Set of \a LIB_ID_FREE_... flags controlling/overriding usual freeing process,
- * 0 to get default safe behavior.
- * \param use_flag_from_idtag: Still use freeing info flags from given #ID datablock,
- * even if some overriding ones are passed in \a flag parameter.
- */
void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag)
{
ID *id = idv;
@@ -191,24 +174,11 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
}
}
-/**
- * Complete ID freeing, should be usable in most cases (even for out-of-Main IDs).
- *
- * See #BKE_id_free_ex description for full details.
- *
- * \param bmain: Main database containing the freed ID,
- * can be NULL in case it's a temp ID outside of any Main.
- * \param idv: Pointer to ID to be freed.
- */
void BKE_id_free(Main *bmain, void *idv)
{
BKE_id_free_ex(bmain, idv, 0, true);
}
-/**
- * Not really a freeing function by itself,
- * it decrements usercount of given id, and only frees it if it reaches 0.
- */
void BKE_id_free_us(Main *bmain, void *idv) /* test users */
{
ID *id = idv;
@@ -378,9 +348,6 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
return num_datablocks_deleted;
}
-/**
- * Properly delete a single ID from given \a bmain database.
- */
void BKE_id_delete(Main *bmain, void *idv)
{
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
@@ -389,16 +356,6 @@ void BKE_id_delete(Main *bmain, void *idv)
id_delete(bmain, false);
}
-/**
- * Properly delete all IDs tagged with \a LIB_TAG_DOIT, in given \a bmain database.
- *
- * This is more efficient than calling #BKE_id_delete repetitively on a large set of IDs
- * (several times faster when deleting most of the IDs at once)...
- *
- * \warning Considered experimental for now, seems to be working OK but this is
- * risky code in a complicated area.
- * \return Number of deleted datablocks.
- */
size_t BKE_id_multi_tagged_delete(Main *bmain)
{
return id_delete(bmain, true);
@@ -408,12 +365,6 @@ size_t BKE_id_multi_tagged_delete(Main *bmain)
/** \name Python Data Handling
* \{ */
-/**
- * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
- * this function will need to be called too, if Python has access to the data.
- *
- * ID data-blocks such as #Material.nodetree are not stored in #Main.
- */
void BKE_libblock_free_data_py(ID *id)
{
#ifdef WITH_PYTHON
diff --git a/source/blender/blenkernel/intern/lib_id_eval.c b/source/blender/blenkernel/intern/lib_id_eval.c
index 140fe403ac3..a29d9270d72 100644
--- a/source/blender/blenkernel/intern/lib_id_eval.c
+++ b/source/blender/blenkernel/intern/lib_id_eval.c
@@ -29,11 +29,6 @@
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
-/**
- * Copy relatives parameters, from `id` to `id_cow`.
- * Use handle the #ID_RECALC_PARAMETERS tag.
- * \note Keep in sync with #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW.
- */
void BKE_id_eval_properties_copy(ID *id_cow, ID *id)
{
const ID_Type id_type = GS(id->name);
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 66a550ec6b0..83ed0ee4c08 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -57,6 +57,7 @@
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
+#include "BLI_memarena.h"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -99,7 +100,6 @@ BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id)
return id->override_library;
}
-/** Initialize empty overriding of \a reference_id by \a local_id. */
IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
{
/* If reference_id is NULL, we are creating an override template for purely local data.
@@ -134,7 +134,6 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
return local_id->override_library;
}
-/** Shalow or deep copy of a whole override from \a src_id to \a dst_id. */
void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_full_copy)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id) || ID_IS_OVERRIDE_LIBRARY_TEMPLATE(src_id));
@@ -176,7 +175,6 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
dst_id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
}
-/** Clear any overriding data from given \a override. */
void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_id_user)
{
BLI_assert(override != NULL);
@@ -196,7 +194,6 @@ void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_i
}
}
-/** Free given \a override. */
void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user)
{
BLI_assert(*override != NULL);
@@ -245,14 +242,11 @@ static ID *lib_override_library_create_from(Main *bmain,
return local_id;
}
-/**
- * Check if given ID has some override rules that actually indicate the user edited it.
- *
- * TODO: This could be simplified by storing a flag in #IDOverrideLibrary during the diffing
- * process?
- */
+/* TODO: This could be simplified by storing a flag in #IDOverrideLibrary
+ * during the diffing process? */
bool BKE_lib_override_library_is_user_edited(struct ID *id)
{
+
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
return false;
}
@@ -280,7 +274,6 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id)
return false;
}
-/** Create an overridden local copy of linked reference. */
ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *reference_id,
const bool do_tagged_remap)
@@ -322,25 +315,6 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
return local_id;
}
-/**
- * Create overridden local copies of all tagged data-blocks in given Main.
- *
- * \note Set `id->newid` of overridden libs with newly created overrides,
- * caller is responsible to clean those pointers before/after usage as needed.
- *
- * \note By default, it will only remap newly created local overriding data-blocks between
- * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in
- * main. You can add more local IDs to be remapped to use new overriding ones by setting their
- * LIB_TAG_DOIT tag.
- *
- * \param reference_library: the library from which the linked data being overridden come from
- * (i.e. the library of the linked reference ID).
- *
- * \param do_no_main: Create the new override data outside of Main database.
- * Used for resyncing of linked overrides.
- *
- * \return \a true on success, \a false otherwise.
- */
bool BKE_lib_override_library_create_from_tag(Main *bmain,
const Library *reference_library,
const bool do_no_main)
@@ -479,8 +453,59 @@ typedef struct LibOverrideGroupTagData {
bool is_override;
/* Whether we are creating new override, or resyncing existing one. */
bool is_resync;
+
+ /* Mapping linked objects to all their instantiating collections (as a linked list).
+ * Avoids calling #BKE_collection_object_find over and over, this function is very expansive. */
+ GHash *linked_object_to_instantiating_collections;
+ MemArena *mem_arena;
} LibOverrideGroupTagData;
+static void lib_override_group_tag_data_object_to_collection_init_collection_process(
+ LibOverrideGroupTagData *data, Collection *collection)
+{
+ LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
+ Object *ob = collection_object->ob;
+ if (!ID_IS_LINKED(ob)) {
+ continue;
+ }
+
+ LinkNodePair **collections_linkedlist_p;
+ if (!BLI_ghash_ensure_p(
+ data->linked_object_to_instantiating_collections, ob, &collections_linkedlist_p)) {
+ *collections_linkedlist_p = BLI_memarena_calloc(data->mem_arena,
+ sizeof(**collections_linkedlist_p));
+ }
+ BLI_linklist_append_arena(*collections_linkedlist_p, collection, data->mem_arena);
+ }
+}
+
+/* Initialize complex data, `data` is expected to be already initialized with basic pointers and
+ * other simple data.
+ *
+ * NOTE: Currently creates a mapping from linked object to all of their instantiating collections
+ * (as returned by #BKE_collection_object_find). */
+static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGroupTagData *data)
+{
+ data->mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ data->linked_object_to_instantiating_collections = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ if (data->scene != NULL) {
+ lib_override_group_tag_data_object_to_collection_init_collection_process(
+ data, data->scene->master_collection);
+ }
+ LISTBASE_FOREACH (Collection *, collection, &data->bmain->collections) {
+ lib_override_group_tag_data_object_to_collection_init_collection_process(data, collection);
+ }
+}
+
+static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data)
+{
+ BLI_ghash_free(data->linked_object_to_instantiating_collections, NULL, NULL);
+ BLI_memarena_free(data->mem_arena);
+ memset(data, 0, sizeof(*data));
+}
+
/* Tag all IDs in dependency relationships within an override hierarchy/group.
*
* Requires existing `Main.relations`.
@@ -599,7 +624,6 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
{
Main *bmain = data->bmain;
- Scene *scene = data->scene;
ID *id_root = data->id_root;
const bool is_resync = data->is_resync;
BLI_assert(!data->is_override);
@@ -637,18 +661,26 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
Collection *instantiating_collection_override_candidate = NULL;
/* Loop over all collections instantiating the object, if we already have a 'locale' one we
* have nothing to do, otherwise try to find a 'linked' one that we can override too. */
- while ((instantiating_collection = BKE_collection_object_find(
- bmain, scene, instantiating_collection, ob)) != NULL) {
- /* In (recursive) resync case, if a collection of a 'parent' lib instantiates the linked
- * object, it is also fine. */
- if (!ID_IS_LINKED(instantiating_collection) ||
- (is_resync && ID_IS_LINKED(id_root) &&
- instantiating_collection->id.lib->temp_index < id_root->lib->temp_index)) {
- break;
- }
- if (ID_IS_LINKED(instantiating_collection) &&
- (!is_resync || instantiating_collection->id.lib == id_root->lib)) {
- instantiating_collection_override_candidate = instantiating_collection;
+ LinkNodePair *instantiating_collection_linklist = BLI_ghash_lookup(
+ data->linked_object_to_instantiating_collections, ob);
+ if (instantiating_collection_linklist != NULL) {
+ for (LinkNode *instantiating_collection_linknode =
+ instantiating_collection_linklist->list;
+ instantiating_collection_linknode != NULL;
+ instantiating_collection_linknode = instantiating_collection_linknode->next) {
+ instantiating_collection = instantiating_collection_linknode->link;
+ /* In (recursive) resync case, if a collection of a 'parent' lib instantiates the
+ * linked object, it is also fine. */
+ if (!ID_IS_LINKED(instantiating_collection) ||
+ (is_resync && ID_IS_LINKED(id_root) &&
+ instantiating_collection->id.lib->temp_index < id_root->lib->temp_index)) {
+ break;
+ }
+ if (ID_IS_LINKED(instantiating_collection) &&
+ (!is_resync || instantiating_collection->id.lib == id_root->lib)) {
+ instantiating_collection_override_candidate = instantiating_collection;
+ }
+ instantiating_collection = NULL;
}
}
@@ -751,12 +783,14 @@ static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_roo
.missing_tag = LIB_TAG_MISSING,
.is_override = false,
.is_resync = false};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
return BKE_lib_override_library_create_from_tag(bmain, id_root->lib, false);
}
@@ -890,24 +924,6 @@ static void lib_override_library_create_post_process(Main *bmain,
BLI_gset_free(all_objects_in_scene, NULL);
}
-/**
- * Advanced 'smart' function to create fully functional overrides.
- *
- * \note Currently it only does special things if given \a id_root is an object or collection, more
- * specific behaviors may be added in the future for other ID types.
- *
- * \note It will override all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at
- * its beginning, so caller code can add extra data-blocks to be overridden as well.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \param id_root: The root ID to create an override from.
- * \param id_reference: Some reference ID used to do some post-processing after overrides have been
- * created, may be NULL. Typically, the Empty object instantiating the linked collection we
- * override, currently.
- * \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
- * \return true if override was successfully created.
- */
bool BKE_lib_override_library_create(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -942,9 +958,6 @@ bool BKE_lib_override_library_create(Main *bmain,
return success;
}
-/**
- * Create a library override template.
- */
bool BKE_lib_override_library_template_create(struct ID *id)
{
if (ID_IS_LINKED(id)) {
@@ -958,16 +971,6 @@ bool BKE_lib_override_library_template_create(struct ID *id)
return true;
}
-/**
- * Convert a given proxy object into a library override.
- *
- * \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to
- * actually convert the proxy itself into an override first.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \return true if override was successfully created.
- */
bool BKE_lib_override_library_proxy_convert(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1039,14 +1042,6 @@ static void lib_override_library_proxy_convert_do(Main *bmain,
}
}
-/**
- * Convert all proxy objects into library overrides.
- *
- * \note Only affects local proxies, linked ones are not affected.
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- */
void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports)
{
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
@@ -1086,15 +1081,6 @@ void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadRepor
}
}
-/**
- * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked
- * data, from an existing override hierarchy.
- *
- * \param id_root: The root liboverride ID to resync from.
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- * \return true if override was successfully resynced.
- */
bool BKE_lib_override_library_resync(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1125,6 +1111,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
.missing_tag = LIB_TAG_MISSING,
.is_override = true,
.is_resync = true};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
@@ -1215,6 +1202,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
/* Make new override from linked data. */
/* Note that this call also remaps all pointers of tagged IDs from old override IDs to new
@@ -1607,6 +1595,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
/* Detect all linked data that would need to be overridden if we had to create an override from
* those used by current existing overrides. */
+ LibOverrideGroupTagData data = {.bmain = bmain,
+ .scene = scene,
+ .id_root = NULL,
+ .tag = LIB_TAG_DOIT,
+ .missing_tag = LIB_TAG_MISSING,
+ .is_override = false,
+ .is_resync = true};
+ lib_override_group_tag_data_object_to_collection_init(&data);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
@@ -1617,19 +1613,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = scene,
- .id_root = id->override_library->reference,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = false,
- .is_resync = true};
+ data.id_root = id->override_library->reference;
lib_override_linked_group_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
lib_override_hierarchy_dependencies_recursive_tag(&data);
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
}
FOREACH_MAIN_ID_END;
+ lib_override_group_tag_data_clear(&data);
/* Now check existing overrides, those needing resync will be the one either already tagged as
* such, or the one using linked data that is now tagged as needing override. */
@@ -1801,23 +1792,6 @@ static int lib_override_libraries_index_define(Main *bmain)
return library_indirect_level_max;
}
-/**
- * Detect and handle required resync of overrides data, when relations between reference linked IDs
- * have changed.
- *
- * This is a fairly complex and costly operation, typically it should be called after
- * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases.
- *
- * This function will first detect the remaining cases requiring a resync (namely, either when an
- * existing linked ID that did not require to be overridden before now would be, or when new IDs
- * are added to the hierarchy).
- *
- * Then it will handle the resync of necessary IDs (through calls to
- * #BKE_lib_override_library_resync).
- *
- * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
- * which case \a scene's master collection children hierarchy is used instead).
- */
void BKE_lib_override_library_main_resync(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1866,14 +1840,6 @@ void BKE_lib_override_library_main_resync(Main *bmain,
}
}
-/**
- * Advanced 'smart' function to delete library overrides (including their existing override
- * hierarchy) and remap their usages to their linked reference IDs.
- *
- * \note All IDs tagged with `LIB_TAG_DOIT` will be deleted.
- *
- * \param id_root: The root liboverride ID to delete.
- */
void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
@@ -1887,9 +1853,11 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
.missing_tag = LIB_TAG_MISSING,
.is_override = true,
.is_resync = false};
+ lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data);
BKE_main_relations_free(bmain);
+ lib_override_group_tag_data_clear(&data);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -1911,11 +1879,6 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
}
-/** Make given ID fully local.
- *
- * \note Only differs from lower-level `BKE_lib_override_library_free in infamous embedded ID
- * cases.
- */
void BKE_lib_override_library_make_local(ID *id)
{
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
@@ -1972,9 +1935,6 @@ BLI_INLINE GHash *override_library_rna_path_mapping_ensure(IDOverrideLibrary *ov
return override_runtime->rna_path_to_override_properties;
}
-/**
- * Find override property from given RNA path, if it exists.
- */
IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibrary *override,
const char *rna_path)
{
@@ -1982,9 +1942,6 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibr
return BLI_ghash_lookup(override_runtime, rna_path);
}
-/**
- * Find override property from given RNA path, or create it if it does not exist.
- */
IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibrary *override,
const char *rna_path,
bool *r_created)
@@ -2010,13 +1967,6 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
return op;
}
-/**
- * Get the RNA-property matching the \a library_prop override property. Used for UI to query
- * additional data about the overridden property (e.g. UI name).
- *
- * \param idpoin: Pointer to the override ID.
- * \param library_prop: The library override property to find the matching RNA property for.
- */
bool BKE_lib_override_rna_property_find(PointerRNA *idpoin,
const IDOverrideLibraryProperty *library_prop,
PointerRNA *r_override_poin,
@@ -2053,9 +2003,6 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
BLI_freelistN(&op->operations);
}
-/**
- * Remove and free given \a override_property from given ID \a override.
- */
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
IDOverrideLibraryProperty *override_property)
{
@@ -2069,9 +2016,6 @@ void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
BLI_freelinkN(&override->properties, override_property);
}
-/**
- * Find override property operation from given sub-item(s), if it exists.
- */
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
IDOverrideLibraryProperty *override_property,
const char *subitem_refname,
@@ -2158,9 +2102,6 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
return NULL;
}
-/**
- * Find override property operation from given sub-item(s), or create it if it does not exist.
- */
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
IDOverrideLibraryProperty *override_property,
const short operation,
@@ -2227,9 +2168,6 @@ void lib_override_library_property_operation_clear(IDOverrideLibraryPropertyOper
}
}
-/**
- * Remove and free given \a override_property_operation from given ID \a override_property.
- */
void BKE_lib_override_library_property_operation_delete(
IDOverrideLibraryProperty *override_property,
IDOverrideLibraryPropertyOperation *override_property_operation)
@@ -2238,9 +2176,6 @@ void BKE_lib_override_library_property_operation_delete(
BLI_freelinkN(&override_property->operations, override_property_operation);
}
-/**
- * Validate that required data for a given operation are available.
- */
bool BKE_lib_override_library_property_operation_operands_validate(
struct IDOverrideLibraryPropertyOperation *override_property_operation,
struct PointerRNA *ptr_dst,
@@ -2278,7 +2213,6 @@ bool BKE_lib_override_library_property_operation_operands_validate(
return true;
}
-/** Check against potential \a bmain. */
void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *reports)
{
if (id->override_library == NULL) {
@@ -2312,7 +2246,6 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *
}
}
-/** Check against potential \a bmain. */
void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
{
ID *id;
@@ -2325,16 +2258,6 @@ void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
FOREACH_MAIN_ID_END;
}
-/**
- * Check that status of local data-block is still valid against current reference one.
- *
- * It means that all overridable, but not overridden, properties' local values must be equal to
- * reference ones. Clears #LIB_TAG_OVERRIDE_OK if they do not.
- *
- * This is typically used to detect whether some property has been changed in local and a new
- * #IDOverrideProperty (of #IDOverridePropertyOperation) has to be added.
- *
- * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
@@ -2384,16 +2307,6 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
return true;
}
-/**
- * Check that status of reference data-block is still valid against current local one.
- *
- * It means that all non-overridden properties' local values must be equal to reference ones.
- * Clears LIB_TAG_OVERRIDE_OK if they do not.
- *
- * This is typically used to detect whether some reference has changed and local
- * needs to be updated against it.
- *
- * \return true if status is OK, false otherwise. */
bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
@@ -2450,20 +2363,6 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
return true;
}
-/**
- * Compare local and reference data-blocks and create new override operations as needed,
- * or reset to reference values if overriding is not allowed.
- *
- * \note Defining override operations is only mandatory before saving a `.blend` file on disk
- * (not for undo!).
- * Knowing that info at runtime is only useful for UI/UX feedback.
- *
- * \note This is by far the biggest operation (the more time-consuming) of the three so far,
- * since it has to go over all properties in depth (all overridable ones at least).
- * Generating differential values and applying overrides are much cheaper.
- *
- * \return true if any library operation was created.
- */
bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
{
BLI_assert(local->override_library != NULL);
@@ -2540,7 +2439,6 @@ static void lib_override_library_operations_create_cb(TaskPool *__restrict pool,
}
}
-/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool force_auto)
{
ID *id;
@@ -2669,7 +2567,6 @@ static bool lib_override_library_id_reset_do(Main *bmain, ID *id_root)
return was_op_deleted;
}
-/** Reset all overrides in given \a id_root, while preserving ID relations. */
void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -2728,7 +2625,6 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i
}
}
-/** Reset all overrides in given \a id_root and its dependencies, while preserving ID relations. */
void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root)
{
BKE_main_relations_create(bmain, 0);
@@ -2749,7 +2645,6 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root)
FOREACH_MAIN_ID_END;
}
-/** Set or clear given tag in all operations in that override property data. */
void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
const short tag,
const bool do_set)
@@ -2773,7 +2668,6 @@ void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *o
}
}
-/** Set or clear given tag in all properties and operations in that override data. */
void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
const short tag,
const bool do_set)
@@ -2785,7 +2679,6 @@ void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
}
}
-/** Set or clear given tag in all properties and operations in that Main's ID override data. */
void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set)
{
ID *id;
@@ -2798,7 +2691,6 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons
FOREACH_MAIN_ID_END;
}
-/** Remove all tagged-as-unused properties and operations from that ID override data. */
void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
{
if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
@@ -2818,7 +2710,6 @@ void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
}
}
-/** Remove all tagged-as-unused properties and operations from that Main's ID override data. */
void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
{
ID *id;
@@ -2839,7 +2730,6 @@ static void lib_override_id_swap(Main *bmain, ID *id_local, ID *id_temp)
id_local->tag |= (id_temp->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC);
}
-/** Update given override from its reference (re-applying overridden properties). */
void BKE_lib_override_library_update(Main *bmain, ID *local)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
@@ -2964,7 +2854,6 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
DEG_relations_tag_update(bmain);
}
-/** Update all overrides from given \a bmain. */
void BKE_lib_override_library_main_update(Main *bmain)
{
ID *id;
@@ -2985,7 +2874,6 @@ void BKE_lib_override_library_main_update(Main *bmain)
G_MAIN = orig_gmain;
}
-/** In case an ID is used by another liboverride ID, user may not be allowed to delete it. */
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id)
{
if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
@@ -3026,17 +2914,11 @@ bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID
* exact same data as "desired" ones (kind of "baked" data-blocks).
*/
-/** Initialize an override storage. */
OverrideLibraryStorage *BKE_lib_override_library_operations_store_init(void)
{
return BKE_main_new();
}
-/**
- * Generate suitable 'write' data (this only affects differential override operations).
- *
- * Note that \a local ID is no more modified by this call,
- * all extra data are stored in its temp \a storage_id copy. */
ID *BKE_lib_override_library_operations_store_start(Main *bmain,
OverrideLibraryStorage *override_storage,
ID *local)
@@ -3101,10 +2983,6 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
return storage_id;
}
-/**
- * Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
- * original state.
- */
void BKE_lib_override_library_operations_store_end(
OverrideLibraryStorage *UNUSED(override_storage), ID *local)
{
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 74750a9b61a..4ad0186f9b5 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -76,8 +76,6 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
-/** Check whether current iteration over ID usages should be stopped or not.
- * \return true if the iteration should be stopped, false otherwise. */
bool BKE_lib_query_foreachid_iter_stop(LibraryForeachIDData *data)
{
return (data->status & IDWALK_STOP) != 0;
@@ -162,10 +160,6 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void
BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag);
}
-/** Process embedded ID pointers (root nodetrees, master collections, ...).
- *
- * Those require specific care, since they are technically sub-data of their owner, yet in some
- * cases they still behave as regular IDs. */
void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
{
/* Needed e.g. for callbacks handling relationships. This call shall be absolutely read-only. */
@@ -367,18 +361,12 @@ static bool library_foreach_ID_link(Main *bmain,
#undef CALLBACK_INVOKE
}
-/**
- * Loop over all of the ID's this data-block links to.
- */
void BKE_library_foreach_ID_link(
Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
{
library_foreach_ID_link(bmain, NULL, id, callback, user_data, flag, NULL);
}
-/**
- * re-usable function, use when replacing ID's
- */
void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
{
if (cb_flag & IDWALK_CB_USER) {
@@ -390,12 +378,6 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
}
}
-/**
- * Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used.
- *
- * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above,
- * quite useful to reduce useless iterations in some cases.
- */
bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
{
/* any type of ID can be used in custom props. */
@@ -567,16 +549,6 @@ static int foreach_libblock_id_users_callback(LibraryIDLinkCallbackData *cb_data
return IDWALK_RET_NOP;
}
-/**
- * Return the number of times given \a id_user uses/references \a id_used.
- *
- * \note This only checks for pointer references of an ID, shallow usages
- * (like e.g. by RNA paths, as done for FCurves) are not detected at all.
- *
- * \param id_user: the ID which is supposed to use (reference) \a id_used.
- * \param id_used: the ID which is supposed to be used (referenced) by \a id_user.
- * \return the number of direct usages/references of \a id_used by \a id_user.
- */
int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
{
IDUsersIter iter;
@@ -625,26 +597,16 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
return is_defined;
}
-/**
- * Check whether given ID is used locally (i.e. by another non-linked ID).
- */
bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
{
return library_ID_is_used(bmain, idv, false);
}
-/**
- * Check whether given ID is used indirectly (i.e. by another linked ID).
- */
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
{
return library_ID_is_used(bmain, idv, true);
}
-/**
- * Combine #BKE_library_ID_is_locally_used() and #BKE_library_ID_is_indirectly_used()
- * in a single call.
- */
void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
{
IDUsersIter iter;
@@ -759,21 +721,6 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain,
}
}
-/**
- * Tag all unused IDs (a.k.a 'orphaned').
- *
- * By default only tag IDs with `0` user count.
- * If `do_tag_recursive` is set, it will check dependencies to detect all IDs that are not actually
- * used in current file, including 'archipelagos` (i.e. set of IDs referencing each other in
- * loops, but without any 'external' valid usages.
- *
- * Valid usages here are defined as ref-counting usages, which are not towards embedded or
- * loop-back data.
- *
- * \param r_num_tagged: If non-NULL, must be a zero-initialized array of #INDEX_ID_MAX integers.
- * Number of tagged-as-unused IDs is then set for each type, and as total in
- * #INDEX_ID_NULL item.
- */
void BKE_lib_query_unused_ids_tag(Main *bmain,
const int tag,
const bool do_local_ids,
@@ -838,15 +785,6 @@ static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackD
return IDWALK_RET_NOP;
}
-/**
- * Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly)
- * in any way by any local data), including complex cases like 'linked archipelagoes', i.e.
- * linked data-blocks that use each other in loops,
- * which prevents their deletion by 'basic' usage checks.
- *
- * \param do_init_tag: if \a true, all linked data are checked, if \a false,
- * only linked data-blocks already tagged with #LIB_TAG_DOIT are checked.
- */
void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
{
ID *id;
@@ -876,14 +814,6 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
}
}
-/**
- * Untag linked data blocks used by other untagged linked data-blocks.
- * Used to detect data-blocks that we can forcefully make local
- * (instead of copying them to later get rid of original):
- * All data-blocks we want to make local are tagged by caller,
- * after this function has ran caller knows data-blocks still tagged can directly be made local,
- * since they are only used by other data-blocks that will also be made fully local.
- */
void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
{
ListBase *lb_array[INDEX_ID_MAX];
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 014c923f04f..3cea0de32ee 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -456,10 +456,6 @@ static void libblock_remap_data(
#endif
}
-/**
- * Replace all references in given Main to \a old_id by \a new_id
- * (if \a new_id is NULL, it unlinks \a old_id).
- */
void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
{
IDRemap id_remap_data;
@@ -565,13 +561,6 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r
BKE_main_unlock(bmain);
}
-/**
- * Unlink given \a id from given \a bmain
- * (does not touch to indirect, i.e. library, usages of the ID).
- *
- * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by
- * #LIB_TAG_DOIT flag (quite obviously, 'non-NULL' usages can never be unlinked by this function).
- */
void BKE_libblock_unlink(Main *bmain,
void *idv,
const bool do_flag_never_null,
@@ -587,16 +576,6 @@ void BKE_libblock_unlink(Main *bmain,
BKE_main_unlock(bmain);
}
-/**
- * Similar to libblock_remap, but only affects IDs used by given \a idv ID.
- *
- * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
- * in which case all ID usages by given \a idv will be cleared.
- * \param us_min_never_null: If \a true and new_id is NULL,
- * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented
- * (needed when given \a idv is going to be deleted right after being unlinked).
- */
-/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
/* XXX Arg! Naming... :(
* _relink? avoids confusion with _remap, but is confusing with _unlink
* _remap_used_ids?
@@ -604,9 +583,13 @@ void BKE_libblock_unlink(Main *bmain,
* BKE_id_remap maybe?
* ... sigh
*/
+
void BKE_libblock_relink_ex(
Main *bmain, void *idv, void *old_idv, void *new_idv, const short remap_flags)
{
+
+ /* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
+
ID *id = idv;
ID *old_id = old_idv;
ID *new_id = new_idv;
@@ -710,15 +693,6 @@ static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
bmain, id, id_relink_to_newid_looper, POINTER_FROM_INT(remap_flag), 0);
}
-/**
- * Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
- * in the dependency tree of IDs for all data-blocks tagged with `LIB_TAG_NEW`.
- *
- * NOTE: `LIB_TAG_NEW` is cleared
- *
- * Very specific usage, not sure we'll keep it on the long run,
- * currently only used in Object/Collection duplication code...
- */
void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
{
if (ID_IS_LINKED(id)) {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 1dba353d8ce..c97b003d241 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -36,6 +36,7 @@
#include "BLT_translation.h"
+#include "BKE_bpath.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
@@ -60,6 +61,22 @@ static void library_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lib->parent, IDWALK_CB_NEVER_SELF);
}
+static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Library *lib = (Library *)id;
+
+ /* FIXME: Find if we should respect #BKE_BPATH_FOREACH_PATH_SKIP_PACKED here, and if not, explain
+ * why. */
+ if (lib->packedfile !=
+ NULL /*&& (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0 */) {
+ return;
+ }
+
+ if (BKE_bpath_foreach_path_fixed_process(bpath_data, lib->filepath)) {
+ BKE_library_filepath_set(bpath_data->bmain, lib, lib->filepath);
+ }
+}
+
IDTypeInfo IDType_ID_LI = {
.id_code = ID_LI,
.id_filter = 0,
@@ -69,6 +86,7 @@ IDTypeInfo IDType_ID_LI = {
.name_plural = "libraries",
.translation_context = BLT_I18NCONTEXT_ID_LIBRARY,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -76,6 +94,7 @@ IDTypeInfo IDType_ID_LI = {
.make_local = NULL,
.foreach_id = library_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = library_foreach_path,
.owner_get = NULL,
.blend_write = NULL,
@@ -108,7 +127,7 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
*/
/* Never make paths relative to parent lib - reading code (blenloader) always set *all*
* `lib->filepath` relative to current main, not to their parent for indirectly linked ones. */
- const char *basepath = BKE_main_blendfile_path(bmain);
- BLI_path_abs(lib->filepath_abs, basepath);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
+ BLI_path_abs(lib->filepath_abs, blendfile_path);
}
}
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index 05e8d4fe978..e73cda7e24d 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -195,6 +195,7 @@ IDTypeInfo IDType_ID_LA = {
.name_plural = "lights",
.translation_context = BLT_I18NCONTEXT_ID_LIGHT,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = light_init_data,
.copy_data = light_copy_data,
@@ -202,6 +203,7 @@ IDTypeInfo IDType_ID_LA = {
.make_local = NULL,
.foreach_id = light_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = light_blend_write,
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 57ad6695db4..035e41815e5 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -92,6 +92,7 @@ IDTypeInfo IDType_ID_LP = {
.name_plural = "lightprobes",
.translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = lightprobe_init_data,
.copy_data = NULL,
@@ -99,6 +100,7 @@ IDTypeInfo IDType_ID_LP = {
.make_local = NULL,
.foreach_id = lightprobe_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = lightprobe_blend_write,
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 3c305d1fb3f..ac0dbcb715d 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -754,6 +754,7 @@ IDTypeInfo IDType_ID_LS = {
.name_plural = "linestyles",
.translation_context = BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = linestyle_init_data,
.copy_data = linestyle_copy_data,
@@ -761,6 +762,7 @@ IDTypeInfo IDType_ID_LS = {
.make_local = NULL,
.foreach_id = linestyle_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = linestyle_blend_write,
@@ -1910,10 +1912,6 @@ int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineSt
return 0;
}
-/**
- * Reinsert \a modifier in modifier list with an offset of \a direction.
- * \return if position of \a modifier has changed.
- */
bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier,
int direction)
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index a5de0bc99c8..64731be57ac 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -205,7 +205,6 @@ void BKE_main_free(Main *mainvar)
MEM_freeN(mainvar);
}
-/* Check whether given `bmain` is empty or contains some IDs. */
bool BKE_main_is_empty(struct Main *bmain)
{
ID *id_iter;
@@ -278,7 +277,6 @@ static int main_relations_create_idlink_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
-/** Generate the mappings between used IDs and their users, and vice-versa. */
void BKE_main_relations_create(Main *bmain, const short flag)
{
if (bmain->relations != NULL) {
@@ -326,7 +324,6 @@ void BKE_main_relations_free(Main *bmain)
}
}
-/** Set or clear given `tag` in all relation entries of given `bmain`. */
void BKE_main_relations_tag_set(struct Main *bmain,
const eMainIDRelationsEntryTags tag,
const bool value)
@@ -350,12 +347,6 @@ void BKE_main_relations_tag_set(struct Main *bmain,
BLI_ghashIterator_free(gh_iter);
}
-/**
- * Create a GSet storing all IDs present in given \a bmain, by their pointers.
- *
- * \param gset: If not NULL, given GSet will be extended with IDs from given \a bmain,
- * instead of creating a new one.
- */
GSet *BKE_main_gset_create(Main *bmain, GSet *gset)
{
if (gset == NULL) {
@@ -404,12 +395,6 @@ static bool lib_weak_key_cmp(const void *a, const void *b)
STREQ(string_pair_a->id_name, string_pair_b->id_name));
}
-/**
- * Generate a mapping between 'library path' of an ID (as a pair (relative blend file path, id
- * name)), and a current local ID, if any.
- *
- * This uses the information stored in `ID.library_weak_reference`.
- */
GHash *BKE_main_library_weak_reference_create(Main *bmain)
{
GHash *library_weak_reference_mapping = BLI_ghash_new(
@@ -442,24 +427,11 @@ GHash *BKE_main_library_weak_reference_create(Main *bmain)
return library_weak_reference_mapping;
}
-/**
- * Destroy the data generated by #BKE_main_library_weak_reference_create.
- */
void BKE_main_library_weak_reference_destroy(GHash *library_weak_reference_mapping)
{
BLI_ghash_free(library_weak_reference_mapping, MEM_freeN, NULL);
}
-/**
- * Search for a local ID matching the given linked ID reference.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID
- * type.
- */
ID *BKE_main_library_weak_reference_search_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name)
@@ -469,16 +441,6 @@ ID *BKE_main_library_weak_reference_search_item(GHash *library_weak_reference_ma
return (ID *)BLI_ghash_lookup(library_weak_reference_mapping, &key);
}
-/**
- * Add the given ID weak library reference to given local ID and the runtime mapping.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param new_id: New local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_add_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -507,21 +469,6 @@ void BKE_main_library_weak_reference_add_item(GHash *library_weak_reference_mapp
*id_p = new_id;
}
-/**
- * Update the status of the given ID weak library reference in current local IDs and the runtime
- * mapping.
- *
- * This effectively transfers the 'ownership' of the given weak reference from `old_id` to
- * `new_id`.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param old_id: Existing local ID matching given weak reference.
- * \param new_id: New local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_update_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -545,16 +492,6 @@ void BKE_main_library_weak_reference_update_item(GHash *library_weak_reference_m
*id_p = new_id;
}
-/**
- * Remove the given ID weak library reference from the given local ID and the runtime mapping.
- *
- * \param library_weak_reference_mapping: the mapping data generated by
- * #BKE_main_library_weak_reference_create.
- * \param library_relative_path: the path of a blend file library (relative to current working
- * one).
- * \param library_id_name: the full ID name, including the leading two chars encoding the ID type.
- * \param old_id: Existing local ID matching given weak reference.
- */
void BKE_main_library_weak_reference_remove_item(GHash *library_weak_reference_mapping,
const char *library_filepath,
const char *library_id_name,
@@ -572,13 +509,6 @@ void BKE_main_library_weak_reference_remove_item(GHash *library_weak_reference_m
MEM_SAFE_FREE(old_id->library_weak_reference);
}
-/**
- * Generates a raw .blend file thumbnail data from given image.
- *
- * \param bmain: If not NULL, also store generated data in this Main.
- * \param img: ImBuf image to generate thumbnail data from.
- * \return The generated .blend file raw thumbnail data.
- */
BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
{
BlendThumbnail *data = NULL;
@@ -603,13 +533,6 @@ BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
return data;
}
-/**
- * Generates an image from raw .blend file thumbnail \a data.
- *
- * \param bmain: Use this bmain->blen_thumb data if given \a data is NULL.
- * \param data: Raw .blend file thumbnail data.
- * \return An ImBuf from given data, or NULL if invalid.
- */
ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
{
ImBuf *img = NULL;
@@ -626,9 +549,6 @@ ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
return img;
}
-/**
- * Generates an empty (black) thumbnail for given Main.
- */
void BKE_main_thumbnail_create(struct Main *bmain)
{
MEM_SAFE_FREE(bmain->blen_thumb);
@@ -638,28 +558,16 @@ void BKE_main_thumbnail_create(struct Main *bmain)
bmain->blen_thumb->height = BLEN_THUMB_SIZE;
}
-/**
- * Return filepath of given \a main.
- */
const char *BKE_main_blendfile_path(const Main *bmain)
{
- return bmain->name;
+ return bmain->filepath;
}
-/**
- * Return filepath of global main #G_MAIN.
- *
- * \warning Usage is not recommended,
- * you should always try to get a valid Main pointer from context...
- */
const char *BKE_main_blendfile_path_from_global(void)
{
return BKE_main_blendfile_path(G_MAIN);
}
-/**
- * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type.
- */
ListBase *which_libbase(Main *bmain, short type)
{
switch ((ID_Type)type) {
@@ -747,18 +655,6 @@ ListBase *which_libbase(Main *bmain, short type)
return NULL;
}
-/**
- * Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]`
- * array, and return the number of those for convenience.
- *
- * This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists
- * in turn), without worrying about block types.
- *
- * \param lb: Array of lists #INDEX_ID_MAX in length.
- *
- * \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>`
- * enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h`
- */
int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/])
{
/* Libraries may be accessed from pretty much any other ID. */
diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c
index c75365a788d..38523f22aad 100644
--- a/source/blender/blenkernel/intern/main_idmap.c
+++ b/source/blender/blenkernel/intern/main_idmap.c
@@ -88,18 +88,6 @@ static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id
return NULL;
}
-/**
- * Generate mapping from ID type/name to ID pointer for given \a bmain.
- *
- * \note When used during undo/redo, there is no guaranty that ID pointers from UI area
- * are not pointing to freed memory (when some IDs have been deleted). To avoid crashes
- * in those cases, one can provide the 'old' (aka current) Main database as reference.
- * #BKE_main_idmap_lookup_id will then check that given ID does exist in \a old_bmain
- * before trying to use it.
- *
- * \param create_valid_ids_set: If \a true, generate a reference to prevent freed memory accesses.
- * \param old_bmain: If not NULL, its IDs will be added the valid references set.
- */
struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
const bool create_valid_ids_set,
struct Main *old_bmain,
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 1d3ebaac303..6f498c5c9e7 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -255,6 +255,7 @@ IDTypeInfo IDType_ID_MSK = {
.name_plural = "masks",
.translation_context = BLT_I18NCONTEXT_ID_MASK,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = mask_copy_data,
@@ -262,6 +263,7 @@ IDTypeInfo IDType_ID_MSK = {
.make_local = NULL,
.foreach_id = mask_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = mask_blend_write,
@@ -371,7 +373,6 @@ MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name)
return masklay;
}
-/* NOTE: may still be hidden, caller needs to check. */
MaskLayer *BKE_mask_layer_active(Mask *mask)
{
return BLI_findlink(&mask->masklayers, mask->masklay_act);
@@ -787,12 +788,11 @@ BLI_INLINE void orthogonal_direction_get(const float vec[2], float result[2])
normalize_v2(result);
}
-/* TODO(sergey): This function will re-calculate loads of stuff again and again
- * when differentiating feather points. This might be easily cached
- * in the callee function for this case.
- */
void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2])
{
+ /* TODO(sergey): This function will re-calculate loads of stuff again and again
+ * when differentiating feather points. This might be easily cached
+ * in the callee function for this case. */
MaskSplinePoint *point_prev, *point_next;
@@ -1132,7 +1132,6 @@ MaskSpline *BKE_mask_spline_copy(const MaskSpline *spline)
return nspline;
}
-/* NOTE: Does NOT add to the list. */
MaskLayerShape *BKE_mask_layer_shape_alloc(MaskLayer *masklay, const int frame)
{
MaskLayerShape *masklay_shape;
@@ -1156,8 +1155,6 @@ void BKE_mask_layer_shape_free(MaskLayerShape *masklay_shape)
MEM_freeN(masklay_shape);
}
-/** \brief Free all animation keys for a mask layer
- */
void BKE_mask_layer_free_shapes(MaskLayer *masklay)
{
MaskLayerShape *masklay_shape;
@@ -1245,7 +1242,6 @@ void BKE_mask_coord_from_image(Image *image, ImageUser *iuser, float r_co[2], co
BKE_mask_coord_from_frame(r_co, co, frame_size);
}
-/* as above but divide */
void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2])
{
if (frame_size[0] == frame_size[1]) {
@@ -1428,8 +1424,6 @@ void BKE_mask_get_handle_point_adjacent(MaskSpline *spline,
*r_point_next = mask_spline_point_next(spline, points_array, point);
}
-/* calculates the tangent of a point by its previous and next
- * (ignoring handles - as if its a poly line) */
void BKE_mask_calc_tangent_polyline(MaskSpline *spline, MaskSplinePoint *point, float t[2])
{
float tvec_a[2], tvec_b[2];
@@ -1513,11 +1507,6 @@ void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline,
}
}
-/**
- * \brief Resets auto handles even for non-auto bezier points
- *
- * Useful for giving sane defaults.
- */
void BKE_mask_calc_handle_point_auto(MaskSpline *spline,
MaskSplinePoint *point,
const bool do_recalc_length)
@@ -1640,7 +1629,6 @@ static void mask_layer_shape_to_mask_point(BezTriple *bezt,
bezt->radius = fp[7];
}
-/* these functions match. copy is swapped */
void BKE_mask_layer_shape_from_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape)
{
int tot = BKE_mask_layer_shape_totvert(masklay);
@@ -1696,7 +1684,6 @@ BLI_INLINE void interp_v2_v2v2_flfl(
target[1] = s * a[1] + t * b[1];
}
-/* linear interpolation only */
void BKE_mask_layer_shape_to_mask_interp(MaskLayer *masklay,
MaskLayerShape *masklay_shape_a,
MaskLayerShape *masklay_shape_b,
@@ -1757,9 +1744,6 @@ MaskLayerShape *BKE_mask_layer_shape_find_frame(MaskLayer *masklay, const int fr
return NULL;
}
-/**
- * When returning 2 - the frame isn't found but before/after frames are.
- */
int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay,
const float frame,
MaskLayerShape **r_masklay_shape_a,
@@ -1922,7 +1906,6 @@ static void interp_weights_uv_v2_apply(const float uv[2],
r_pt[1] += dvec[0] * uv[1];
}
-/* When a new points added - resize all shape-key array. */
void BKE_mask_layer_shape_changed_add(MaskLayer *masklay,
int index,
bool do_init,
@@ -2017,7 +2000,6 @@ void BKE_mask_layer_shape_changed_add(MaskLayer *masklay,
}
}
-/* move array to account for removed point */
void BKE_mask_layer_shape_changed_remove(MaskLayer *masklay, int index, int count)
{
MaskLayerShape *masklay_shape;
@@ -2079,13 +2061,11 @@ static void mask_clipboard_free_ex(bool final_free)
}
}
-/* Free the clipboard. */
void BKE_mask_clipboard_free(void)
{
mask_clipboard_free_ex(true);
}
-/* Copy selected visible splines from the given layer to clipboard. */
void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
{
MaskSpline *spline;
@@ -2120,13 +2100,11 @@ void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
}
}
-/* Check clipboard is empty. */
bool BKE_mask_clipboard_is_empty(void)
{
return BLI_listbase_is_empty(&mask_clipboard.splines);
}
-/* Paste the contents of clipboard to given mask layer */
void BKE_mask_clipboard_paste_to_layer(Main *bmain, MaskLayer *mask_layer)
{
MaskSpline *spline;
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index 4584d9e527e..69fc7554eed 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -720,10 +720,6 @@ static float (*mask_spline_feather_differentiated_points_with_resolution__double
return feather;
}
-/**
- * values align with #BKE_mask_spline_differentiate_with_resolution
- * when \a resol arguments match.
- */
float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
MaskSpline *spline,
const unsigned int resol,
@@ -788,7 +784,6 @@ float (*BKE_mask_spline_feather_points(MaskSpline *spline, int *r_tot_feather_po
return feather;
}
-/* *** mask point functions which involve evaluation *** */
float *BKE_mask_point_segment_feather_diff(MaskSpline *spline,
MaskSplinePoint *point,
int width,
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 0c40a1b5078..b0876957620 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -1474,9 +1474,6 @@ static void maskrasterize_buffer_cb(void *__restrict userdata,
}
}
-/**
- * \brief Rasterize a buffer from a single mask (threaded execution).
- */
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
const unsigned int width,
const unsigned int height,
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1fac83c5665..d6035887790 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -261,6 +261,7 @@ IDTypeInfo IDType_ID_MA = {
.name_plural = "materials",
.translation_context = BLT_I18NCONTEXT_ID_MATERIAL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = material_init_data,
.copy_data = material_copy_data,
@@ -268,6 +269,7 @@ IDTypeInfo IDType_ID_MA = {
.make_local = NULL,
.foreach_id = material_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = material_blend_write,
@@ -387,7 +389,6 @@ short *BKE_object_material_len_p(Object *ob)
return NULL;
}
-/* same as above but for ID's */
Material ***BKE_id_material_array_p(ID *id)
{
/* ensure we don't try get materials from non-obdata */
@@ -726,13 +727,6 @@ static ID *get_evaluated_object_data_with_materials(Object *ob)
return data;
}
-/**
- * On evaluated objects the number of materials on an object and its data might go out of sync.
- * This is because during evaluation materials can be added/removed on the object data.
- *
- * For rendering or exporting we generally use the materials on the object data. However, some
- * material indices might be overwritten by the object.
- */
Material *BKE_object_material_get_eval(Object *ob, short act)
{
BLI_assert(DEG_is_evaluated_object(ob));
@@ -806,10 +800,6 @@ void BKE_id_material_eval_assign(ID *id, int slot, Material *material)
(*materials_ptr)[slot_index] = material;
}
-/**
- * Add an empty material slot if the id has no material slots. This material slot allows the
- * material to be overwritten by object-linked materials.
- */
void BKE_id_material_eval_ensure_default_slot(ID *id)
{
short *len_ptr = BKE_id_material_len_p(id);
@@ -1099,12 +1089,6 @@ void BKE_object_material_remap(Object *ob, const unsigned int *remap)
}
}
-/**
- * Calculate a material remapping from \a ob_src to \a ob_dst.
- *
- * \param remap_src_to_dst: An array the size of `ob_src->totcol`
- * where index values are filled in which map to \a ob_dst materials.
- */
void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst)
{
if (ob_src->totcol == 0) {
@@ -1153,9 +1137,6 @@ void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap
BLI_ghash_free(gh_mat_map, NULL, NULL);
}
-/**
- * Copy materials from evaluated geometry to the original geometry of an object.
- */
void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, ID *data_eval)
{
ID *data_orig = ob_orig->data;
@@ -1190,7 +1171,6 @@ void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, ID *data_e
BKE_object_materials_test(bmain, ob_orig, data_orig);
}
-/* XXX: this calls many more update calls per object then are needed, could be optimized. */
void BKE_object_material_array_assign(Main *bmain,
struct Object *ob,
struct Material ***matar,
@@ -1553,7 +1533,6 @@ bNode *BKE_texpaint_slot_material_find_node(Material *ma, short texpaint_slot)
return find_data.r_node;
}
-/* r_col = current value, col = new value, (fac == 0) is no change */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
{
float tmp, facm = 1.0f - fac;
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 48d31361eac..ac6b0a04def 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -189,6 +189,7 @@ IDTypeInfo IDType_ID_MB = {
.name_plural = "metaballs",
.translation_context = BLT_I18NCONTEXT_ID_METABALL,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = metaball_init_data,
.copy_data = metaball_copy_data,
@@ -196,6 +197,7 @@ IDTypeInfo IDType_ID_MB = {
.make_local = NULL,
.foreach_id = metaball_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = metaball_blend_write,
@@ -219,8 +221,6 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name)
return mb;
}
-/* most simple meta-element adding function
- * don't do context manipulation here (rna uses) */
MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
{
MetaElem *ml = MEM_callocN(sizeof(MetaElem), "metaelem");
@@ -267,13 +267,6 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
return ml;
}
-/**
- * Compute bounding box of all #MetaElem / #MetaBall
- *
- * Bounding box is computed from polygonized surface. \a ob is
- * basic meta-balls (with name `Meta` for example). All other meta-ball objects
- * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box.
- */
void BKE_mball_texspace_calc(Object *ob)
{
DispList *dl;
@@ -317,7 +310,6 @@ void BKE_mball_texspace_calc(Object *ob)
bb->flag &= ~BOUNDBOX_DIRTY;
}
-/** Return or compute bbox for given metaball object. */
BoundBox *BKE_mball_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_MBALL);
@@ -370,38 +362,29 @@ float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
return orcodata;
}
-/**
- * \brief Test, if \a ob is a basis meta-ball.
- *
- * It test last character of Object ID name. If last character
- * is digit it return 0, else it return 1.
- *
- *
- * Meta-Ball Basis Notes from Blender-2.5x
- * =======================================
- *
- * This is a can of worms.
- *
- * This really needs a rewrite/refactor its totally broken in anything other than basic cases
- * Multiple Scenes + Set Scenes & mixing meta-ball basis _should_ work but fails to update the
- * depsgraph on rename and linking into scenes or removal of basis meta-ball.
- * So take care when changing this code.
- *
- * Main idiot thing here is that the system returns #BKE_mball_basis_find()
- * objects which fail a #BKE_mball_is_basis() test.
- *
- * Not only that but the depsgraph and their areas depend on this behavior,
- * so making small fixes here isn't worth it.
- * - Campbell
- */
bool BKE_mball_is_basis(Object *ob)
{
- /* just a quick test */
+ /* Meta-Ball Basis Notes from Blender-2.5x
+ * =======================================
+ *
+ * NOTE(@campbellbarton): This is a can of worms.
+ *
+ * This really needs a rewrite/refactor its totally broken in anything other than basic cases
+ * Multiple Scenes + Set Scenes & mixing meta-ball basis _should_ work but fails to update the
+ * depsgraph on rename and linking into scenes or removal of basis meta-ball.
+ * So take care when changing this code.
+ *
+ * Main idiot thing here is that the system returns #BKE_mball_basis_find()
+ * objects which fail a #BKE_mball_is_basis() test.
+ *
+ * Not only that but the depsgraph and their areas depend on this behavior,
+ * so making small fixes here isn't worth it. */
+
+ /* Just a quick test. */
const int len = strlen(ob->id.name);
return (!isdigit(ob->id.name[len - 1]));
}
-/* return nonzero if ob1 is a basis mball for ob */
bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
{
int basis1nr, basis2nr;
@@ -454,13 +437,6 @@ bool BKE_mball_is_any_unselected(const MetaBall *mb)
return false;
}
-/**
- * \brief copy some properties from object to other meta-ball object with same base name
- *
- * When some properties (wire-size, threshold, update flags) of meta-ball are changed, then this
- * properties are copied to all meta-balls in same "group" (meta-balls with same base name:
- * `MBall`, `MBall.001`, `MBall.002`, etc). The most important is to copy properties to the base
- * meta-ball, because this meta-ball influence polygonization of meta-balls. */
void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
Scene *sce_iter = scene;
@@ -499,14 +475,6 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object)
}
}
-/** \brief This function finds the basis MetaBall.
- *
- * Basis meta-ball doesn't include any number at the end of
- * its name. All meta-balls with same base of name can be
- * blended. meta-balls with different basic name can't be blended.
- *
- * \warning #BKE_mball_is_basis() can fail on returned object, see function docs for details.
- */
Object *BKE_mball_basis_find(Scene *scene, Object *object)
{
Object *bob = object;
@@ -571,7 +539,6 @@ bool BKE_mball_minmax_ex(
return changed;
}
-/* basic vertex data functions */
bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
{
INIT_MINMAX(min, max);
@@ -646,7 +613,6 @@ void BKE_mball_translate(MetaBall *mb, const float offset[3])
}
}
-/* *** select funcs *** */
int BKE_mball_select_count(const MetaBall *mb)
{
int sel = 0;
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index a2590171abd..eebe6efad78 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -55,6 +55,8 @@
/* experimental (faster) normal calculation */
// #define USE_ACCUM_NORMAL
+#define MBALL_ARRAY_LEN_INIT 4096
+
/* Data types */
typedef struct corner { /* corner of a cube */
@@ -448,7 +450,7 @@ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4)
#endif
if (UNLIKELY(process->totindex == process->curindex)) {
- process->totindex += 4096;
+ process->totindex = process->totindex ? (process->totindex * 2) : MBALL_ARRAY_LEN_INIT;
process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex);
}
@@ -946,8 +948,8 @@ static int getedge(EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, in
*/
static void addtovertices(PROCESS *process, const float v[3], const float no[3])
{
- if (process->curvertex == process->totvertex) {
- process->totvertex += 4096;
+ if (UNLIKELY(process->curvertex == process->totvertex)) {
+ process->totvertex = process->totvertex ? process->totvertex * 2 : MBALL_ARRAY_LEN_INIT;
process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3]));
process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3]));
}
@@ -1447,6 +1449,16 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa
/* add resulting surface to displist */
if (process.curindex) {
+
+ /* Avoid over-allocation since this is stored in the displist. */
+ if (process.curindex != process.totindex) {
+ process.indices = MEM_reallocN(process.indices, sizeof(int[4]) * process.curindex);
+ }
+ if (process.curvertex != process.totvertex) {
+ process.co = MEM_reallocN(process.co, process.curvertex * sizeof(float[3]));
+ process.no = MEM_reallocN(process.no, process.curvertex * sizeof(float[3]));
+ }
+
dl = MEM_callocN(sizeof(DispList), "mballdisp");
BLI_addtail(dispbase, dl);
dl->type = DL_INDEX4;
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 73e0c2cfa74..05aa9111fa3 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -48,6 +48,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
@@ -183,6 +184,14 @@ static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
+static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Mesh *me = (Mesh *)id;
+ if (me->ldata.external) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, me->ldata.external->filename);
+ }
+}
+
static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Mesh *mesh = (Mesh *)id;
@@ -355,28 +364,33 @@ static void mesh_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_ME = {
- ID_ME,
- FILTER_ID_ME,
- INDEX_ID_ME,
- sizeof(Mesh),
- "Mesh",
- "meshes",
- BLT_I18NCONTEXT_ID_MESH,
- IDTYPE_FLAGS_APPEND_IS_REUSABLE,
-
- mesh_init_data,
- mesh_copy_data,
- mesh_free_data,
- nullptr,
- mesh_foreach_id,
- nullptr,
- nullptr,
- mesh_blend_write,
- mesh_blend_read_data,
- mesh_blend_read_lib,
- mesh_read_expand,
- nullptr,
- nullptr,
+ /* id_code */ ID_ME,
+ /* id_filter */ FILTER_ID_ME,
+ /* main_listbase_index */ INDEX_ID_ME,
+ /* struct_size */ sizeof(Mesh),
+ /* name */ "Mesh",
+ /* name_plural */ "meshes",
+ /* translation_context */ BLT_I18NCONTEXT_ID_MESH,
+ /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
+
+ /* init_data */ mesh_init_data,
+ /* copy_data */ mesh_copy_data,
+ /* free_data */ mesh_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ mesh_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ mesh_foreach_path,
+ /* owner_get */ nullptr,
+
+ /* blend_write */ mesh_blend_write,
+ /* blend_read_data */ mesh_blend_read_data,
+ /* blend_read_lib */ mesh_blend_read_lib,
+ /* blend_read_expand */ mesh_read_expand,
+
+ /* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
enum {
@@ -438,13 +452,15 @@ static int customdata_compare(
const uint64_t cd_mask_all_attr = CD_MASK_PROP_ALL | cd_mask_non_generic;
for (int i = 0; i < c1->totlayer; i++) {
- if (CD_TYPE_AS_MASK(c1->layers[i].type) & cd_mask_all_attr) {
+ l1 = &c1->layers[i];
+ if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l1->anonymous_id != nullptr) {
layer_count1++;
}
}
for (int i = 0; i < c2->totlayer; i++) {
- if (CD_TYPE_AS_MASK(c2->layers[i].type) & cd_mask_all_attr) {
+ l2 = &c2->layers[i];
+ if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l2->anonymous_id != nullptr) {
layer_count2++;
}
}
@@ -460,7 +476,8 @@ static int customdata_compare(
l1 = c1->layers + i1;
for (int i2 = 0; i2 < c2->totlayer; i2++) {
l2 = c2->layers + i2;
- if (l1->type != l2->type || !STREQ(l1->name, l2->name)) {
+ if (l1->type != l2->type || !STREQ(l1->name, l2->name) || l1->anonymous_id != nullptr ||
+ l2->anonymous_id != nullptr) {
continue;
}
/* At this point `l1` and `l2` have the same name and type, so they should be compared. */
@@ -673,12 +690,6 @@ static int customdata_compare(
return 0;
}
-/**
- * Used for unit testing; compares two meshes, checking only
- * differences we care about. should be usable with leaf's
- * testing framework I get RNA work done, will use hackish
- * testing code for now.
- */
const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
{
int c;
@@ -879,10 +890,6 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me)
return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
}
-/**
- * Free (or release) any data used by this mesh (does not free the mesh itself).
- * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used.
- */
void BKE_mesh_free_data_for_undo(Mesh *me)
{
mesh_free_data(&me->id);
@@ -997,10 +1004,6 @@ Mesh *BKE_mesh_new_nomain(
return mesh;
}
-/**
- * Copy user editable settings that we want to preserve
- * when a new mesh is based on an existing mesh.
- */
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
{
/* Copy general settings. */
@@ -1023,12 +1026,6 @@ void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
me_dst->vertex_group_active_index = me_src->vertex_group_active_index;
}
-/**
- * A version of #BKE_mesh_copy_parameters that is intended for evaluated output
- * (the modifier stack for example).
- *
- * \warning User counts are not handled for ID's.
- */
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
{
/* User counts aren't handled, don't copy into a mesh from #G_MAIN. */
@@ -1249,7 +1246,7 @@ void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_size[3])
}
}
-void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size)
+void BKE_mesh_texspace_get_reference(Mesh *me, char **r_texflag, float **r_loc, float **r_size)
{
BKE_mesh_texspace_ensure(me);
@@ -1267,7 +1264,7 @@ void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc,
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
{
float *texloc, *texsize;
- short *texflag;
+ char *texflag;
if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) {
me->texflag = *texflag;
@@ -1315,10 +1312,18 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int
}
}
-/**
- * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
- * this is necessary to make the if #MFace.v4 check for quads work.
- */
+void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh)
+{
+ if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
+ return;
+ }
+
+ /* Orcos are stored in normalized 0..1 range by convention. */
+ float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
+ BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
+}
+
int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr)
{
/* first test if the face is legal */
@@ -1522,10 +1527,6 @@ void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
}
}
-/**
- * Find the index of the loop in 'poly' which references vertex,
- * returns -1 if not found
- */
int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint vert)
{
for (int j = 0; j < poly->totloop; j++, loopstart++) {
@@ -1537,11 +1538,6 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint ver
return -1;
}
-/**
- * Fill \a r_adj with the loop indices in \a poly adjacent to the
- * vertex. Returns the index of the loop matching vertex, or -1 if the
- * vertex is not in \a poly
- */
int poly_get_adj_loops_from_vert(const MPoly *poly, const MLoop *mloop, uint vert, uint r_adj[2])
{
int corner = poly_find_loop_from_vert(poly, &mloop[poly->loopstart], vert);
@@ -1555,10 +1551,6 @@ int poly_get_adj_loops_from_vert(const MPoly *poly, const MLoop *mloop, uint ver
return corner;
}
-/**
- * Return the index of the edge vert that is not equal to \a v. If
- * neither edge vertex is equal to \a v, returns -1.
- */
int BKE_mesh_edge_other_vert(const MEdge *e, int v)
{
if (e->v1 == v) {
@@ -1571,9 +1563,6 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v)
return -1;
}
-/**
- * Sets each output array element to the edge index if it is a real edge, or -1.
- */
void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3])
{
for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
@@ -1586,7 +1575,6 @@ void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri,
}
}
-/* basic vertex data functions */
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
{
int i = me->totvert;
@@ -1768,9 +1756,6 @@ void BKE_mesh_mselect_validate(Mesh *me)
me->mselect = mselect_dst;
}
-/**
- * Return the index within me->mselect, or -1
- */
int BKE_mesh_mselect_find(Mesh *me, int index, int type)
{
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
@@ -1784,9 +1769,6 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type)
return -1;
}
-/**
- * Return The index of the active element.
- */
int BKE_mesh_mselect_active_get(Mesh *me, int type)
{
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
@@ -1887,13 +1869,6 @@ void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3])
mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
-/**
- * Compute 'split' (aka loop, or per face corner's) normals.
- *
- * \param r_lnors_spacearr: Allows to get computed loop normal space array.
- * That data, among other things, contains 'smooth fan' info, useful e.g.
- * to split geometry along sharp edges...
- */
void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float(*r_loopnors)[3];
@@ -2169,12 +2144,6 @@ static void split_faces_split_new_edges(Mesh *mesh,
}
}
-/* Split faces based on the edge angle and loop normals.
- * Matches behavior of face splitting in render engines.
- *
- * NOTE: Will leave CD_NORMAL loop data layer which is
- * used by render engines to set shading up.
- */
void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
{
const int num_polys = mesh->totpoly;
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 3086f117707..771d79a0445 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -807,16 +807,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
#endif // WITH_GMP
-/**
- * Do a mesh boolean operation directly on meshes (without going back and forth to BMesh).
- * \param meshes: An array of Mesh pointers.
- * \param obmats: An array of pointers to the obmat matrices that transform local
- * coordinates to global ones. It is allowed for the pointers to be null, meaning the
- * transformation is the identity.
- * \param material_remaps: An array of pointers to arrays of maps from material slot numbers in the
- * corresponding mesh to the material slot in the first mesh. It is OK for material_remaps or any
- * of its constituent arrays to be empty.
- */
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<const float4x4 *> obmats,
const float4x4 &target_transform,
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 1769be54211..e8054884f26 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -1277,11 +1277,6 @@ static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
}
}
-/**
- * \param use_virtual_modifiers: When enabled calculate virtual-modifiers before applying `md_eval`
- * support this since virtual-modifiers are not modifiers from a user perspective,
- * allowing shape keys to be included with the modifier being applied, see: T91923.
- */
Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_eval,
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index 91fd022a316..5cc1b4e4860 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -191,7 +191,6 @@ void BKE_mesh_calc_poly_center(const MPoly *mpoly,
}
}
-/* NOTE: passing poly-normal is only a speedup so we can skip calculating it. */
float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray)
{
if (mpoly->totloop == 3) {
@@ -249,23 +248,6 @@ float BKE_mesh_calc_poly_uv_area(const MPoly *mpoly, const MLoopUV *uv_array)
return area;
}
-/**
- * Calculate the volume and volume-weighted centroid of the volume
- * formed by the polygon and the origin.
- * Results will be negative if the origin is "outside" the polygon
- * (+ve normal side), but the polygon may be non-planar with no effect.
- *
- * Method from:
- * - http://forums.cgsociety.org/archive/index.php?t-756235.html
- * - http://www.globalspec.com/reference/52702/203279/4-8-the-centroid-of-a-tetrahedron
- *
- * \note
- * - Volume is 6x actual volume, and centroid is 4x actual volume-weighted centroid
- * (so division can be done once at the end).
- * - Results will have bias if polygon is non-planar.
- * - The resulting volume will only be correct if the mesh is manifold and has consistent
- * face winding (non-contiguous face normals or holes in the mesh surface).
- */
static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *mpoly,
const MLoop *loopstart,
const MVert *mvarray,
@@ -445,10 +427,6 @@ bool BKE_mesh_center_median(const Mesh *me, float r_cent[3])
return (me->totvert != 0);
}
-/**
- * Calculate the center from polygons,
- * use when we want to ignore vertex locations that don't have connected faces.
- */
bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3])
{
int i = me->totpoly;
@@ -514,10 +492,6 @@ bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
return (me->totpoly != 0);
}
-/**
- * \note Mesh must be manifold with consistent face-winding,
- * see #mesh_calc_poly_volume_centroid for details.
- */
bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
{
int i = me->totpoly;
@@ -602,12 +576,6 @@ static bool mesh_calc_center_centroid_ex(const MVert *mverts,
return true;
}
-/**
- * Calculate the volume and center.
- *
- * \param r_volume: Volume (unsigned).
- * \param r_center: Center of mass.
- */
void BKE_mesh_calc_volume(const MVert *mverts,
const int mverts_num,
const MLoopTri *looptri,
@@ -800,19 +768,6 @@ void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
BKE_mesh_update_customdata_pointers(mesh, true);
}
-/**
- * The same as #BKE_mesh_convert_mfaces_to_mpolys
- * but oriented to be used in #do_versions from `readfile.c`
- * the difference is how active/render/clone/stencil indices are handled here.
- *
- * normally they're being set from `pdata` which totally makes sense for meshes which are already
- * converted to #BMesh structures, but when loading older files indices shall be updated in other
- * way around, so newly added `pdata` and `ldata` would have this indices set
- * based on `fdata` layer.
- *
- * this is normally only needed when reading older files,
- * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used.
- */
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
{
BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
@@ -957,12 +912,9 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id,
#undef ME_FGON
}
+
/** \} */
-/**
- * Flip a single MLoop's #MDisps structure,
- * low level function to be called from face-flipping code which re-arranged the mdisps themselves.
- */
void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
{
if (UNLIKELY(!md->totdisp || !md->disps)) {
@@ -999,14 +951,6 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
}
}
-/**
- * Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
- * (keeping the same vertex as 'start point').
- *
- * \param mpoly: the polygon to flip.
- * \param mloop: the full loops array.
- * \param ldata: the loops custom data.
- */
void BKE_mesh_polygon_flip_ex(MPoly *mpoly,
MLoop *mloop,
CustomData *ldata,
@@ -1056,11 +1000,6 @@ void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, nullptr, mdisp, true);
}
-/**
- * Flip (invert winding of) all polygons (used to inverse their normals).
- *
- * \note Invalidates tessellation, caller must handle that.
- */
void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
{
MDisps *mdisp = (MDisps *)CustomData_get_layer(ldata, CD_MDISPS);
@@ -1076,8 +1015,6 @@ void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int t
/** \name Mesh Flag Flushing
* \{ */
-/* update the hide flag for edges and faces from the corresponding
- * flag in verts */
void BKE_mesh_flush_hidden_from_verts_ex(const MVert *mvert,
const MLoop *mloop,
MEdge *medge,
@@ -1149,9 +1086,6 @@ void BKE_mesh_flush_hidden_from_polys(Mesh *me)
me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
-/**
- * simple poly -> vert/edge selection.
- */
void BKE_mesh_flush_select_from_polys_ex(MVert *mvert,
const int totvert,
const MLoop *mloop,
@@ -1248,23 +1182,13 @@ void BKE_mesh_flush_select_from_verts(Mesh *me)
BKE_mesh_flush_select_from_verts_ex(
me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Spatial Calculation
* \{ */
-/**
- * This function takes the difference between 2 vertex-coord-arrays
- * (\a vert_cos_src, \a vert_cos_dst),
- * and applies the difference to \a vert_cos_new relative to \a vert_cos_org.
- *
- * \param vert_cos_src: reference deform source.
- * \param vert_cos_dst: reference deform destination.
- *
- * \param vert_cos_org: reference for the output location.
- * \param vert_cos_new: resulting coords.
- */
void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
const int totpoly,
const MLoop *mloop,
@@ -1318,4 +1242,5 @@ void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
MEM_freeN(vert_accum);
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index 7a776b0ecb7..3b6afc1f47a 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -34,7 +34,6 @@
#include "MEM_guardedalloc.h"
-/* Copied from cdDM_foreachMappedVert */
void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
void (*func)(void *userData,
int index,
@@ -95,11 +94,6 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
}
}
-/**
- * Copied from #cdDM_foreachMappedEdge.
- * \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
- * edge indices.
- */
void BKE_mesh_foreach_mapped_edge(
Mesh *mesh,
const int tot_edges,
@@ -151,7 +145,6 @@ void BKE_mesh_foreach_mapped_edge(
}
}
-/* Copied from cdDM_foreachMappedLoop */
void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
void (*func)(void *userData,
int vertex_index,
@@ -232,7 +225,6 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
}
}
-/* Copied from cdDM_foreachMappedFaceCenter */
void BKE_mesh_foreach_mapped_face_center(
Mesh *mesh,
void (*func)(void *userData, int index, const float cent[3], const float no[3]),
@@ -309,7 +301,6 @@ void BKE_mesh_foreach_mapped_face_center(
}
}
-/* Copied from cdDM_foreachMappedFaceCenter */
void BKE_mesh_foreach_mapped_subdiv_face_center(
Mesh *mesh,
void (*func)(void *userData, int index, const float cent[3], const float no[3]),
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index d28bb9c0744..415cce95d38 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -42,9 +42,6 @@
* \{ */
/* ngon version wip, based on BM_uv_vert_map_create */
-/* this replaces the non bmesh function (in trunk) which takes MTFace's,
- * if we ever need it back we could but for now this replaces it because its unused. */
-
UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
const MLoop *mloop,
const MLoopUV *mloopuv,
@@ -250,11 +247,6 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of polys that use that vertex as a corner.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -266,11 +258,6 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, false);
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of loops that use that vertex as a corner.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -282,11 +269,6 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
}
-/**
- * Generates a map where the key is the edge and the value
- * is a list of looptris that use that edge.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const MVert *UNUSED(mvert),
@@ -331,11 +313,6 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the vertex and the value
- * is a list of edges that use that vertex as an endpoint.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
@@ -375,10 +352,6 @@ void BKE_mesh_vert_edge_map_create(
*r_mem = indices;
}
-/**
- * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly
- * (not their edges).
- */
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
@@ -418,11 +391,6 @@ void BKE_mesh_vert_edge_vert_map_create(
*r_mem = indices;
}
-/**
- * Generates a map where the key is the edge and the value is a list of loops that use that edge.
- * Loops indices of a same poly are contiguous and in winding order.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MEdge *UNUSED(medge),
@@ -476,11 +444,6 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * Generates a map where the key is the edge and the value
- * is a list of polygons that use that edge.
- * The lists are allocated from one memory pool.
- */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const MEdge *UNUSED(medge),
@@ -529,20 +492,6 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * This function creates a map so the source-data (vert/edge/loop/poly)
- * can loop over the destination data (using the destination arrays origindex).
- *
- * This has the advantage that it can operate on any data-types.
- *
- * \param totsource: The total number of elements that \a final_origindex points to.
- * \param totfinal: The size of \a final_origindex
- * \param final_origindex: The size of the final array.
- *
- * \note `totsource` could be `totpoly`,
- * `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
- * This would allow an MPoly to loop over its tessfaces.
- */
void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
int **r_mem,
const int totsource,
@@ -584,10 +533,6 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
*r_mem = indices;
}
-/**
- * A version of #BKE_mesh_origindex_map_create that takes a looptri array.
- * Making a poly -> looptri map.
- */
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
const MPoly *mpoly,
@@ -630,7 +575,7 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
typedef bool (*MeshRemap_CheckIslandBoundary)(const struct MPoly *mpoly,
const struct MLoop *mloop,
const struct MEdge *medge,
- const int nbr_egde_users,
+ const int nbr_edge_users,
const struct MPoly *mpoly_array,
const struct MeshElemMap *edge_poly_map,
void *user_data);
@@ -833,14 +778,14 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
const MLoop *UNUSED(ml),
const MEdge *me,
- const int nbr_egde_users,
+ const int nbr_edge_users,
const MPoly *mpoly_array,
const MeshElemMap *edge_poly_map,
void *UNUSED(user_data))
{
/* Edge is sharp if one of its polys is flat, or edge itself is sharp,
* or edge is not used by exactly two polygons. */
- if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_egde_users == 2)) {
+ if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (nbr_edge_users == 2)) {
/* In that case, edge appears to be smooth, but we need to check its other poly too. */
const MPoly *mp_other = (mp == &mpoly_array[edge_poly_map->indices[0]]) ?
&mpoly_array[edge_poly_map->indices[1]] :
@@ -850,14 +795,6 @@ static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
return true;
}
-/**
- * Calculate smooth groups from sharp edges.
- *
- * \param r_totgroup: The total number of groups, 1 or more.
- * \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
- * starting at 1 (0 being used as 'invalid' flag).
- * Note it's callers's responsibility to MEM_freeN returned array.
- */
int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
const int totedge,
const MPoly *mpoly,
@@ -1012,7 +949,7 @@ typedef struct MeshCheckIslandBoundaryUv {
static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp),
const MLoop *ml,
const MEdge *me,
- const int UNUSED(nbr_egde_users),
+ const int UNUSED(nbr_edge_users),
const MPoly *UNUSED(mpoly_array),
const MeshElemMap *UNUSED(edge_poly_map),
void *user_data)
@@ -1202,10 +1139,6 @@ static bool mesh_calc_islands_loop_poly_uv(MVert *UNUSED(verts),
return true;
}
-/**
- * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams),
- * not some UV layers coordinates.
- */
bool BKE_mesh_calc_islands_loop_poly_edgeseam(MVert *verts,
const int totvert,
MEdge *edges,
@@ -1220,19 +1153,6 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(MVert *verts,
verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store);
}
-/**
- * Calculate UV islands.
- *
- * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
- * This has the advantages of simplicity, and being valid/common to all UV maps.
- * However, it means actual UV islands without matching UV seams will not be handled correctly...
- * If a valid UV layer is passed as \a luvs parameter,
- * UV coordinates are also used to detect islands boundaries.
- *
- * \note All this could be optimized...
- * Not sure it would be worth the more complex code, though,
- * those loops are supposed to be really quick to do...
- */
bool BKE_mesh_calc_islands_loop_poly_uvmap(MVert *verts,
const int totvert,
MEdge *edges,
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
index d3d835378ca..0115a70a52a 100644
--- a/source/blender/blenkernel/intern/mesh_merge.c
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -204,38 +204,6 @@ static bool poly_gset_compare_fn(const void *k1, const void *k2)
return true;
}
-/**
- * Merge Verts
- *
- * This frees the given mesh and returns a new mesh.
- *
- * \param vtargetmap: The table that maps vertices to target vertices. a value of -1
- * indicates a vertex is a target, and is to be kept.
- * This array is aligned with 'mesh->totvert'
- * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.),
- * this is not supported and will likely generate corrupted geometry.
- *
- * \param tot_vtargetmap: The number of non '-1' values in vtargetmap. (not the size)
- *
- * \param merge_mode: enum with two modes.
- * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
- * When called by the Mirror Modifier,
- * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
- * of faces sharing the same set of vertices)
- * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
- * When called by the Array Modifier,
- * In this mode, faces where all vertices are merged are double-checked,
- * to see whether all target vertices actually make up a poly already.
- * Indeed it could be that all of a poly's vertices are merged,
- * but merged to vertices that do not make up a single poly,
- * in which case the original poly should not be dumped.
- * Actually this later behavior could apply to the Mirror Modifier as well,
- * but the additional checks are costly and not necessary in the case of mirror,
- * because each vertex is only merged to its own mirror.
- *
- * \note #BKE_mesh_tessface_calc_ex has to run on the returned DM
- * if you want to access tessfaces.
- */
Mesh *BKE_mesh_merge_verts(Mesh *mesh,
const int *vtargetmap,
const int tot_vtargetmap,
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 6df13e71e72..2d4308945fc 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -130,14 +130,11 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
BM_mesh_free(bm);
}
-/**
- * \warning This should _not_ be used to modify original meshes since
- * it doesn't handle shape-keys, use #BKE_mesh_mirror_apply_mirror_on_axis instead.
- */
Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
Object *ob,
const Mesh *mesh,
- const int axis)
+ const int axis,
+ const bool use_correct_order_on_merge)
{
const float tolerance_sq = mmd->tolerance * mmd->tolerance;
const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
@@ -266,23 +263,46 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
* Always merge from the copied into the original vertices so it's possible to
* generate a 1:1 mapping by scanning vertices from the beginning of the array
* as is done in #BKE_editmesh_vert_coords_when_deformed. Without this,
- * the coordinates returned will sometimes point to the copied vertex locations, see: T91444.
+ * the coordinates returned will sometimes point to the copied vertex locations, see:
+ * T91444.
+ *
+ * However, such a change also affects non-versionable things like some modifiers binding, so
+ * we cannot enforce that behavior on existing modifiers, in which case we keep using the
+ * old, incorrect behavior of merging the source vertex into its copy.
*/
- if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
- *vtmap_b = i;
- tot_vtargetmap++;
+ if (use_correct_order_on_merge) {
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_b = i;
+ tot_vtargetmap++;
+
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_b = -1;
+ }
- /* average location */
- mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
- copy_v3_v3(mv_prev->co, mv->co);
+ /* Fill here to avoid 2x loops. */
+ *vtmap_a = -1;
}
else {
+ if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
+ *vtmap_a = maxVerts + i;
+ tot_vtargetmap++;
+
+ /* average location */
+ mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
+ copy_v3_v3(mv_prev->co, mv->co);
+ }
+ else {
+ *vtmap_a = -1;
+ }
+
+ /* Fill here to avoid 2x loops. */
*vtmap_b = -1;
}
- /* Fill here to avoid 2x loops. */
- *vtmap_a = -1;
-
vtmap_a++;
vtmap_b++;
}
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 9a761c6fa11..da5b4ccc764 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -316,9 +316,6 @@ void BKE_mesh_ensure_normals(Mesh *mesh)
BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
}
-/**
- * Called after calculating all modifiers.
- */
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
@@ -378,10 +375,6 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
}
}
-/**
- * NOTE: this does not update the #CD_NORMAL layer,
- * but does update the normals in the #CD_MVERT layer.
- */
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
@@ -479,13 +472,6 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
lnors_spacearr->data_type = data_type;
}
-/**
- * Utility for multi-threaded calculation that ensures
- * `lnors_spacearr_tls` doesn't share memory with `lnors_spacearr`
- * that would cause it not to be thread safe.
- *
- * \note This works as long as threads never operate on the same loops at once.
- */
void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls)
{
@@ -493,10 +479,6 @@ void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr,
lnors_spacearr_tls->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
}
-/**
- * Utility for multi-threaded calculation
- * that merges `lnors_spacearr_tls` into `lnors_spacearr`.
- */
void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpaceArray *lnors_spacearr_tls)
{
@@ -537,11 +519,6 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
-/* Should only be called once.
- * Beware, this modifies ref_vec and other_vec in place!
- * In case no valid space can be generated, ref_alpha and ref_beta are set to zero
- * (which means 'use auto lnors').
- */
void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
const float lnor[3],
float vec_ref[3],
@@ -614,14 +591,6 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
}
}
-/**
- * Add a new given loop to given lnor_space.
- * Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct
- * (in case of BMLOOP_PTR), or nullptr (in case of LOOP_INDEX), loop index is then stored in
- * pointer. If \a is_single is set, the BMLoop or loop index is directly stored in \a
- * lnor_space->loops pointer (since there is only one loop in this fan), else it is added to the
- * linked list of loops in the fan.
- */
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpace *lnor_space,
const int ml_index,
@@ -901,12 +870,6 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
}
}
-/**
- * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
- *
- * Used when defining an empty custom loop normals data layer,
- * to keep same shading as with auto-smooth!
- */
void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
const int UNUSED(numVerts),
struct MEdge *medges,
@@ -1568,11 +1531,6 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
#endif
}
-/**
- * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
- * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
- * (splitting edges).
- */
void BKE_mesh_normals_loop_split(const MVert *mverts,
const int UNUSED(numVerts),
MEdge *medges,
@@ -2057,36 +2015,16 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
}
}
-/**
- * Higher level functions hiding most of the code needed around call to
- * #BKE_mesh_normals_loop_custom_set().
- *
- * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there
- * with automatically computed vectors.
- */
void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
{
mesh_set_custom_normals(mesh, r_custom_loopnors, false);
}
-/**
- * Higher level functions hiding most of the code needed around call to
- * #BKE_mesh_normals_loop_custom_from_vertices_set().
- *
- * \param r_custom_vertnors: is not const, since code will replace zero_v3 normals there
- * with automatically computed vectors.
- */
void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3])
{
mesh_set_custom_normals(mesh, r_custom_vertnors, true);
}
-/**
- * Computes average per-vertex normals from given custom loop normals.
- *
- * \param clnors: The computed custom loop normals.
- * \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
- */
void BKE_mesh_normals_loop_to_vertex(const int numVerts,
const MLoop *mloops,
const int numLoops,
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 53a31cbbc7a..5b5378bd829 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -50,7 +50,7 @@
static CLG_LogRef LOG = {"bke.mesh"};
/* -------------------------------------------------------------------- */
-/** \name Some generic helpers.
+/** \name Some Generic Helpers
* \{ */
static bool mesh_remap_bvhtree_query_nearest(BVHTreeFromMesh *treedata,
@@ -117,22 +117,12 @@ static bool mesh_remap_bvhtree_query_raycast(BVHTreeFromMesh *treedata,
/** \} */
-/**
- * \name Auto-match.
+/* -------------------------------------------------------------------- */
+/** \name Auto-match.
*
* Find transform of a mesh to get best match with another.
* \{ */
-/**
- * Compute a value of the difference between both given meshes.
- * The smaller the result, the better the match.
- *
- * We return the inverse of the average of the inversed
- * shortest distance from each dst vertex to src ones.
- * In other words, beyond a certain (relatively small) distance, all differences have more or less
- * the same weight in final result, which allows to reduce influence of a few high differences,
- * in favor of a global good matching.
- */
float BKE_mesh_remap_calc_difference_from_mesh(const SpaceTransform *space_transform,
const MVert *verts_dst,
const int numverts_dst,
@@ -268,9 +258,6 @@ static void mesh_calc_eigen_matrix(const MVert *verts,
copy_v3_v3(r_mat[3], center);
}
-/**
- * Set r_space_transform so that best bbox of dst matches best bbox of src.
- */
void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst,
const int numverts_dst,
Mesh *me_src,
@@ -328,7 +315,7 @@ void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh to mesh mapping
+/** \name Mesh to Mesh Mapping
* \{ */
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int UNUSED(vert_mode),
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 7b1d5140421..45c84ed0862 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -74,28 +74,17 @@ static void mesh_runtime_free_mutexes(Mesh *mesh)
}
}
-/**
- * \brief Initialize the runtime of the given mesh.
- *
- * Function expects that the runtime is already cleared.
- */
void BKE_mesh_runtime_init_data(Mesh *mesh)
{
mesh_runtime_init_mutexes(mesh);
}
-/**
- * \brief Free all data (and mutexes) inside the runtime of the given mesh.
- */
void BKE_mesh_runtime_free_data(Mesh *mesh)
{
BKE_mesh_runtime_clear_cache(mesh);
mesh_runtime_free_mutexes(mesh);
}
-/* Clear all pointers which we don't want to be shared on copying the datablock.
- * However, keep all the flags which defines what the mesh is (for example, that
- * it's deformed only, or that its custom data layers are out of date.) */
void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
{
Mesh_Runtime *runtime = &mesh->runtime;
@@ -111,11 +100,6 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
mesh_runtime_init_mutexes(mesh);
}
-/**
- * \brief This function clears runtime cache of the given mesh.
- *
- * Call this function to recalculate runtime data when used.
- */
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
{
if (mesh->runtime.mesh_eval != NULL) {
@@ -128,7 +112,6 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
BKE_mesh_runtime_clear_edit_data(mesh);
}
-/* This is a ported copy of DM_ensure_looptri_data(dm) */
/**
* Ensure the array is large enough
*
@@ -137,6 +120,7 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
*/
static void mesh_ensure_looptri_data(Mesh *mesh)
{
+ /* This is a ported copy of `DM_ensure_looptri_data(dm)`. */
const uint totpoly = mesh->totpoly;
const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
@@ -162,7 +146,6 @@ static void mesh_ensure_looptri_data(Mesh *mesh)
}
}
-/* This is a ported copy of CDDM_recalc_looptri(dm). */
void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
{
mesh_ensure_looptri_data(mesh);
@@ -182,9 +165,9 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
mesh->runtime.looptris.array_wip = NULL;
}
-/* This is a ported copy of dm_getNumLoopTri(dm). */
int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
{
+ /* This is a ported copy of `dm_getNumLoopTri(dm)`. */
const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
return looptri_len;
@@ -196,11 +179,6 @@ static void mesh_runtime_looptri_recalc_isolated(void *userdata)
BKE_mesh_runtime_looptri_recalc(mesh);
}
-/**
- * \note This function only fills a cache, and therefore the mesh argument can
- * be considered logically const. Concurrent access is protected by a mutex.
- * \note This is a ported copy of dm_getLoopTriArray(dm).
- */
const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
{
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
@@ -222,7 +200,6 @@ const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
return looptri;
}
-/* This is a copy of DM_verttri_from_looptri(). */
void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri,
const MLoop *mloop,
const MLoopTri *looptri,
@@ -314,10 +291,10 @@ void BKE_mesh_batch_cache_free(Mesh *me)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh runtime debug helpers.
+/** \name Mesh Runtime Debug Helpers
* \{ */
-/* evaluated mesh info printing function,
- * to help track down differences output */
+
+/* Evaluated mesh info printing function, to help track down differences output. */
#ifndef NDEBUG
# include "BLI_dynstr.h"
@@ -412,7 +389,6 @@ void BKE_mesh_runtime_debug_print(Mesh *me_eval)
MEM_freeN(str);
}
-/* XXX Should go in customdata file? */
void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
{
int i;
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index e5e971fd574..c7a1b22dad1 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -115,12 +115,6 @@ static void set_tspace(const SMikkTSpaceContext *pContext,
p_res[3] = face_sign;
}
-/**
- * Compute simplified tangent space normals, i.e.
- * tangent vector + sign of bi-tangent one, which combined with
- * split normals can be used to recreate the full tangent space.
- * NOTE: * The mesh should be made of only tris and quads!
- */
void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
const int UNUSED(numVerts),
const MLoop *mloops,
@@ -172,12 +166,6 @@ void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
}
}
-/**
- * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
- * \note
- * - There must be a valid loop's CD_NORMALS available.
- * - The mesh should be made of only tris and quads!
- */
void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
const char *uvmap,
float (*r_looptangents)[4],
@@ -485,12 +473,6 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data,
}
}
-/**
- * Here we get some useful information such as active uv layer name and
- * search if it is already in tangent_names.
- * Also, we calculate tangent_mask that works as a descriptor of tangents state.
- * If tangent_mask has changed, then recalculate tangents.
- */
void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
@@ -564,9 +546,6 @@ void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
}
}
-/**
- * See: #BKE_editmesh_loop_tangent_calc (matching logic).
- */
void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
const MPoly *mpoly,
const uint mpoly_len,
diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c
index 213f2929d63..241aefc418c 100644
--- a/source/blender/blenkernel/intern/mesh_tessellate.c
+++ b/source/blender/blenkernel/intern/mesh_tessellate.c
@@ -154,17 +154,6 @@ static void mesh_loops_to_tessdata(CustomData *fdata,
}
}
-/**
- * Recreate #MFace Tessellation.
- *
- * \param do_face_nor_copy: Controls whether the normals from the poly
- * are copied to the tessellated faces.
- *
- * \return number of tessellation faces.
- *
- * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since
- * it's not used in many places and #MFace should be phased out.
- */
int BKE_mesh_tessface_calc_ex(CustomData *fdata,
CustomData *ldata,
CustomData *pdata,
@@ -712,9 +701,6 @@ static void mesh_recalc_looptri__multi_threaded(const MLoop *mloop,
&settings);
}
-/**
- * Calculate tessellation into #MLoopTri which exist only for this purpose.
- */
void BKE_mesh_recalc_looptri(const MLoop *mloop,
const MPoly *mpoly,
const MVert *mvert,
@@ -730,14 +716,6 @@ void BKE_mesh_recalc_looptri(const MLoop *mloop,
}
}
-/**
- * A version of #BKE_mesh_recalc_looptri which takes pre-calculated polygon normals
- * (used to avoid having to calculate the face normal for NGON tessellation).
- *
- * \note Only use this function if normals have already been calculated, there is no need
- * to calculate normals just to use this function as it will cause the normals for triangles
- * to be calculated which aren't needed for tessellation.
- */
void BKE_mesh_recalc_looptri_with_normals(const MLoop *mloop,
const MPoly *mpoly,
const MVert *mvert,
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 08668d55cf4..ba86c0fd449 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -193,6 +193,7 @@ static int search_polyloop_cmp(const void *v1, const void *v2)
/* Else, sort on loopstart. */
return sp1->loopstart > sp2->loopstart ? 1 : sp1->loopstart < sp2->loopstart ? -1 : 0;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -213,21 +214,6 @@ static int search_polyloop_cmp(const void *v1, const void *v2)
} \
} while (0)
-/**
- * Validate the mesh, \a do_fixes requires \a mesh to be non-null.
- *
- * \return false if no changes needed to be made.
- *
- * Vertex Normals
- * ==============
- *
- * While zeroed normals are checked, these checks aren't comprehensive.
- * Technically, to detect errors here a normal recalculation and comparison is necessary.
- * However this function is mainly to prevent severe errors in geometry
- * (invalid data that will crash Blender, or cause some features to behave incorrectly),
- * not to detect subtle differences in the resulting normals which could be caused
- * by importers that load normals (for example).
- */
/* NOLINTNEXTLINE: readability-function-size */
bool BKE_mesh_validate_arrays(Mesh *mesh,
MVert *mverts,
@@ -997,9 +983,6 @@ static bool mesh_validate_customdata(CustomData *data,
return is_valid;
}
-/**
- * \returns is_valid.
- */
bool BKE_mesh_validate_all_customdata(CustomData *vdata,
const uint totvert,
CustomData *edata,
@@ -1061,11 +1044,6 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata,
return is_valid;
}
-/**
- * Validates and corrects a Mesh.
- *
- * \returns true if a change is made.
- */
bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_mask)
{
bool is_valid = true;
@@ -1112,13 +1090,6 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
return false;
}
-/**
- * Checks if a Mesh is valid without any modification. This is always verbose.
- *
- * \see #DM_is_valid to call on derived meshes
- *
- * \returns is_valid.
- */
bool BKE_mesh_is_valid(Mesh *me)
{
const bool do_verbose = true;
@@ -1162,10 +1133,6 @@ bool BKE_mesh_is_valid(Mesh *me)
return is_valid;
}
-/**
- * Check all material indices of polygons are valid, invalid ones are set to 0.
- * \returns is_valid.
- */
bool BKE_mesh_validate_material_indices(Mesh *me)
{
/* Cast to unsigned to catch negative indices too. */
@@ -1196,9 +1163,9 @@ bool BKE_mesh_validate_material_indices(Mesh *me)
/** \name Mesh Stripping (removing invalid data)
* \{ */
-/* We need to keep this for edge creation (for now?), and some old readfile code... */
void BKE_mesh_strip_loose_faces(Mesh *me)
{
+ /* NOTE: We need to keep this for edge creation (for now?), and some old `readfile.c` code. */
MFace *f;
int a, b;
@@ -1217,13 +1184,6 @@ void BKE_mesh_strip_loose_faces(Mesh *me)
}
}
-/**
- * Works on both loops and polys!
- *
- * \note It won't try to guess which loops of an invalid poly to remove!
- * this is the work of the caller, to mark those loops...
- * See e.g. #BKE_mesh_validate_arrays().
- */
void BKE_mesh_strip_loose_polysloops(Mesh *me)
{
MPoly *p;
@@ -1329,6 +1289,7 @@ void BKE_mesh_strip_loose_edges(Mesh *me)
MEM_freeN(new_idx);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1512,10 +1473,6 @@ static void mesh_calc_edges_mdata(MVert *UNUSED(allvert),
*r_totedge = totedge_final;
}
-/**
- * If the mesh is from a very old blender version,
- * convert mface->edcode to edge drawflags
- */
void BKE_mesh_calc_edges_legacy(Mesh *me, const bool use_old)
{
MEdge *medge;
@@ -1565,12 +1522,6 @@ void BKE_mesh_calc_edges_loose(Mesh *mesh)
}
}
-/**
- * Calculate/create edges from tessface data
- *
- * \param mesh: The mesh to add edges into
- */
-
void BKE_mesh_calc_edges_tessface(Mesh *mesh)
{
const int numFaces = mesh->totface;
diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index 574ab785445..c8fae3cf880 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -220,9 +220,6 @@ static void clear_hash_tables(MutableSpan<EdgeMap> edge_maps)
} // namespace blender::bke::calc_edges
-/**
- * Calculate edges from polygons.
- */
void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select_new_edges)
{
using namespace blender;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 6f6cf12f023..e1d201d7806 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -133,9 +133,6 @@ const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type)
return NULL;
}
-/**
- * Get the idname of the modifier type's panel, which was defined in the #panelRegister callback.
- */
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
@@ -213,9 +210,6 @@ void BKE_modifier_free(ModifierData *md)
BKE_modifier_free_ex(md, 0);
}
-/**
- * Use instead of `BLI_remlink` when the object's active modifier should change.
- */
void BKE_modifier_remove_from_list(Object *ob, ModifierData *md)
{
BLI_assert(BLI_findindex(&ob->modifiers, md) != -1);
@@ -328,9 +322,6 @@ void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData
}
}
-/* callback's can use this
- * to avoid copying every member.
- */
void BKE_modifier_copydata_generic(const ModifierData *md_src,
ModifierData *md_dst,
const int UNUSED(flag))
@@ -457,13 +448,6 @@ void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *_for
CLOG_ERROR(&LOG, "Object: \"%s\", Modifier: \"%s\", %s", ob->id.name + 2, md->name, md->error);
}
-/* used for buttons, to find out if the 'draw deformed in editmode' option is
- * there
- *
- * also used in transform_conversion.c, to detect CrazySpace [tm] (2nd arg
- * then is NULL)
- * also used for some mesh tools to give warnings
- */
int BKE_modifiers_get_cage_index(const Scene *scene,
Object *ob,
int *r_lastPossibleCageIndex,
@@ -547,12 +531,6 @@ bool BKE_modifiers_is_particle_enabled(Object *ob)
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-/**
- * Check whether is enabled.
- *
- * \param scene: Current scene, may be NULL,
- * in which case isDisabled callback of the modifier is never called.
- */
bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
@@ -575,12 +553,6 @@ bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int re
return true;
}
-/**
- * Check whether given modifier is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param md: May be NULL, in which case we consider it as a non-local modifier case.
- */
bool BKE_modifier_is_nonlocal_in_liboverride(const Object *ob, const ModifierData *md)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
@@ -674,8 +646,6 @@ ModifierData *BKE_modifier_get_last_preview(const struct Scene *scene,
return tmp_md;
}
-/* This is to include things that are not modifiers in the evaluation of the modifier stack, for
- * example parenting to an armature. */
ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
VirtualModifierData *virtualModifierData)
{
@@ -719,9 +689,6 @@ ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
return md;
}
-/* Takes an object and returns its first selected armature, else just its armature
- * This should work for multiple armatures per object
- */
Object *BKE_modifiers_is_deformed_by_armature(Object *ob)
{
if (ob->type == OB_GPENCIL) {
@@ -790,9 +757,6 @@ Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob)
return NULL;
}
-/* Takes an object and returns its first selected lattice, else just its lattice
- * This should work for multiple lattices per object
- */
Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
{
VirtualModifierData virtualModifierData;
@@ -816,9 +780,6 @@ Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
return NULL;
}
-/* Takes an object and returns its first selected curve, else just its curve
- * This should work for multiple curves per object
- */
Object *BKE_modifiers_is_deformed_by_curve(Object *ob)
{
VirtualModifierData virtualModifierData;
@@ -946,7 +907,6 @@ void BKE_modifier_free_temporary_data(ModifierData *md)
}
}
-/* ensure modifier correctness when changing ob->data */
void BKE_modifiers_test_object(Object *ob)
{
ModifierData *md;
@@ -967,45 +927,29 @@ void BKE_modifiers_test_object(Object *ob)
}
}
-/* where should this go?, it doesn't fit well anywhere :S - campbell */
-
-/* elubie: changed this to default to the same dir as the render output
- * to prevent saving to C:\ on Windows */
-
-/* campbell: logic behind this...
- *
- * - if the ID is from a library, return library path
- * - else if the file has been saved return the blend file path.
- * - else if the file isn't saved and the ID isn't from a library, return the temp dir.
- */
const char *BKE_modifier_path_relbase(Main *bmain, Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED(ob)) {
+ /* - If the ID is from a library, return library path.
+ * - Else if the file has been saved return the blend file path.
+ * - Else if the file isn't saved and the ID isn't from a library, return the temp dir.
+ */
+ if ((bmain->filepath[0] != '\0') || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH(bmain, &ob->id);
}
- /* last resort, better than using "" which resolves to the current
- * working directory */
+ /* Last resort, better than using "" which resolves to the current working directory. */
return BKE_tempdir_session();
}
const char *BKE_modifier_path_relbase_from_global(Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED(ob)) {
- return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
- }
-
- /* last resort, better than using "" which resolves to the current
- * working directory */
- return BKE_tempdir_session();
+ return BKE_modifier_path_relbase(G_MAIN, ob);
}
-/* initializes the path with either */
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
- /* elubie: changed this to default to the same dir as the render output
- * to prevent saving to C:\ on Windows */
- BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ BLI_join_dirfile(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
}
/**
@@ -1086,15 +1030,6 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
/* end modifier callback wrappers */
-/**
- * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
- * e.g. second operand for boolean modifier.
- * Note that modifiers in stack always get fully evaluated COW ID pointers,
- * never original ones. Makes things simpler.
- *
- * \param get_cage_mesh: Return evaluated mesh with only deforming modifiers applied
- * (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh).
- */
Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
const bool get_cage_mesh)
{
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 34fb9f71bd9..fc2e7d0a6a3 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -60,6 +60,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -165,6 +166,12 @@ static void movie_clip_foreach_cache(ID *id,
function_callback(id, &key, (void **)&movie_clip->tracking.camera.intrinsics, 0, user_data);
}
+static void movie_clip_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ MovieClip *movie_clip = (MovieClip *)id;
+ BKE_bpath_foreach_path_fixed_process(bpath_data, movie_clip->filepath);
+}
+
static void write_movieTracks(BlendWriter *writer, ListBase *tracks)
{
MovieTrackingTrack *track;
@@ -347,6 +354,7 @@ IDTypeInfo IDType_ID_MC = {
.name_plural = "movieclips",
.translation_context = BLT_I18NCONTEXT_ID_MOVIECLIP,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = movie_clip_init_data,
.copy_data = movie_clip_copy_data,
@@ -354,6 +362,7 @@ IDTypeInfo IDType_ID_MC = {
.make_local = NULL,
.foreach_id = movie_clip_foreach_id,
.foreach_cache = movie_clip_foreach_cache,
+ .foreach_path = movie_clip_foreach_path,
.owner_get = NULL,
.blend_write = movieclip_blend_write,
@@ -535,10 +544,6 @@ static void movieclip_convert_multilayer_add_pass(void *UNUSED(layer),
#endif /* WITH_OPENEXR */
-/* Will try to make image buffer usable when originating from the multi-layer
- * source.
- * Internally finds a first combined pass and uses that as a buffer. Not ideal,
- * but is better than a complete empty buffer. */
void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -979,10 +984,6 @@ static void detect_clip_source(Main *bmain, MovieClip *clip)
}
}
-/* checks if image was already loaded, then returns same image
- * otherwise creates new.
- * does not load ibuf itself
- * pass on optional frame for #name images */
MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
{
MovieClip *clip;
@@ -1612,7 +1613,6 @@ void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
*aspy = clip->aspy / clip->aspx / clip->tracking.camera.pixel_aspect;
}
-/* get segments of cached frames. useful for debugging cache policies */
void BKE_movieclip_get_cache_segments(MovieClip *clip,
MovieClipUser *user,
int *r_totseg,
@@ -1848,9 +1848,6 @@ static void movieclip_build_proxy_ibuf(
IMB_freeImBuf(scaleibuf);
}
-/* NOTE: currently used by proxy job for movies, threading happens within single frame
- * (meaning scaling shall be threaded)
- */
void BKE_movieclip_build_proxy_frame(MovieClip *clip,
int clip_flag,
struct MovieDistortion *distortion,
@@ -1892,9 +1889,6 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip,
}
}
-/* NOTE: currently used by proxy job for sequences, threading happens within sequence
- * (different threads handles different frames, no threading within frame is needed)
- */
void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip,
ImBuf *ibuf,
struct MovieDistortion *distortion,
@@ -2150,4 +2144,5 @@ void BKE_movieclip_free_gputexture(struct MovieClip *clip)
MEM_freeN(tex);
}
}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index dc418545e23..fbad7d98630 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -330,9 +330,6 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *
return NULL;
}
-/* used for applying scale on mdisps layer and syncing subdivide levels when joining objects
- * use_first - return first multires modifier if all multires'es are disabled
- */
MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_first)
{
ModifierData *md;
@@ -519,7 +516,6 @@ static int get_levels_from_disps(Object *ob)
return totlvl;
}
-/* reset the multires levels to match the number of mdisps */
void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *ob)
{
Mesh *me = ob->data;
@@ -712,7 +708,6 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
multires_set_tot_level(ob, mmd, lvl);
}
-/* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */
void multiresModifier_del_levels(MultiresModifierData *mmd,
Scene *scene,
Object *ob,
@@ -1295,7 +1290,6 @@ DerivedMesh *multires_make_derived_from_derived(
return result;
}
-/* Adapted from sculptmode.c */
void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v)
{
int x, y, x2, y2;
@@ -1349,8 +1343,6 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
add_v3_v3v3(out, d2[0], d2[1]);
}
-/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
- * such that 'ob_dst' has the same total number of levels as 'ob_src'. */
void multiresModifier_sync_levels_ex(Object *ob_dst,
MultiresModifierData *mmd_src,
MultiresModifierData *mmd_dst)
@@ -1469,7 +1461,6 @@ void multiresModifier_prepare_join(struct Depsgraph *depsgraph,
multires_apply_smat(depsgraph, scene, ob, mat);
}
-/* update multires data after topology changing */
void multires_topology_changed(Mesh *me)
{
MDisps *mdisp = NULL, *cur = NULL;
@@ -1504,11 +1495,6 @@ void multires_topology_changed(Mesh *me)
}
}
-/* Makes sure data from an external file is fully read.
- *
- * Since the multires data files only contain displacement vectors without knowledge about
- * subdivision level some extra work is needed. Namely make is to all displacement grids have
- * proper level and number of displacement vectors set. */
void multires_ensure_external_read(struct Mesh *mesh, int top_level)
{
if (!CustomData_external_test(&mesh->ldata, CD_MDISPS)) {
@@ -1544,7 +1530,6 @@ void multiresModifier_ensure_external_read(struct Mesh *mesh, const MultiresModi
/***************** Multires interpolation stuff *****************/
-/* Find per-corner coordinate with given per-face UV coord */
int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert),
struct MPoly *mpoly,
struct MLoop *UNUSED(mloop),
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index bd52d70b223..e0bb3cf792c 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -69,10 +69,6 @@ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
return true;
}
-/* Returns truth on success, false otherwise.
- *
- * This function might fail in cases like source and destination not having
- * matched amount of vertices. */
bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
struct MultiresModifierData *mmd,
struct Object *dst,
diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h
index 36ecf1a6395..db419418998 100644
--- a/source/blender/blenkernel/intern/multires_reshape.h
+++ b/source/blender/blenkernel/intern/multires_reshape.h
@@ -143,15 +143,19 @@ typedef struct ReshapeConstGridElement {
* Construct/destruct reshape context.
*/
-/* Create subdivision surface descriptor which is configured for surface evaluation at a given
- * multires modifier. */
+/**
+ * Create subdivision surface descriptor which is configured for surface evaluation at a given
+ * multi-res modifier.
+ */
struct Subdiv *multires_reshape_create_subdiv(struct Depsgraph *depsgraph,
struct Object *object,
const struct MultiresModifierData *mmd);
-/* NOTE: Initialized base mesh to object's mesh, the Subdiv is created from the deformed
- * mesh prior to the multires modifier if depsgraph is not NULL. If the depsgraph is NULL
- * then Subdiv is created from base mesh (without any deformation applied). */
+/**
+ * \note Initialized base mesh to object's mesh, the Subdivision is created from the deformed
+ * mesh prior to the multi-res modifier if depsgraph is not NULL. If the depsgraph is NULL
+ * then Subdivision is created from base mesh (without any deformation applied).
+ */
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context,
struct Depsgraph *depsgraph,
struct Object *object,
@@ -185,29 +189,41 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context);
* Helper accessors.
*/
-/* For the given grid index get index of face it was created for. */
+/**
+ * For the given grid index get index of face it was created for.
+ */
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context,
int grid_index);
-/* For the given grid index get corner of a face it was created for. */
+/**
+ * For the given grid index get corner of a face it was created for.
+ */
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index);
bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index);
-/* For the given grid index get index of corresponding ptex face. */
+/**
+ * For the given grid index get index of corresponding PTEX face.
+ */
int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context,
int grid_index);
-/* Convert normalized coordinate within a grid to a normalized coordinate within a ptex face. */
+/**
+ * Convert normalized coordinate within a grid to a normalized coordinate within a PTEX face.
+ */
PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord);
-/* Convert a normalized coordinate within a ptex face to a normalized coordinate within a grid. */
+/**
+ * Convert a normalized coordinate within a PTEX face to a normalized coordinate within a grid.
+ */
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context,
const PTexCoord *ptex_coord);
-/* Calculate tangent matrix which converts displacement to a object vector.
- * Is calculated for the given surface derivatives at a given base face corner. */
+/**
+ * Calculate tangent matrix which converts displacement to a object vector.
+ * Is calculated for the given surface derivatives at a given base face corner.
+ */
void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context,
const int face_index,
const int corner,
@@ -215,14 +231,18 @@ void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *re
const float dPdv[3],
float r_tangent_matrix[3][3]);
-/* Get grid elements which are to be reshaped at a given or ptex coordinate.
- * The data is coming from final custom mdata layers. */
+/**
+ * Get grid elements which are to be reshaped at a given or PTEX coordinate.
+ * The data is coming from final custom mdata layers.
+ */
ReshapeGridElement multires_reshape_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
ReshapeGridElement multires_reshape_grid_element_for_ptex_coord(
const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord);
-/* Get original grid element for the given coordinate. */
+/**
+ * Get original grid element for the given coordinate.
+ */
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
@@ -230,8 +250,10 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
* Sample limit surface of the base mesh.
*/
-/* Evaluate limit surface created from base mesh.
- * This is the limit surface which defines tangent space for MDisps. */
+/**
+ * Evaluate limit surface created from base mesh.
+ * This is the limit surface which defines tangent space for MDisps.
+ */
void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord,
float r_P[3],
@@ -241,17 +263,23 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
* Custom data preparation.
*/
-/* Make sure custom data is allocated for the given level. */
+/**
+ * Make sure custom data is allocated for the given level.
+ */
void multires_reshape_ensure_grids(struct Mesh *mesh, const int level);
/* --------------------------------------------------------------------
* Functions specific to reshaping from a set of vertices in a object position.
*/
-/* Returns truth if all coordinates were assigned.
+/**
+ * Set displacement grids values at a reshape level to a object coordinates of the given source.
+ *
+ * \returns truth if all coordinates were assigned.
*
* False will be returned if the number of vertex coordinates did not match required number of
- * vertices at a reshape level. */
+ * vertices at a reshape level.
+ */
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
@@ -261,13 +289,15 @@ bool multires_reshape_assign_final_coords_from_vertcos(
* Functions specific to reshaping from CCG.
*/
-/* Store final object-space coordinates in the displacement grids.
+/**
+ * Store final object-space coordinates in the displacement grids.
* The reason why displacement grids are used for storage is based on memory
* footprint optimization.
*
- * NOTE: Displacement grids to be at least at a reshape level.
+ * \note Displacement grids to be at least at a reshape level.
*
- * Return truth if all coordinates have been updated. */
+ * \return truth if all coordinates have been updated.
+ */
bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg);
@@ -275,11 +305,15 @@ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext
* Functions specific to reshaping from MDISPS.
*/
-/* Reads and writes to the current mesh CD_MDISPS. */
+/**
+ * Reads and writes to the current mesh #CD_MDISPS.
+ */
void multires_reshape_assign_final_coords_from_mdisps(
const MultiresReshapeContext *reshape_context);
-/* Reads from original CD_MIDTSPS, writes to the current mesh CD_MDISPS. */
+/**
+ * Reads from original #CD_MIDTSPS, writes to the current mesh #CD_MDISPS.
+ */
void multires_reshape_assign_final_elements_from_orig_mdisps(
const MultiresReshapeContext *reshape_context);
@@ -287,15 +321,18 @@ void multires_reshape_assign_final_elements_from_orig_mdisps(
* Displacement smooth.
*/
-/* Operates on a displacement grids (CD_MDISPS) which contains object space coordinates stored for
+/**
+ * Operates on a displacement grids (CD_MDISPS) which contains object space coordinates stored for
* the reshape level.
*
* The result is grids which are defining mesh with a smooth surface and details starting from
- * reshape level up to top level added back from original displacement grids. */
+ * reshape level up to top level added back from original displacement grids.
+ */
void multires_reshape_smooth_object_grids_with_details(
const MultiresReshapeContext *reshape_context);
-/* Operates on a displacement grids (CD_MDISPS) which contains object space-coordinates stored for
+/**
+ * Operates on a displacement grids (CD_MDISPS) which contains object space-coordinates stored for
* the reshape level.
*
* Makes it so surface on top level looks smooth. Details are not preserved
@@ -307,8 +344,10 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
* Displacement, space conversion.
*/
-/* Store original grid data, so then it's possible to calculate delta from it and add
- * high-frequency content on top of reshaped grids. */
+/**
+ * Store original grid data, so then it's possible to calculate delta from it and add
+ * high-frequency content on top of reshaped grids.
+ */
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context);
void multires_reshape_object_grids_to_tangent_displacement(
@@ -318,21 +357,29 @@ void multires_reshape_object_grids_to_tangent_displacement(
* Apply base.
*/
-/* Update mesh coordinates to the final positions of displacement in object space.
+/**
+ * Update mesh coordinates to the final positions of displacement in object space.
* This is effectively desired position of base mesh vertices after canceling out displacement.
*
- * NOTE: Expects that mesh's CD_MDISPS has been set to object space positions. */
+ * \note Expects that mesh's CD_MDISPS has been set to object space positions.
+ */
void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *reshape_context);
-/* Perform better fitting of the base mesh so its subdivided version brings vertices to their
- * desired locations. */
+/**
+ * Perform better fitting of the base mesh so its subdivided version brings vertices to their
+ * desired locations.
+ */
void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context);
-/* Refine subdivision surface to the new positions of the base mesh. */
+/**
+ * Refine subdivision surface to the new positions of the base mesh.
+ */
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context);
-/* Refine subdivision surface to the new positions of the deformed mesh (base mesh with all
- * modifiers leading the multires applied).
+/**
+ * Refine subdivision surface to the new positions of the deformed mesh (base mesh with all
+ * modifiers leading the multi-res applied).
*
- * NOTE: Will re-evaluate all leading modifiers, so it's not cheap. */
+ * \note Will re-evaluate all leading modifiers, so it's not cheap.
+ */
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context);
diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index 79a2b9eb002..b7572204182 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -47,8 +47,6 @@
/** \name Construct/destruct reshape context
* \{ */
-/* Create subdivision surface descriptor which is configured for surface evaluation at a given
- * multires modifier. */
Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
/*const*/ Object *object,
const MultiresModifierData *mmd)
@@ -332,7 +330,6 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
/** \name Helper accessors
* \{ */
-/* For the given grid index get index of face it was created for. */
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context,
int grid_index)
{
@@ -345,7 +342,6 @@ int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_co
return reshape_context->grid_to_face_index[grid_index];
}
-/* For the given grid index get corner of a face it was created for. */
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index)
{
BLI_assert(grid_index >= 0);
@@ -364,7 +360,6 @@ bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context
return (base_poly->totloop == 4);
}
-/* For the given grid index get index of corresponding ptex face. */
int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context,
int grid_index)
{
@@ -374,7 +369,6 @@ int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_co
return reshape_context->face_ptex_offset[face_index] + (is_quad ? 0 : corner);
}
-/* Convert normalized coordinate within a grid to a normalized coordinate within a ptex face. */
PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord)
{
@@ -402,7 +396,6 @@ PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *resh
return ptex_coord;
}
-/* Convert a normalized coordinate within a ptex face to a normalized coordinate within a grid. */
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context,
const PTexCoord *ptex_coord)
{
diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
index 04df5698cf9..ed2df1ba8c5 100644
--- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c
+++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
@@ -182,7 +182,6 @@ static void multires_reshape_vertcos_foreach_vertex_every_edge(
multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
}
-/* Set displacement grids values at a reshape level to a object coordinates of the given source. */
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 124db07298d..84484a63291 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -61,14 +61,20 @@
static CLG_LogRef LOG = {"bke.nla"};
+/**
+ * Find the active track and strip.
+ *
+ * The active strip may or may not be on the active track.
+ */
+static void nla_tweakmode_find_active(const ListBase /* NlaTrack */ *nla_tracks,
+ NlaTrack **r_track_of_active_strip,
+ NlaStrip **r_active_strip);
+
/* *************************************************** */
/* Data Management */
/* Freeing ------------------------------------------- */
-/* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
- * and the strip itself.
- */
void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
{
NlaStrip *cs, *csn;
@@ -108,9 +114,6 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
}
}
-/* Remove the given NLA track from the set of NLA tracks, free the track's data,
- * and the track itself.
- */
void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
{
NlaStrip *strip, *stripn;
@@ -135,9 +138,6 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
}
}
-/* Free the elements of type NLA Tracks provided in the given list, but do not free
- * the list itself since that is not free-standing
- */
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
{
NlaTrack *nlt, *nltn;
@@ -159,13 +159,6 @@ void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
/* Copying ------------------------------------------- */
-/**
- * Copy NLA strip
- *
- * \param use_same_action: When true, the existing action is used (instead of being duplicated)
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
NlaStrip *BKE_nlastrip_copy(Main *bmain,
NlaStrip *strip,
const bool use_same_action,
@@ -215,11 +208,6 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain,
return strip_d;
}
-/**
- * Copy a single NLA Track.
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
NlaTrack *BKE_nlatrack_copy(Main *bmain,
NlaTrack *nlt,
const bool use_same_actions,
@@ -249,11 +237,6 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain,
return nlt_d;
}
-/**
- * Copy all NLA data.
- * \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
- * flags in BKE_lib_id.h
- */
void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const int flag)
{
NlaTrack *nlt, *nlt_d;
@@ -309,6 +292,14 @@ static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
track_dest = track_dest->next;
}
+
+ /* If the above assumption failed to hold, do a more thorough search for the active strip. */
+ if (adt_source->actstrip != NULL && adt_dest->actstrip == NULL) {
+ nla_tweakmode_find_active(&adt_source->nla_tracks, &track_dest, &adt_dest->actstrip);
+ }
+
+ BLI_assert_msg((adt_source->actstrip == NULL) == (adt_dest->actstrip == NULL),
+ "Active strip did not copy correctly");
}
void BKE_nla_tracks_copy_from_adt(Main *bmain,
@@ -325,9 +316,6 @@ void BKE_nla_tracks_copy_from_adt(Main *bmain,
/* Adding ------------------------------------------- */
-/* Add a NLA Track to the given AnimData
- * - prev: NLA-Track to add the new one after
- */
NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev, const bool is_liboverride)
{
NlaTrack *nlt;
@@ -371,7 +359,6 @@ NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev, const bool is_liboverr
return nlt;
}
-/* Create a NLA Strip referencing the given Action */
NlaStrip *BKE_nlastrip_new(bAction *act)
{
NlaStrip *strip;
@@ -390,6 +377,16 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
*/
strip->flag = NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_SYNC_LENGTH;
+ /* Disable sync for actions with a manual frame range, since it only syncs to range anyway. */
+ if (act->flag & ACT_FRAME_RANGE) {
+ strip->flag &= ~NLASTRIP_FLAG_SYNC_LENGTH;
+ }
+
+ /* Enable cyclic time for known cyclic actions. */
+ if (BKE_action_is_cyclic(act)) {
+ strip->flag |= NLASTRIP_FLAG_USR_TIME_CYCLIC;
+ }
+
/* assign the action reference */
strip->act = act;
id_us_plus(&act->id);
@@ -397,7 +394,7 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
/* determine initial range
* - strip length cannot be 0... ever...
*/
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend);
strip->start = strip->actstart;
strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) :
@@ -411,8 +408,6 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
return strip;
}
-/* Add new NLA-strip to the top of the NLA stack - i.e.
- * into the last track if space, or a new one otherwise. */
NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_liboverride)
{
NlaStrip *strip;
@@ -445,7 +440,6 @@ NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_libo
return strip;
}
-/* Add a NLA Strip referencing the given speaker's sound */
NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
{
NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip");
@@ -482,10 +476,6 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
return strip;
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
{
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, strip->act, IDWALK_CB_USER);
@@ -601,12 +591,6 @@ static float nlastrip_get_frame_transition(NlaStrip *strip, float cframe, short
return (cframe - strip->start) / length;
}
-/* non clipped mapping for strip-time <-> global time
- * mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*
- *
- * only secure for 'internal' (i.e. within AnimSys evaluation) operations,
- * but should not be directly relied on for stuff which interacts with editors
- */
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
{
switch (strip->type) {
@@ -621,12 +605,6 @@ float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
}
}
-/* Non clipped mapping for strip-time <-> global time
- * mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*
- *
- * Public API method - perform this mapping using the given AnimData block
- * and perform any necessary sanity checks on the value
- */
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
{
NlaStrip *strip;
@@ -675,7 +653,6 @@ float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
/* List of Strips ------------------------------------ */
/* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
-/* Check if there is any space in the given list to add the given strip */
bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
{
NlaStrip *strip;
@@ -710,9 +687,6 @@ bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
return true;
}
-/* Rearrange the strips in the track so that they are always in order
- * (usually only needed after a strip has been moved)
- */
void BKE_nlastrips_sort_strips(ListBase *strips)
{
ListBase tmp = {NULL, NULL};
@@ -756,9 +730,6 @@ void BKE_nlastrips_sort_strips(ListBase *strips)
strips->last = tmp.last;
}
-/* Add the given NLA-Strip to the given list of strips, assuming that it
- * isn't currently a member of another list
- */
bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
{
NlaStrip *ns;
@@ -794,10 +765,6 @@ bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
/* Meta-Strips ------------------------------------ */
-/* Convert 'islands' (i.e. continuous string of) selected strips to be
- * contained within 'Meta-Strips' which act as strips which contain strips.
- * temp: are the meta-strips to be created 'temporary' ones used for transforms?
- */
void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
{
NlaStrip *mstrip = NULL;
@@ -851,7 +818,6 @@ void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
}
}
-/* Split a meta-strip into a set of normal strips */
void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
{
NlaStrip *cs, *csn;
@@ -874,10 +840,6 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
BKE_nlastrip_free(strips, strip, true);
}
-/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
- * sel: only consider selected meta-strips, otherwise all meta-strips are removed
- * onlyTemp: only remove the 'temporary' meta-strips used for transforms
- */
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
{
NlaStrip *strip, *stripn;
@@ -903,9 +865,6 @@ void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
}
}
-/* Add the given NLA-Strip to the given Meta-Strip, assuming that the
- * strip isn't attached to any list of strips
- */
bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
{
/* sanity checks */
@@ -954,9 +913,6 @@ bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
return BKE_nlastrips_add_strip(&mstrip->strips, strip);
}
-/* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
- * until the Meta-Strips children all fit within the Meta-Strip's new dimensions
- */
void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
{
NlaStrip *strip;
@@ -1039,7 +995,6 @@ void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
/* NLA-Tracks ---------------------------------------- */
-/* Find the active NLA-track for the given stack */
NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
{
NlaTrack *nlt;
@@ -1060,11 +1015,6 @@ NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
return NULL;
}
-/* Get the NLA Track that the active action/action strip comes from,
- * since this info is not stored in AnimData. It also isn't as simple
- * as just using the active track, since multiple tracks may have been
- * entered at the same time.
- */
NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
{
NlaTrack *nlt;
@@ -1096,9 +1046,6 @@ NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
return NULL;
}
-/* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
- * that has this status in its AnimData block.
- */
void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
{
NlaTrack *nt;
@@ -1133,9 +1080,6 @@ void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
}
}
-/* Make the given NLA-track the active one for the given stack. If no track is provided,
- * this function can be used to simply deactivate all the NLA tracks in the given stack too.
- */
void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
{
NlaTrack *nlt;
@@ -1156,7 +1100,6 @@ void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
}
}
-/* Check if there is any space in the given track to add a strip of the given length */
bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
{
/* sanity checks
@@ -1177,9 +1120,6 @@ bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
return BKE_nlastrips_has_space(&nlt->strips, start, end);
}
-/* Rearrange the strips in the track so that they are always in order
- * (usually only needed after a strip has been moved)
- */
void BKE_nlatrack_sort_strips(NlaTrack *nlt)
{
/* sanity checks */
@@ -1191,9 +1131,6 @@ void BKE_nlatrack_sort_strips(NlaTrack *nlt)
BKE_nlastrips_sort_strips(&nlt->strips);
}
-/* Add the given NLA-Strip to the given NLA-Track, assuming that it
- * isn't currently attached to another one
- */
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_liboverride)
{
/* sanity checks */
@@ -1211,9 +1148,6 @@ bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_libove
return BKE_nlastrips_add_strip(&nlt->strips, strip);
}
-/* Get the extents of the given NLA-Track including gaps between strips,
- * returning whether this succeeded or not
- */
bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
{
NlaStrip *strip;
@@ -1243,12 +1177,6 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
return true;
}
-/**
- * Check whether given NLA track is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param nlt: May be NULL, in which case we consider it as a non-local track case.
- */
bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
{
return (ID_IS_OVERRIDE_LIBRARY(id) &&
@@ -1257,7 +1185,6 @@ bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt)
/* NLA Strips -------------------------------------- */
-/* Find the active NLA-strip within the given track */
NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
{
NlaStrip *strip;
@@ -1278,7 +1205,6 @@ NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
return NULL;
}
-/* Make the given NLA-Strip the active one within the given block */
void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
{
NlaTrack *nlt;
@@ -1302,7 +1228,6 @@ void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
}
}
-/* Does the given NLA-strip fall within the given bounds (times)? */
bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
{
const float stripLen = (strip) ? strip->end - strip->start : 0.0f;
@@ -1430,10 +1355,6 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
}
}
-/**
- * Recalculate the start and end frames for the strip to match the bounds of its action such that
- * the overall NLA animation result is unchanged.
- */
void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
{
float prev_actstart;
@@ -1444,16 +1365,13 @@ void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
prev_actstart = strip->actstart;
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend);
/* Set start such that key's do not visually move, to preserve the overall animation result. */
strip->start += (strip->actstart - prev_actstart) * strip->scale;
BKE_nlastrip_recalculate_bounds(strip);
}
-/* Recalculate the start and end frames for the current strip, after changing
- * the extents of the action or the mapping (repeats or scale factor) info
- */
void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
{
float actlen, mapping;
@@ -1518,7 +1436,6 @@ static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip)
/* Animated Strips ------------------------------------------- */
-/* Check if the given NLA-Track has any strips with own F-Curves */
bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
{
NlaStrip *strip;
@@ -1539,7 +1456,6 @@ bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
return false;
}
-/* Check if given NLA-Tracks have any strips with own F-Curves */
bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
{
NlaTrack *nlt;
@@ -1560,7 +1476,6 @@ bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
return false;
}
-/* Validate the NLA-Strips 'control' F-Curves based on the flags set. */
void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
{
FCurve *fcu;
@@ -1624,9 +1539,6 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
}
}
-/* Check if the given RNA pointer + property combo should be handled by
- * NLA strip curves or not.
- */
bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
{
/* sanity checks */
@@ -1666,11 +1578,6 @@ static bool nla_editbone_name_check(void *arg, const char *name)
return BLI_ghash_haskey((GHash *)arg, (const void *)name);
}
-/* Find (and set) a unique name for a strip from the whole AnimData block
- * Uses a similar method to the BLI method, but is implemented differently
- * as we need to ensure that the name is unique over several lists of tracks,
- * not just a single track.
- */
void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
{
GHash *gh;
@@ -1844,7 +1751,6 @@ static void BKE_nlastrip_validate_autoblends(NlaTrack *nlt, NlaStrip *nls)
}
}
-/* Ensure that auto-blending and other settings are set correctly */
void BKE_nla_validate_state(AnimData *adt)
{
NlaStrip *strip, *fstrip = NULL;
@@ -1901,12 +1807,6 @@ void BKE_nla_validate_state(AnimData *adt)
/* name of stashed tracks - the translation stuff is included here to save extra work */
#define STASH_TRACK_NAME DATA_("[Action Stash]")
-/* Check if an action is "stashed" in the NLA already
- *
- * The criteria for this are:
- * 1) The action in question lives in a "stash" track
- * 2) We only check first-level strips. That is, we will not check inside meta strips.
- */
bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
{
NlaTrack *nlt;
@@ -1925,9 +1825,6 @@ bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
return false;
}
-/* "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
- * to retain it in the file for future uses
- */
bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
{
NlaTrack *prev_track = NULL;
@@ -1996,12 +1893,6 @@ bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride)
/* Core Tools ------------------------------------------- */
-/* For the given AnimData block, add the active action to the NLA
- * stack (i.e. 'push-down' action). The UI should only allow this
- * for normal editing only (i.e. not in editmode for some strip's action),
- * so no checks for this are performed.
- */
-/* TODO: maybe we should have checks for this too... */
void BKE_nla_action_pushdown(AnimData *adt, const bool is_liboverride)
{
NlaStrip *strip;
@@ -2076,29 +1967,17 @@ void BKE_nla_action_pushdown(AnimData *adt, const bool is_liboverride)
BKE_nlastrip_set_active(adt, strip);
}
-/* Find the active strip + track combo, and set them up as the tweaking track,
- * and return if successful or not.
- */
-bool BKE_nla_tweakmode_enter(AnimData *adt)
+static void nla_tweakmode_find_active(const ListBase /* NlaTrack */ *nla_tracks,
+ NlaTrack **r_track_of_active_strip,
+ NlaStrip **r_active_strip)
{
NlaTrack *nlt, *activeTrack = NULL;
NlaStrip *strip, *activeStrip = NULL;
- /* verify that data is valid */
- if (ELEM(NULL, adt, adt->nla_tracks.first)) {
- return false;
- }
-
- /* If block is already in tweak-mode, just leave, but we should report
- * that this block is in tweak-mode (as our returncode). */
- if (adt->flag & ADT_NLA_EDIT_ON) {
- return true;
- }
-
/* go over the tracks, finding the active one, and its active strip
* - if we cannot find both, then there's nothing to do
*/
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (nlt = nla_tracks->first; nlt; nlt = nlt->next) {
/* check if active */
if (nlt->flag & NLATRACK_ACTIVE) {
/* store reference to this active track */
@@ -2117,7 +1996,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
*/
if (activeTrack == NULL) {
/* try last selected track for active strip */
- for (nlt = adt->nla_tracks.last; nlt; nlt = nlt->prev) {
+ for (nlt = nla_tracks->last; nlt; nlt = nlt->prev) {
if (nlt->flag & NLATRACK_SELECTED) {
/* assume this is the active track */
activeTrack = nlt;
@@ -2139,6 +2018,28 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
}
}
+ *r_track_of_active_strip = activeTrack;
+ *r_active_strip = activeStrip;
+}
+
+bool BKE_nla_tweakmode_enter(AnimData *adt)
+{
+ NlaTrack *nlt, *activeTrack = NULL;
+ NlaStrip *strip, *activeStrip = NULL;
+
+ /* verify that data is valid */
+ if (ELEM(NULL, adt, adt->nla_tracks.first)) {
+ return false;
+ }
+
+ /* If block is already in tweak-mode, just leave, but we should report
+ * that this block is in tweak-mode (as our returncode). */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ return true;
+ }
+
+ nla_tweakmode_find_active(&adt->nla_tracks, &activeTrack, &activeStrip);
+
if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) {
if (G.debug & G_DEBUG) {
printf("NLA tweak-mode enter - neither active requirement found\n");
@@ -2191,7 +2092,6 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
return true;
}
-/* Exit tweak-mode for this AnimData block. */
void BKE_nla_tweakmode_exit(AnimData *adt)
{
NlaStrip *strip;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index e02ea3f7e37..be458ed036e 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -47,22 +47,23 @@
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
+#include "BLI_color.hh"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_map.hh"
-#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_set.hh"
#include "BLI_stack.hh"
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_vector_set.hh"
-
#include "BLT_translation.h"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
+#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_cryptomatte.h"
#include "BKE_global.h"
@@ -74,8 +75,6 @@
#include "BKE_main.h"
#include "BKE_node.h"
-#include "BLI_ghash.h"
-#include "BLI_threads.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -103,6 +102,7 @@ using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::Stack;
+using blender::StringRef;
using blender::Vector;
using blender::VectorSet;
using blender::nodes::FieldInferencingInterface;
@@ -416,6 +416,29 @@ static void node_foreach_cache(ID *id,
}
}
+static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
+
+ switch (ntree->type) {
+ case NTREE_SHADER: {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_SCRIPT) {
+ NodeShaderScript *nss = reinterpret_cast<NodeShaderScript *>(node->storage);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, nss->filepath);
+ }
+ else if (node->type == SH_NODE_TEX_IES) {
+ NodeShaderTexIES *ies = reinterpret_cast<NodeShaderTexIES *>(node->storage);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, ies->filepath);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
static ID *node_owner_get(Main *bmain, ID *id)
{
if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
@@ -520,7 +543,6 @@ static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
write_node_socket_default_value(writer, sock);
}
-/* this is only direct data, tree itself should have been written */
void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
{
BKE_id_blend_write(writer, &ntree->id);
@@ -682,7 +704,6 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
sock->declaration = nullptr;
}
-/* ntree itself has been read! */
void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
{
/* NOTE: writing and reading goes in sync, for speed. */
@@ -1047,6 +1068,7 @@ IDTypeInfo IDType_ID_NT = {
/* name_plural */ "node_groups",
/* translation_context */ BLT_I18NCONTEXT_ID_NODETREE,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ ntree_init_data,
/* copy_data */ ntree_copy_data,
@@ -1054,6 +1076,7 @@ IDTypeInfo IDType_ID_NT = {
/* make_local */ nullptr,
/* foreach_id */ node_foreach_id,
/* foreach_cache */ node_foreach_cache,
+ /* foreach_path */ node_foreach_path,
/* owner_get */ node_owner_get,
/* blend_write */ ntree_blend_write,
@@ -1272,14 +1295,6 @@ static void update_typeinfo(Main *bmain,
FOREACH_NODETREE_END;
}
-/**
- * Try to initialize all type-info in a node tree.
- *
- * \note In general undefined type-info is a perfectly valid case,
- * the type may just be registered later.
- * In that case the update_typeinfo function will set type-info on registration
- * and do necessary updates.
- */
void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree)
{
ntree->init |= NTREE_TYPE_INIT;
@@ -1351,7 +1366,7 @@ bool ntreeIsRegistered(bNodeTree *ntree)
return (ntree->typeinfo != &NodeTreeTypeUndefined);
}
-GHashIterator *ntreeTypeGetIterator(void)
+GHashIterator *ntreeTypeGetIterator()
{
return BLI_ghashIterator_new(nodetreetypes_hash);
}
@@ -1429,14 +1444,14 @@ void nodeUnregisterType(bNodeType *nt)
BLI_ghash_remove(nodetypes_hash, nt->idname, nullptr, node_free_type);
}
-bool nodeTypeUndefined(bNode *node)
+bool nodeTypeUndefined(const bNode *node)
{
return (node->typeinfo == &NodeTypeUndefined) ||
((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id &&
ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING));
}
-GHashIterator *nodeTypeGetIterator(void)
+GHashIterator *nodeTypeGetIterator()
{
return BLI_ghashIterator_new(nodetypes_hash);
}
@@ -1484,7 +1499,7 @@ bool nodeSocketIsRegistered(bNodeSocket *sock)
return (sock->typeinfo != &NodeSocketTypeUndefined);
}
-GHashIterator *nodeSocketTypeGetIterator(void)
+GHashIterator *nodeSocketTypeGetIterator()
{
return BLI_ghashIterator_new(nodesockettypes_hash);
}
@@ -1508,6 +1523,33 @@ struct bNodeSocket *nodeFindSocket(const bNode *node,
return nullptr;
}
+namespace blender::bke {
+
+bNodeSocket *node_find_enabled_socket(bNode &node,
+ const eNodeSocketInOut in_out,
+ const StringRef name)
+{
+ ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
+ LISTBASE_FOREACH (bNodeSocket *, socket, sockets) {
+ if (!(socket->flag & SOCK_UNAVAIL) && socket->name == name) {
+ return socket;
+ }
+ }
+ return nullptr;
+}
+
+bNodeSocket *node_find_enabled_input_socket(bNode &node, StringRef name)
+{
+ return node_find_enabled_socket(node, SOCK_IN, name);
+}
+
+bNodeSocket *node_find_enabled_output_socket(bNode &node, StringRef name)
+{
+ return node_find_enabled_socket(node, SOCK_OUT, name);
+}
+
+} // namespace blender::bke
+
/* find unique socket identifier */
static bool unique_identifier_check(void *arg, const char *identifier)
{
@@ -2035,13 +2077,11 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
node->update |= NODE_UPDATE;
}
-/* finds a node based on its name */
bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
{
return (bNode *)BLI_findstring(&ntree->nodes, name, offsetof(bNode, name));
}
-/* Finds a node based on given socket and returns true on success. */
bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_sockindex)
{
*r_node = nullptr;
@@ -2065,9 +2105,6 @@ bool nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r_so
return false;
}
-/**
- * \note Recursive
- */
bNode *nodeFindRootParent(bNode *node)
{
if (node->parent) {
@@ -2076,10 +2113,6 @@ bNode *nodeFindRootParent(bNode *node)
return node->type == NODE_FRAME ? node : nullptr;
}
-/**
- * \returns true if \a child has \a parent as a parent/grandparent/...
- * \note Recursive
- */
bool nodeIsChildOf(const bNode *parent, const bNode *child)
{
if (parent == child) {
@@ -2091,13 +2124,6 @@ bool nodeIsChildOf(const bNode *parent, const bNode *child)
return false;
}
-/**
- * Iterate over a chain of nodes, starting with \a node_start, executing
- * \a callback for each node (which can return false to end iterator).
- *
- * \param reversed: for backwards iteration
- * \note Recursive
- */
void nodeChainIter(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *, const bool),
@@ -2152,17 +2178,6 @@ static void iter_backwards_ex(const bNodeTree *ntree,
}
}
-/**
- * Iterate over a chain of nodes, starting with \a node_start, executing
- * \a callback for each node (which can return false to end iterator).
- *
- * Faster than nodeChainIter. Iter only once per node.
- * Can be called recursively (using another nodeChainIterBackwards) by
- * setting the recursion_lvl accordingly.
- *
- * \note Needs updated socket links (ntreeUpdateTree).
- * \note Recursive
- */
void nodeChainIterBackwards(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *),
@@ -2185,12 +2200,6 @@ void nodeChainIterBackwards(const bNodeTree *ntree,
iter_backwards_ex(ntree, node_start, callback, userdata, recursion_mask);
}
-/**
- * Iterate over all parents of \a node, executing \a callback for each parent
- * (which can return false to end iterator)
- *
- * \note Recursive
- */
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata)
{
if (node->parent) {
@@ -2203,7 +2212,6 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd
/* ************** Add stuff ********** */
-/* Find the first available, non-duplicate name for a given node */
void nodeUniqueName(bNodeTree *ntree, bNode *node)
{
BLI_uniquename(
@@ -2266,9 +2274,6 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
sock_dst->cache = nullptr;
}
-/* keep socket listorder identical, for copying links */
-/* ntree is the target tree */
-/* unique_name needs to be true. It's only disabled for speed when doing GPUnodetrees. */
bNode *BKE_node_copy_ex(bNodeTree *ntree,
const bNode *node_src,
const int flag,
@@ -2412,7 +2417,6 @@ static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
return count;
}
-/* also used via rna api, so we check for proper input output direction */
bNodeLink *nodeAddLink(
bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
{
@@ -2831,8 +2835,8 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
/* XXX this should be removed eventually ...
* Currently BKE functions are modeled closely on previous code,
* using BKE_node_preview_init_tree to set up previews for a whole node tree in advance.
- * This should be left more to the individual node tree implementations.
- */
+ * This should be left more to the individual node tree implementations. */
+
bool BKE_node_preview_used(const bNode *node)
{
/* XXX check for closed nodes? */
@@ -3065,9 +3069,6 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo
}
}
-/* hack warning! this function is only used for shader previews, and
- * since it gets called multiple times per pixel for Ztransp we only
- * add the color once. Preview gets cleared before it starts render though */
void BKE_node_preview_set_pixel(
bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
{
@@ -3091,7 +3092,6 @@ void BKE_node_preview_set_pixel(
/* ************** Free stuff ********** */
-/* goes over entire tree */
void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
@@ -3281,8 +3281,6 @@ static void free_localized_node_groups(bNodeTree *ntree)
}
}
-/* Free (or release) any data used by this nodetree. Does not free the
- * nodetree itself and does no ID user counting. */
void ntreeFreeTree(bNodeTree *ntree)
{
ntree_free_data(&ntree->id);
@@ -3386,12 +3384,6 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
-/**
- * Get address of potential node-tree pointer of given ID.
- *
- * \warning Using this function directly is potentially dangerous, if you don't know or are not
- * sure, please use `ntreeFromID()` instead.
- */
bNodeTree **BKE_ntree_ptr_from_id(ID *id)
{
switch (GS(id->name)) {
@@ -3414,7 +3406,6 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id)
}
}
-/* Returns the private NodeTree object of the datablock, if it has one. */
bNodeTree *ntreeFromID(ID *id)
{
bNodeTree **nodetree = BKE_ntree_ptr_from_id(id);
@@ -3453,48 +3444,43 @@ void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable)
}
}
-/* returns localized tree for execution in threads */
bNodeTree *ntreeLocalize(bNodeTree *ntree)
{
- if (ntree) {
- /* Make full copy outside of Main database.
- * NOTE: previews are not copied here.
- */
- bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex(
- nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA));
-
- ltree->id.tag |= LIB_TAG_LOCALIZED;
+ if (ntree == nullptr) {
+ return nullptr;
+ }
- LISTBASE_FOREACH (bNode *, node, &ltree->nodes) {
- if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
- node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
- }
- }
+ /* Make full copy outside of Main database.
+ * NOTE: previews are not copied here. */
+ bNodeTree *ltree = (bNodeTree *)BKE_id_copy_ex(
+ nullptr, &ntree->id, nullptr, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA));
- /* ensures only a single output node is enabled */
- ntreeSetOutput(ntree);
+ ltree->id.tag |= LIB_TAG_LOCALIZED;
- bNode *node_src = (bNode *)ntree->nodes.first;
- bNode *node_local = (bNode *)ltree->nodes.first;
- while (node_src != nullptr) {
- node_local->original = node_src;
- node_src = node_src->next;
- node_local = node_local->next;
+ LISTBASE_FOREACH (bNode *, node, &ltree->nodes) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
+ node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
}
+ }
- if (ntree->typeinfo->localize) {
- ntree->typeinfo->localize(ltree, ntree);
- }
+ /* ensures only a single output node is enabled */
+ ntreeSetOutput(ntree);
- return ltree;
+ bNode *node_src = (bNode *)ntree->nodes.first;
+ bNode *node_local = (bNode *)ltree->nodes.first;
+ while (node_src != nullptr) {
+ node_local->original = node_src;
+ node_src = node_src->next;
+ node_local = node_local->next;
}
- return nullptr;
+ if (ntree->typeinfo->localize) {
+ ntree->typeinfo->localize(ltree, ntree);
+ }
+
+ return ltree;
}
-/* sync local composite with real tree */
-/* local tree is supposed to be running, be careful moving previews! */
-/* is called by jobs manager, outside threads, so it doesn't happen during draw */
void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
{
if (localtree && ntree) {
@@ -3504,8 +3490,6 @@ void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
}
}
-/* merge local tree results back, and free local tree */
-/* we have to assume the editor already changed completely */
void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
if (ntree && localtree) {
@@ -3873,7 +3857,6 @@ static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key,
return nullptr;
}
-/* two active flags, ID nodes have special flag for buttons display */
bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
{
if (ntree) {
@@ -3916,7 +3899,6 @@ bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id)
return ok;
}
-/* two active flags, ID nodes have special flag for buttons display */
void nodeClearActiveID(bNodeTree *ntree, short idtype)
{
if (ntree == nullptr) {
@@ -3959,7 +3941,6 @@ void nodeClearActive(bNodeTree *ntree)
}
}
-/* two active flags, ID nodes have special flag for buttons display */
void nodeSetActive(bNodeTree *ntree, bNode *node)
{
/* make sure only one node is active, and only one per ID type */
@@ -4028,10 +4009,6 @@ static void update_socket_declarations(ListBase *sockets,
}
}
-/**
- * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration
- * and sockets are up to date already.
- */
void nodeSocketDeclarationsUpdate(bNode *node)
{
BLI_assert(node->declaration != nullptr);
@@ -4039,10 +4016,6 @@ void nodeSocketDeclarationsUpdate(bNode *node)
update_socket_declarations(&node->outputs, node->declaration->outputs());
}
-/**
- * Just update `node->declaration` if necessary. This can also be called on nodes that may not be
- * up to date (e.g. because the need versioning or are dynamic).
- */
bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node)
{
if (node->declaration != nullptr) {
@@ -4064,10 +4037,6 @@ bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node)
return true;
}
-/**
- * If the node implements a `declare` function, this function makes sure that `node->declaration`
- * is up to date. It is expected that the sockets of the node are up to date already.
- */
bool nodeDeclarationEnsure(bNodeTree *ntree, bNode *node)
{
if (nodeDeclarationEnsureOnOutdatedNode(ntree, node)) {
@@ -4115,7 +4084,7 @@ void BKE_node_clipboard_init(const struct bNodeTree *ntree)
node_clipboard.type = ntree->type;
}
-void BKE_node_clipboard_clear(void)
+void BKE_node_clipboard_clear()
{
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_clipboard.links) {
nodeRemLink(nullptr, link);
@@ -4132,8 +4101,7 @@ void BKE_node_clipboard_clear(void)
#endif
}
-/* return false when one or more ID's are lost */
-bool BKE_node_clipboard_validate(void)
+bool BKE_node_clipboard_validate()
{
bool ok = true;
@@ -4211,22 +4179,22 @@ void BKE_node_clipboard_add_link(bNodeLink *link)
BLI_addtail(&node_clipboard.links, link);
}
-const ListBase *BKE_node_clipboard_get_nodes(void)
+const ListBase *BKE_node_clipboard_get_nodes()
{
return &node_clipboard.nodes;
}
-const ListBase *BKE_node_clipboard_get_links(void)
+const ListBase *BKE_node_clipboard_get_links()
{
return &node_clipboard.links;
}
-int BKE_node_clipboard_get_type(void)
+int BKE_node_clipboard_get_type()
{
return node_clipboard.type;
}
-void BKE_node_clipboard_free(void)
+void BKE_node_clipboard_free()
{
BKE_node_clipboard_validate();
BKE_node_clipboard_clear();
@@ -4234,7 +4202,6 @@ void BKE_node_clipboard_free(void)
/* Node Instance Hash */
-/* magic number for initial hash key */
const bNodeInstanceKey NODE_INSTANCE_KEY_BASE = {5381};
const bNodeInstanceKey NODE_INSTANCE_KEY_NONE = {0};
@@ -4520,7 +4487,8 @@ static void ntree_validate_links(bNodeTree *ntree)
link->flag &= ~NODE_LINK_VALID;
}
else if (ntree->typeinfo->validate_link) {
- if (!ntree->typeinfo->validate_link(ntree, link)) {
+ if (!ntree->typeinfo->validate_link((eNodeSocketDatatype)link->fromsock->type,
+ (eNodeSocketDatatype)link->tosock->type)) {
link->flag &= ~NODE_LINK_VALID;
}
}
@@ -4809,7 +4777,9 @@ static void propagate_data_requirements_from_right_to_left(
/* The output is required to be a single value when it is connected to any input that does
* not support fields. */
for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
- state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ if (target_socket->is_available()) {
+ state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ }
}
if (state.requires_single) {
@@ -5059,9 +5029,6 @@ static bool update_field_inferencing(bNodeTree &btree)
} // namespace blender::bke::node_field_inferencing
-/**
- * \param tree_update_flag: #eNodeTreeUpdate enum.
- */
void ntreeUpdateAllUsers(Main *main, ID *id, const int tree_update_flag)
{
if (id == nullptr) {
@@ -5244,7 +5211,7 @@ void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
/* ************* node type access ********** */
-void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
+void nodeLabel(const bNodeTree *ntree, const bNode *node, char *label, int maxlen)
{
label[0] = '\0';
@@ -5266,7 +5233,6 @@ void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
}
}
-/* Get node socket label if it is set */
const char *nodeSocketLabel(const bNodeSocket *sock)
{
return (sock->label[0] != '\0') ? sock->label : sock->name;
@@ -5448,10 +5414,6 @@ void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
}
}
-/**
- * \warning Nodes defining a storage type _must_ allocate this for new nodes.
- * Otherwise nodes will reload as undefined (T46619).
- */
void node_type_storage(bNodeType *ntype,
const char *storagename,
void (*freefunc)(struct bNode *node),
@@ -5469,13 +5431,6 @@ void node_type_storage(bNodeType *ntype,
ntype->freefunc = freefunc;
}
-void node_type_label(
- struct bNodeType *ntype,
- void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen))
-{
- ntype->labelfunc = labelfunc;
-}
-
void node_type_update(struct bNodeType *ntype,
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
{
@@ -5827,6 +5782,7 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_compare();
register_node_type_geo_attribute_convert();
register_node_type_geo_attribute_curve_map();
+ register_node_type_geo_attribute_domain_size();
register_node_type_geo_attribute_fill();
register_node_type_geo_attribute_map_range();
register_node_type_geo_attribute_math();
@@ -5845,7 +5801,6 @@ static void registerGeometryNodes()
register_node_type_geo_curve_fillet();
register_node_type_geo_curve_handle_type_selection();
register_node_type_geo_curve_length();
- register_node_type_geo_curve_parameter();
register_node_type_geo_curve_primitive_bezier_segment();
register_node_type_geo_curve_primitive_circle();
register_node_type_geo_curve_primitive_line();
@@ -5857,6 +5812,7 @@ static void registerGeometryNodes()
register_node_type_geo_curve_reverse();
register_node_type_geo_curve_sample();
register_node_type_geo_curve_set_handles();
+ register_node_type_geo_curve_spline_parameter();
register_node_type_geo_curve_spline_type();
register_node_type_geo_curve_subdivide();
register_node_type_geo_curve_to_mesh();
@@ -5864,7 +5820,9 @@ static void registerGeometryNodes()
register_node_type_geo_curve_trim();
register_node_type_geo_delete_geometry();
register_node_type_geo_distribute_points_on_faces();
+ register_node_type_geo_dual_mesh();
register_node_type_geo_edge_split();
+ register_node_type_geo_geometry_to_instance();
register_node_type_geo_image_texture();
register_node_type_geo_input_curve_handles();
register_node_type_geo_input_curve_tilt();
@@ -5872,9 +5830,16 @@ static void registerGeometryNodes()
register_node_type_geo_input_index();
register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
+ register_node_type_geo_input_mesh_edge_neighbors();
+ register_node_type_geo_input_mesh_edge_vertices();
+ register_node_type_geo_input_mesh_face_area();
+ register_node_type_geo_input_mesh_face_neighbors();
+ register_node_type_geo_input_mesh_island();
+ register_node_type_geo_input_mesh_vertex_neighbors();
register_node_type_geo_input_normal();
register_node_type_geo_input_position();
register_node_type_geo_input_radius();
+ register_node_type_geo_input_scene_time();
register_node_type_geo_input_shade_smooth();
register_node_type_geo_input_spline_cyclic();
register_node_type_geo_input_spline_length();
@@ -5943,7 +5908,7 @@ static void registerFunctionNodes()
register_node_type_fn_align_euler_to_vector();
register_node_type_fn_boolean_math();
- register_node_type_fn_float_compare();
+ register_node_type_fn_compare();
register_node_type_fn_float_to_int();
register_node_type_fn_input_bool();
register_node_type_fn_input_color();
@@ -5959,7 +5924,7 @@ static void registerFunctionNodes()
register_node_type_fn_value_to_string();
}
-void BKE_node_system_init(void)
+void BKE_node_system_init()
{
nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
nodetypes_hash = BLI_ghash_str_new("nodetypes_hash gh");
@@ -5986,7 +5951,7 @@ void BKE_node_system_init(void)
registerFunctionNodes();
}
-void BKE_node_system_exit(void)
+void BKE_node_system_exit()
{
if (nodetypes_hash) {
NODE_TYPES_BEGIN (nt) {
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index d650003afe2..7fec91ed65a 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -83,6 +83,7 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_asset.h"
+#include "BKE_bpath.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
@@ -548,6 +549,67 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
+static void object_foreach_path_pointcache(ListBase *ptcache_list,
+ BPathForeachPathData *bpath_data)
+{
+ for (PointCache *cache = (PointCache *)ptcache_list->first; cache != nullptr;
+ cache = cache->next) {
+ if (cache->flag & PTCACHE_DISK_CACHE) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, cache->path);
+ }
+ }
+}
+
+static void object_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Object *ob = reinterpret_cast<Object *>(id);
+
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ /* TODO: Move that to #ModifierTypeInfo. */
+ switch (md->type) {
+ case eModifierType_Fluidsim: {
+ FluidsimModifierData *fluidmd = reinterpret_cast<FluidsimModifierData *>(md);
+ if (fluidmd->fss) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, fluidmd->fss->surfdataPath);
+ }
+ break;
+ }
+ case eModifierType_Fluid: {
+ FluidModifierData *fmd = reinterpret_cast<FluidModifierData *>(md);
+ if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
+ BKE_bpath_foreach_path_fixed_process(bpath_data, fmd->domain->cache_directory);
+ }
+ break;
+ }
+ case eModifierType_Cloth: {
+ ClothModifierData *clmd = reinterpret_cast<ClothModifierData *>(md);
+ object_foreach_path_pointcache(&clmd->ptcaches, bpath_data);
+ break;
+ }
+ case eModifierType_Ocean: {
+ OceanModifierData *omd = reinterpret_cast<OceanModifierData *>(md);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, omd->cachepath);
+ break;
+ }
+ case eModifierType_MeshCache: {
+ MeshCacheModifierData *mcmd = reinterpret_cast<MeshCacheModifierData *>(md);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, mcmd->filepath);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (ob->soft != nullptr) {
+ object_foreach_path_pointcache(&ob->soft->shared->ptcaches, bpath_data);
+ }
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
+ object_foreach_path_pointcache(&psys->ptcaches, bpath_data);
+ }
+}
+
static void write_fmaps(BlendWriter *writer, ListBase *fbase)
{
LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
@@ -1258,6 +1320,7 @@ IDTypeInfo IDType_ID_OB = {
/* name_plural */ "objects",
/* translation_context */ BLT_I18NCONTEXT_ID_OBJECT,
/* flags */ 0,
+ /* asset_type_info */ &AssetType_OB,
/* init_data */ object_init_data,
/* copy_data */ object_copy_data,
@@ -1265,6 +1328,7 @@ IDTypeInfo IDType_ID_OB = {
/* make_local */ object_make_local,
/* foreach_id */ object_foreach_id,
/* foreach_cache */ nullptr,
+ /* foreach_path */ object_foreach_path,
/* owner_get */ nullptr,
/* blend_write */ object_blend_write,
@@ -1275,8 +1339,6 @@ IDTypeInfo IDType_ID_OB = {
/* blend_read_undo_preserve */ nullptr,
/* lib_override_apply_post */ object_lib_override_apply_post,
-
- /* asset_type_info */ &AssetType_OB,
};
void BKE_object_workob_clear(Object *workob)
@@ -1394,12 +1456,6 @@ void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData
}
}
-/**
- * Set the object's active modifier.
- *
- * \param md: If nullptr, only clear the active modifier, otherwise
- * it must be in the #Object.modifiers list.
- */
void BKE_object_modifier_set_active(Object *ob, ModifierData *md)
{
LISTBASE_FOREACH (ModifierData *, md_iter, &ob->modifiers) {
@@ -1434,9 +1490,6 @@ ModifierData *BKE_object_active_modifier(const Object *ob)
return nullptr;
}
-/**
- * \return True if the object's type supports regular modifiers (not grease pencil modifiers).
- */
bool BKE_object_supports_modifiers(const Object *ob)
{
return (
@@ -1514,17 +1567,6 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
return psys_dst;
}
-/**
- * Copy a single modifier.
- *
- * \note **Do not** use this function to copy a whole modifier stack (see note below too). Use
- * `BKE_object_modifier_stack_copy` instead.
- *
- * \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
- * systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
- * which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
- * more than once, this function should preferably be called in stack order.
- */
bool BKE_object_copy_modifier(
Main *bmain, Scene *scene, Object *ob_dst, const Object *ob_src, ModifierData *md_src)
{
@@ -1624,12 +1666,6 @@ bool BKE_object_copy_modifier(
return true;
}
-/**
- * Copy a single GPencil modifier.
- *
- * \note **Do not** use this function to copy a whole modifier stack. Use
- * `BKE_object_modifier_stack_copy` instead.
- */
bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *gmd_src)
{
BLI_assert(ob_dst->type == OB_GPENCIL);
@@ -1647,15 +1683,6 @@ bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData
return true;
}
-/**
- * Copy the whole stack of modifiers from one object into another.
- *
- * \warning **Does not** clear modifier stack and related data (particle systems, soft-body,
- * etc.) in `ob_dst`, if needed calling code must do it.
- *
- * \param do_copy_all: If true, even modifiers that should not support copying (like Hook one)
- * will be duplicated.
- */
bool BKE_object_modifier_stack_copy(Object *ob_dst,
const Object *ob_src,
const bool do_copy_all,
@@ -1804,9 +1831,6 @@ static void object_update_from_subsurf_ccg(Object *object)
subdiv_ccg->dirty.hidden = false;
}
-/**
- * Assign #Object.data after modifier stack evaluation.
- */
void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_owned)
{
BLI_assert(object_eval->id.tag & LIB_TAG_COPIED_ON_WRITE);
@@ -1836,9 +1860,6 @@ void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_own
object_eval->runtime.geometry_set_eval = nullptr;
}
-/**
- * Free data derived from mesh, called when mesh changes or is freed.
- */
void BKE_object_free_derived_caches(Object *ob)
{
MEM_SAFE_FREE(ob->runtime.bb);
@@ -1933,9 +1954,6 @@ void BKE_object_free_caches(Object *object)
}
}
-/**
- * Actual check for internal data, not context or flags.
- */
bool BKE_object_is_in_editmode(const Object *ob)
{
if (ob->data == nullptr) {
@@ -2085,9 +2103,6 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
return ((ob->mode == object_mode) || (ob->mode & object_mode) != 0);
}
-/**
- * Return which parts of the object are visible, as evaluated by depsgraph
- */
int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
{
if ((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
@@ -2255,9 +2270,6 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
}
}
-/**
- * Return -1 on failure.
- */
int BKE_object_obdata_to_type(const ID *id)
{
/* Keep in sync with #OB_DATA_SUPPORT_ID macro. */
@@ -2293,9 +2305,6 @@ int BKE_object_obdata_to_type(const ID *id)
}
}
-/**
- * More general add: creates minimum required data, but without vertices etc.
- */
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
if (!name) {
@@ -2325,14 +2334,6 @@ static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, c
return ob;
}
-/**
- * General add: to scene, with layer from area and default name
- *
- * Object is added to the active #Collection.
- * If there is no linked collection to the active #ViewLayer we create a new one.
- *
- * \note Creates minimum required data, but without vertices etc.
- */
Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
Object *ob = object_add_common(bmain, view_layer, type, name);
@@ -2346,11 +2347,6 @@ Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char
return ob;
}
-/**
- * Add a new object, using another one as a reference
- *
- * \param ob_src: object to use to determine the collections of the new object.
- */
Object *BKE_object_add_from(
Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name, Object *ob_src)
{
@@ -2363,15 +2359,6 @@ Object *BKE_object_add_from(
return ob;
}
-/**
- * Add a new object, but assign the given data-block as the `ob->data`
- * for the newly created object.
- *
- * \param data: The data-block to assign as `ob->data` for the new object.
- * This is assumed to be of the correct type.
- * \param do_id_user: If true, #id_us_plus() will be called on data when
- * assigning it to the object.
- */
Object *BKE_object_add_for_data(
Main *bmain, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user)
{
@@ -2623,9 +2610,6 @@ Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer,
return nullptr;
}
-/**
- * Access pose array with special check to get pose object when in weight paint mode.
- */
Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer,
View3D *v3d,
uint *r_objects_len,
@@ -2720,17 +2704,6 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
copy_v3_v3(ob_tar->scale, ob_src->scale);
}
-/**
- * Perform deep-copy of object and its 'children' data-blocks (obdata, materials, actions, etc.).
- *
- * \param dupflag: Controls which sub-data are also duplicated
- * (see #eDupli_ID_Flags in DNA_userdef_types.h).
- *
- * \note This function does not do any remapping to new IDs, caller must do it
- * (\a #BKE_libblock_relink_to_newid()).
- * \note Caller MUST free \a newid pointers itself (#BKE_main_id_newptr_and_tag_clear()) and call
- * updates of DEG too (#DAG_relations_tag_update()).
- */
Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplicate_options)
{
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
@@ -2900,17 +2873,11 @@ Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplica
return obn;
}
-/**
- * Returns true if the Object is from an external blend file (libdata).
- */
bool BKE_object_is_libdata(const Object *ob)
{
return (ob && ID_IS_LINKED(ob));
}
-/**
- * Returns true if the Object data is from an external blend file (libdata).
- */
bool BKE_object_obdata_is_libdata(const Object *ob)
{
/* Linked objects with local obdata are forbidden! */
@@ -2974,12 +2941,6 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
}
}
-/**
- * Proxy rule:
- * - lib_object->proxy_from == the one we borrow from, set temporally while object_update.
- * - local_object->proxy == pointer to library object, saved in files and read.
- * - local_object->proxy_group == pointer to collection dupli-object, saved in files and read.
- */
void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
{
/* paranoia checks */
@@ -3079,10 +3040,6 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
ob->dt = target->dt;
}
-/**
- * Use with newly created objects to set their size
- * (used to apply scene-scale).
- */
void BKE_object_obdata_size_init(struct Object *ob, const float size)
{
/* apply radius as a scale to types that support it */
@@ -3721,12 +3678,6 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
object_where_is_calc_ex(depsgraph, scene, ob, ctime, nullptr, nullptr);
}
-/**
- * Calculate object transformation matrix without recalculating dependencies and
- * constraints -- assume dependencies are already solved by depsgraph.
- * No changes to object and its parent would be done.
- * Used for bundles orientation in 3d space relative to parented blender camera.
- */
void BKE_object_where_is_calc_mat4(Object *ob, float r_obmat[4][4])
{
if (ob->parent) {
@@ -3750,14 +3701,6 @@ void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
object_where_is_calc_ex(depsgraph, scene, ob, ctime, nullptr, nullptr);
}
-/**
- * For calculation of the inverse parent transform, only used for editor.
- *
- * It assumes the object parent is already in the depsgraph.
- * Otherwise, after changing ob->parent you need to call:
- * - #DEG_relations_tag_update(bmain);
- * - #BKE_scene_graph_update_tagged(depsgraph, bmain);
- */
void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob)
{
BKE_object_workob_clear(workob);
@@ -3789,16 +3732,6 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o
BKE_object_where_is_calc(depsgraph, scene, workob);
}
-/**
- * Applies the global transformation \a mat to the \a ob using a relative parent space if
- * supplied.
- *
- * \param mat: the global transformation mat that the object should be set object to.
- * \param parent: the parent space in which this object will be set relative to
- * (should probably always be parent_eval).
- * \param use_compat: true to ensure that rotations are set using the
- * min difference between the old and new orientation.
- */
void BKE_object_apply_mat4_ex(Object *ob,
const float mat[4][4],
Object *parent,
@@ -3842,9 +3775,6 @@ void BKE_object_apply_mat4_ex(Object *ob,
/* BKE_object_mat3_to_rot handles delta rotations */
}
-/**
- * XXX: should be removed after COW operators port to use BKE_object_apply_mat4_ex directly.
- */
void BKE_object_apply_mat4(Object *ob,
const float mat[4][4],
const bool use_compat,
@@ -3859,7 +3789,7 @@ void BKE_object_apply_mat4(Object *ob,
/** \name Object Bounding Box API
* \{ */
-BoundBox *BKE_boundbox_alloc_unit(void)
+BoundBox *BKE_boundbox_alloc_unit()
{
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
@@ -3948,9 +3878,6 @@ BoundBox *BKE_object_boundbox_get(Object *ob)
return bb;
}
-/**
- * Use this to temporally disable/enable bound-box.
- */
void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
{
BoundBox *bb = BKE_object_boundbox_get(ob);
@@ -3984,6 +3911,37 @@ void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
+bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
+{
+ blender::float3 min, max;
+ INIT_MINMAX(min, max);
+
+ if (ob->runtime.geometry_set_eval) {
+ ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
+ }
+ else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {
+ if (!BKE_mesh_wrapper_minmax(mesh_eval, min, max)) {
+ return false;
+ }
+ }
+ else if (ob->runtime.curve_cache) {
+ BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
+ }
+ else {
+ return false;
+ }
+
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
+ }
+
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -4009,14 +3967,6 @@ void BKE_object_dimensions_get(Object *ob, float r_vec[3])
}
}
-/**
- * The original scale and object matrix can be passed in so any difference
- * of the objects matrix and the final matrix can be accounted for,
- * typically this caused by parenting, constraints or delta-scale.
- *
- * Re-using these values from the object causes a feedback loop
- * when multiple values are modified at once in some situations. see: T69536.
- */
void BKE_object_dimensions_set_ex(Object *ob,
const float value[3],
int axis_mask,
@@ -4341,6 +4291,12 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph,
DEG_OBJECT_ITER_END;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Transform Channels (Backup/Restore)
+ * \{ */
+
/**
* See struct members from #Object in DNA_object_types.h
*/
@@ -4401,17 +4357,11 @@ void BKE_object_tfm_restore(Object *ob, void *obtfm_pt)
copy_m4_m4(ob->imat, obtfm->imat);
}
-bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
-{
- /* test if 'ob' is a parent somewhere in par's parents */
- if (par == nullptr) {
- return false;
- }
- if (ob == par) {
- return true;
- }
- return BKE_object_parent_loop_check(par->parent, ob);
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Evaluation/Update API
+ * \{ */
static void object_handle_update_proxy(Depsgraph *depsgraph,
Scene *scene,
@@ -4435,19 +4385,6 @@ static void object_handle_update_proxy(Depsgraph *depsgraph,
}
}
-/**
- * Proxy rule:
- * - lib_object->proxy_from == the one we borrow from, only set temporal and cleared here.
- * - local_object->proxy == pointer to library object, saved in files and read.
- *
- * Function below is polluted with proxy exceptions, cleanup will follow!
- *
- * The main object update call, for object matrix, constraints, keys and displist (modifiers)
- * requires flags to be set!
- *
- * Ideally we shouldn't have to pass the rigid body world,
- * but need bigger restructuring to avoid id.
- */
void BKE_object_handle_update_ex(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -4502,13 +4439,6 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
}
-/**
- * \warning "scene" here may not be the scene object actually resides in.
- * When dealing with background-sets, "scene" is actually the active scene.
- * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
- * rigid bodies depend on their world so use #BKE_object_handle_update_ex()
- * to also pass along the current rigid body world.
- */
void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
BKE_object_handle_update_ex(depsgraph, scene, ob, nullptr, true);
@@ -4521,7 +4451,7 @@ void BKE_object_sculpt_data_create(Object *ob)
ob->sculpt->mode_type = (eObjectMode)ob->mode;
}
-bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, float **r_size)
+bool BKE_object_obdata_texspace_get(Object *ob, char **r_texflag, float **r_loc, float **r_size)
{
if (ob->data == nullptr) {
@@ -4566,17 +4496,17 @@ bool BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc
return true;
}
-/** Get evaluated mesh for given object. */
Mesh *BKE_object_get_evaluated_mesh(const Object *object)
{
/* First attempt to retrieve the evaluated mesh from the evaluated geometry set. Most
* object types either store it there or add a reference to it if it's owned elsewhere. */
GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval;
if (geometry_set_eval) {
- /* Some areas expect to be able to modify the evaluated mesh. Theoretically this should be
- * avoided, or at least protected with a lock, so a const mesh could be returned from this
- * function. */
- Mesh *mesh = geometry_set_eval->get_mesh_for_write();
+ /* Some areas expect to be able to modify the evaluated mesh in limited ways. Theoretically
+ * this should be avoided, or at least protected with a lock, so a const mesh could be returned
+ * from this function. We use a const_cast instead of #get_mesh_for_write, because that might
+ * result in a copy of the mesh when it is shared. */
+ Mesh *mesh = const_cast<Mesh *>(geometry_set_eval->get_mesh_for_read());
if (mesh) {
return mesh;
}
@@ -4593,13 +4523,6 @@ Mesh *BKE_object_get_evaluated_mesh(const Object *object)
return nullptr;
}
-/**
- * Get mesh which is not affected by modifiers:
- * - For original objects it will be same as `object->data`, and it is a mesh
- * which is in the corresponding #Main.
- * - For copied-on-write objects it will give pointer to a copied-on-write
- * mesh which corresponds to original object's mesh.
- */
Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
{
if (object->type == OB_MESH && object->runtime.data_orig != nullptr) {
@@ -4615,12 +4538,6 @@ Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
return (Mesh *)object->data;
}
-/**
- * Get a mesh which corresponds to the very original mesh from #Main.
- * - For original objects it will be object->data.
- * - For evaluated objects it will be same mesh as corresponding original
- * object uses as data.
- */
Mesh *BKE_object_get_original_mesh(const Object *object)
{
Mesh *result = nullptr;
@@ -4669,6 +4586,12 @@ Lattice *BKE_object_get_evaluated_lattice(const Object *object)
return lt_eval;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Point Cache
+ * \{ */
+
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = (const LinkData *)a, *bd = (const LinkData *)b;
@@ -4733,6 +4656,8 @@ void BKE_object_delete_ptcache(Object *ob, int index)
BLI_freelinkN(&ob->pc_ids, link);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Object Data Shape Key Insert
* \{ */
@@ -4971,6 +4896,22 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Object Query API
+ * \{ */
+
+bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
+{
+ /* test if 'ob' is a parent somewhere in par's parents */
+ if (par == nullptr) {
+ return false;
+ }
+ if (ob == par) {
+ return true;
+ }
+ return BKE_object_parent_loop_check(par->parent, ob);
+}
+
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
if (ob->flag & flag) {
@@ -4993,10 +4934,6 @@ bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_chi
return false;
}
-/**
- * Most important if this is modified it should _always_ return true, in certain
- * cases false positives are hard to avoid (shape keys for example).
- */
int BKE_object_is_modified(Scene *scene, Object *ob)
{
/* Always test on original object since evaluated object may no longer
@@ -5030,21 +4967,6 @@ int BKE_object_is_modified(Scene *scene, Object *ob)
return flag;
}
-/**
- * Check of objects moves in time.
- *
- * \note This function is currently optimized for usage in combination
- * with modifier deformation checks (#eModifierTypeType_OnlyDeform),
- * so modifiers can quickly check if their target objects moves
- * (causing deformation motion blur) or not.
- *
- * This makes it possible to give some degree of false-positives here,
- * but it's currently an acceptable tradeoff between complexity and check
- * speed. In combination with checks of modifier stack and real life usage
- * percentage of false-positives shouldn't be that high.
- *
- * \note This function does not consider physics systems.
- */
bool BKE_object_moves_in_time(const Object *object, bool recurse_parent)
{
/* If object has any sort of animation data assume it is moving. */
@@ -5140,11 +5062,6 @@ static bool modifiers_has_animation_check(const Object *ob)
return false;
}
-/**
- * Test if object is affected by deforming modifiers (for motion blur). again
- * most important is to avoid false positives, this is to skip computations
- * and we can still if there was actual deformation afterwards.
- */
int BKE_object_is_deform_modified(Scene *scene, Object *ob)
{
/* Always test on original object since evaluated object may no longer
@@ -5194,7 +5111,6 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
return flag;
}
-/** Return the number of scenes using (instantiating) that object in their collections. */
int BKE_object_scenes_users_get(Main *bmain, Object *ob)
{
int num_scenes = 0;
@@ -5234,14 +5150,31 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
return clip;
}
+bool BKE_object_supports_material_slots(struct Object *ob)
+{
+ return ELEM(ob->type,
+ OB_MESH,
+ OB_CURVE,
+ OB_SURF,
+ OB_FONT,
+ OB_MBALL,
+ OB_HAIR,
+ OB_POINTCLOUD,
+ OB_VOLUME,
+ OB_GPENCIL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Runtime
+ * \{ */
+
void BKE_object_runtime_reset(Object *object)
{
memset(&object->runtime, 0, sizeof(object->runtime));
}
-/**
- * Reset all pointers which we don't want to be shared when copying the object.
- */
void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
{
Object_Runtime *runtime = &object->runtime;
@@ -5254,12 +5187,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
runtime->geometry_set_eval = nullptr;
}
-/**
- * The function frees memory used by the runtime data, but not the runtime field itself.
- *
- * All runtime data is cleared to ensure it's not used again,
- * in keeping with other `_free_data(..)` functions.
- */
void BKE_object_runtime_free_data(Object *object)
{
/* Currently this is all that's needed. */
@@ -5268,6 +5195,12 @@ void BKE_object_runtime_free_data(Object *object)
BKE_object_runtime_reset(object);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Relationships
+ * \{ */
+
/**
* Find an associated armature object.
*/
@@ -5301,13 +5234,6 @@ static void obrel_list_add(LinkNode **links, Object *ob)
ob->id.tag |= LIB_TAG_DOIT;
}
-/**
- * Iterates over all objects of the given scene layer.
- * Depending on the #eObjectSet flag:
- * collect either #OB_SET_ALL, #OB_SET_VISIBLE or #OB_SET_SELECTED objects.
- * If #OB_SET_VISIBLE or#OB_SET_SELECTED are collected,
- * then also add related objects according to the given \a includeFilter.
- */
LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
eObjectSet objectSet,
eObRelationTypes includeFilter)
@@ -5385,9 +5311,6 @@ LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
return links;
}
-/**
- * return all groups this object is a part of, caller must free.
- */
struct LinkNode *BKE_object_groups(Main *bmain, Scene *scene, Object *ob)
{
LinkNode *collection_linknode = nullptr;
@@ -5408,15 +5331,12 @@ void BKE_object_groups_clear(Main *bmain, Scene *scene, Object *ob)
}
}
-/**
- * Return a KDTree_3d from the deformed object (in world-space).
- *
- * \note Only mesh objects currently support deforming, others are TODO.
- *
- * \param ob:
- * \param r_tot:
- * \return The kdtree or nullptr if it can't be created.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object KD-Tree
+ * \{ */
+
KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
{
KDTree_3d *tree = nullptr;
@@ -5534,6 +5454,12 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
return tree;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Modifier Utilities
+ * \{ */
+
bool BKE_object_modifier_use_time(Scene *scene,
Object *ob,
ModifierData *md,
@@ -5679,10 +5605,6 @@ static void object_cacheIgnoreClear(Object *ob, int state)
BLI_freelistN(&pidlist);
}
-/**
- * \note this function should eventually be replaced by depsgraph functionality.
- * Avoid calling this in new code unless there is a very good reason for it!
- */
bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -5786,9 +5708,6 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
return false;
}
-/**
- * Updates select_id of all objects in the given \a bmain.
- */
void BKE_object_update_select_id(struct Main *bmain)
{
Object *ob = (Object *)bmain->objects.first;
@@ -5799,6 +5718,12 @@ void BKE_object_update_select_id(struct Main *bmain)
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Conversion
+ * \{ */
+
Mesh *BKE_object_to_mesh(Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers)
{
BKE_object_to_mesh_clear(object);
@@ -5866,16 +5791,4 @@ void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data)
ob->id.py_instance = nullptr;
}
-bool BKE_object_supports_material_slots(struct Object *ob)
-{
- return ELEM(ob->type,
- OB_MESH,
- OB_CURVE,
- OB_SURF,
- OB_FONT,
- OB_MBALL,
- OB_HAIR,
- OB_POINTCLOUD,
- OB_VOLUME,
- OB_GPENCIL);
-}
+/** \} */
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 511f5d4ae66..fb4f4a14265 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -63,13 +63,6 @@ static Lattice *object_defgroup_lattice_get(ID *id)
return (lt->editlatt) ? lt->editlatt->latt : lt;
}
-/**
- * Update users of vgroups from this object, according to given map.
- *
- * Use it when you remove or reorder vgroups in the object.
- *
- * \param map: an array mapping old indices to new indices.
- */
void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
{
ModifierData *md;
@@ -106,15 +99,13 @@ void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
}
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Group creation
* \{ */
-/**
- * Add a vgroup of given name to object. *Does not* handle MDeformVert data at all!
- */
bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
{
bDeformGroup *defgroup;
@@ -129,17 +120,11 @@ bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
return defgroup;
}
-/**
- * Add a vgroup of default name to object. *Does not* handle MDeformVert data at all!
- */
bDeformGroup *BKE_object_defgroup_add(Object *ob)
{
return BKE_object_defgroup_add_name(ob, DATA_("Group"));
}
-/**
- * Create MDeformVert data for given ID. Work in Object mode only.
- */
MDeformVert *BKE_object_defgroup_data_create(ID *id)
{
if (GS(id->name) == ID_ME) {
@@ -156,18 +141,13 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id)
return NULL;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Group clearing
* \{ */
-/**
- * Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
- *
- * \param use_selection: Only operate on selection.
- * \return True if any vertex was removed, false otherwise.
- */
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
{
MDeformVert *dv;
@@ -239,12 +219,6 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
return changed;
}
-/**
- * Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
- *
- * \param use_selection: Only operate on selection.
- * \return True if any vertex was removed, false otherwise.
- */
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
{
bDeformGroup *dg;
@@ -260,6 +234,7 @@ bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
return changed;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -406,9 +381,6 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
object_defgroup_remove_common(ob, dg, def_nr);
}
-/**
- * Remove given vgroup from object. Work in Object and Edit modes.
- */
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
if (ob->type == OB_GPENCIL) {
@@ -426,10 +398,6 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
}
}
-/**
- * Remove all vgroups from object. Work in Object and Edit modes.
- * When only_unlocked=true, locked vertex groups are not removed.
- */
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
{
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
@@ -469,19 +437,11 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
}
}
-/**
- * Remove all vgroups from object. Work in Object and Edit modes.
- */
void BKE_object_defgroup_remove_all(struct Object *ob)
{
BKE_object_defgroup_remove_all_ex(ob, false);
}
-/**
- * Compute mapping for vertex groups with matching name, -1 is used for no remapping.
- * Returns null if no remapping is required.
- * The returned array has to be freed.
- */
int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
{
const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
@@ -549,11 +509,6 @@ void BKE_object_defgroup_index_map_apply(MDeformVert *dvert,
}
}
-/**
- * Get MDeformVert vgroup data from given object. Should only be used in Object mode.
- *
- * \return True if the id type supports weights.
- */
bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
{
if (id) {
@@ -579,14 +534,11 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t
*dvert_tot = 0;
return false;
}
+
/** \} */
/* --- functions for getting vgroup aligned maps --- */
-/**
- * gets the status of "flag" for each bDeformGroup
- * in the object data's vertex group list and returns an array containing them
- */
bool *BKE_object_defgroup_lock_flags_get(Object *ob, const int defbase_tot)
{
bool is_locked = false;
@@ -675,8 +627,6 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
return defgroup_validmap;
}
-/* Returns total selected vgroups,
- * wpi.defbase_sel is assumed malloc'd, all values are set */
bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
{
bool *dg_selection = MEM_mallocN(defbase_tot * sizeof(bool), __func__);
@@ -708,11 +658,6 @@ bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_fl
return dg_selection;
}
-/**
- * Checks if the lock relative mode is applicable.
- *
- * \return true if an unlocked deform group is active.
- */
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
const bool *validmap,
int index)
@@ -720,11 +665,6 @@ bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
return validmap && validmap[index] && !(lock_flags && lock_flags[index]);
}
-/**
- * Additional check for whether the lock relative mode is applicable in multi-paint mode.
- *
- * \return true if none of the selected groups are locked.
- */
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
const bool *lock_flags,
const bool *selected,
@@ -747,11 +687,6 @@ bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
return true;
}
-/**
- * Takes a pair of boolean masks of all locked and all deform groups, and computes
- * a pair of masks for locked deform and unlocked deform groups. Output buffers may
- * reuse the input ones.
- */
void BKE_object_defgroup_split_locked_validmap(
int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked)
{
@@ -774,11 +709,6 @@ void BKE_object_defgroup_split_locked_validmap(
}
}
-/**
- * Marks mirror vgroups in output and counts them.
- * Output and counter assumed to be already initialized.
- * Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
- */
void BKE_object_defgroup_mirror_selection(struct Object *ob,
int defbase_tot,
const bool *dg_selection,
@@ -808,9 +738,6 @@ void BKE_object_defgroup_mirror_selection(struct Object *ob,
}
}
-/**
- * Return the subset type of the Vertex Group Selection
- */
bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
eVGroupSelect subset_type,
int *r_defgroup_tot,
@@ -873,9 +800,6 @@ bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
return defgroup_validmap;
}
-/**
- * store indices from the defgroup_validmap (faster lookups in some cases)
- */
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
const int defgroup_tot,
int *r_defgroup_subset_map)
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 442755be15d..9f998b746a2 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -147,7 +147,7 @@ static void init_context(DupliContext *r_ctx,
/**
* Create sub-context for recursive duplis.
*/
-static void copy_dupli_context(
+static bool copy_dupli_context(
DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index)
{
*r_ctx = *ctx;
@@ -168,9 +168,11 @@ static void copy_dupli_context(
if (r_ctx->level == MAX_DUPLI_RECUR - 1) {
std::cerr << "Warning: Maximum instance recursion level reached.\n";
+ return false;
}
r_ctx->gen = get_dupli_generator(r_ctx);
+ return true;
}
/**
@@ -258,7 +260,9 @@ static void make_recursive_duplis(const DupliContext *ctx,
/* Simple preventing of too deep nested collections with #MAX_DUPLI_RECUR. */
if (ctx->level < MAX_DUPLI_RECUR) {
DupliContext rctx;
- copy_dupli_context(&rctx, ctx, ob, space_mat, index);
+ if (!copy_dupli_context(&rctx, ctx, ob, space_mat, index)) {
+ return;
+ }
if (rctx.gen) {
ctx->instance_stack->append(ob);
rctx.gen->make_duplis(&rctx);
@@ -301,13 +305,13 @@ static void make_child_duplis(const DupliContext *ctx,
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (ctx->collection, ob, mode) {
if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id);
-
- /* Meta-balls have a different dupli handling. */
- if (ob->type != OB_MBALL) {
- ob->flag |= OB_DONE; /* Doesn't render. */
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, _base_id)) {
+ /* Meta-balls have a different dupli handling. */
+ if (ob->type != OB_MBALL) {
+ ob->flag |= OB_DONE; /* Doesn't render. */
+ }
+ make_child_duplis_cb(&pctx, userdata, ob);
}
- make_child_duplis_cb(&pctx, userdata, ob);
}
}
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
@@ -324,14 +328,14 @@ static void make_child_duplis(const DupliContext *ctx,
DEG_OBJECT_ITER_BEGIN (ctx->depsgraph, ob, deg_objects_visibility_flags) {
if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id);
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id)) {
+ /* Meta-balls have a different dupli-handling. */
+ if (ob->type != OB_MBALL) {
+ ob->flag |= OB_DONE; /* Doesn't render. */
+ }
- /* Meta-balls have a different dupli-handling. */
- if (ob->type != OB_MBALL) {
- ob->flag |= OB_DONE; /* Doesn't render. */
+ make_child_duplis_cb(&pctx, userdata, ob);
}
-
- make_child_duplis_cb(&pctx, userdata, ob);
}
persistent_dupli_id++;
}
@@ -893,7 +897,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
* between the instances component below and the other components above. */
DupliContext new_instances_ctx;
if (creates_duplis_for_components) {
- copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index);
+ if (!copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index)) {
+ return;
+ }
instances_ctx = &new_instances_ctx;
}
@@ -928,7 +934,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
mul_m4_m4_pre(collection_matrix, parent_transform);
DupliContext sub_ctx;
- copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
+ if (!copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
+ break;
+ }
eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph);
int object_id = 0;
@@ -951,8 +959,9 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values);
DupliContext sub_ctx;
- copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id);
- make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
+ if (copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
+ make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
+ }
break;
}
case InstanceReference::Type::None: {
@@ -1499,7 +1508,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
else {
/* First key. */
state.time = ctime;
- if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
+ if (psys_get_particle_state(&sim, a, &state, false) == 0) {
continue;
}
@@ -1609,8 +1618,9 @@ static void make_duplis_particles(const DupliContext *ctx)
LISTBASE_FOREACH_INDEX (ParticleSystem *, psys, &ctx->object->particlesystem, psysid) {
/* Particles create one more level for persistent `psys` index. */
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid);
- make_duplis_particle_system(&pctx, psys);
+ if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, psysid)) {
+ make_duplis_particle_system(&pctx, psys);
+ }
}
}
@@ -1678,9 +1688,6 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/** \name Dupli-Container Implementation
* \{ */
-/**
- * \return a #ListBase of #DupliObject.
- */
ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist");
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 7e15ac5de5d..4c0d0303c1f 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -67,14 +67,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-/**
- * Restore the object->data to a non-modifier evaluated state.
- *
- * Some changes done directly in evaluated object require them to be reset
- * before being re-evaluated.
- * For example, we need to call this before #BKE_mesh_new_from_object(),
- * in case we removed/added modifiers in the evaluated object.
- */
void BKE_object_eval_reset(Object *ob_eval)
{
BKE_object_free_derived_caches(ob_eval);
@@ -88,10 +80,10 @@ void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob)
BKE_object_to_mat4(ob, ob->obmat);
}
-/* Evaluate parent */
-/* NOTE: based on solve_parenting(), but with the cruft stripped out */
void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob)
{
+ /* NOTE: based on `solve_parenting()`, but with the cruft stripped out. */
+
Object *par = ob->parent;
float totmat[4][4];
@@ -282,7 +274,12 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/** Bounding box from evaluated geometry. */
static void object_sync_boundbox_to_original(Object *object_orig, Object *object_eval)
{
- BoundBox *bb = BKE_object_boundbox_get(object_eval);
+ BoundBox *bb = object_eval->runtime.bb;
+ if (!bb || (bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_object_boundbox_calc_from_evaluated_geometry(object_eval);
+ }
+
+ bb = BKE_object_boundbox_get(object_eval);
if (bb != NULL) {
if (object_orig->runtime.bb == NULL) {
object_orig->runtime.bb = MEM_mallocN(sizeof(*object_orig->runtime.bb), __func__);
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index e9683d3b52c..97326c24a61 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -270,7 +270,6 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float
BLI_rw_mutex_unlock(&oc->oceanmutex);
}
-/* use catmullrom interpolation rather than linear */
void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v)
{
int i0, i1, i2, i3, j0, j1, j2, j3;
@@ -378,8 +377,6 @@ void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x
BKE_ocean_eval_uv_catrom(oc, ocr, x / oc->_Lx, z / oc->_Lz);
}
-/* note that this doesn't wrap properly for i, j < 0, but its not really meant for that being
- * just a way to get the raw data out to save in some image format. */
void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
{
BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
@@ -650,9 +647,6 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool, void *UNUSED(taskd
fftw_execute(o->_N_z_plan);
}
-/**
- * Return true if the ocean is valid and can be used.
- */
bool BKE_ocean_is_valid(const struct Ocean *o)
{
return o->_k != NULL;
@@ -777,9 +771,6 @@ bool BKE_ocean_ensure(struct OceanModifierData *omd, const int resolution)
return true;
}
-/**
- * Return true if the ocean data is valid and can be used.
- */
bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
struct OceanModifierData const *omd,
const int resolution)
@@ -818,9 +809,6 @@ bool BKE_ocean_init_from_modifier(struct Ocean *ocean,
omd->seed);
}
-/**
- * Return true if the ocean data is valid and can be used.
- */
bool BKE_ocean_init(struct Ocean *o,
int M,
int N,
diff --git a/source/blender/blenkernel/intern/ocean_spectrum.c b/source/blender/blenkernel/intern/ocean_spectrum.c
index c5504b22b43..43e0f399213 100644
--- a/source/blender/blenkernel/intern/ocean_spectrum.c
+++ b/source/blender/blenkernel/intern/ocean_spectrum.c
@@ -128,11 +128,6 @@ static float jonswap(const Ocean *oc, const float k2)
return val;
}
-/**
- * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind.
- * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing
- * for days over an area that includes hundreds of wavelengths on a side.
- */
float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
@@ -159,10 +154,6 @@ float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const
return val;
}
-/**
- * TMA extends the JONSWAP spectrum.
- * This spectral model is best suited to shallow water.
- */
float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
@@ -195,14 +186,6 @@ float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, cons
return val;
}
-/**
- * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening
- * function This enhancement is an artificial construct to address the problem that the wave
- * spectrum is never fully developed.
- *
- * The fetch parameter represents the distance from a lee shore,
- * called the fetch, or the distance over which the wind blows with constant velocity.
- */
float BLI_ocean_spectrum_jonswap(const Ocean *oc, const float kx, const float kz)
{
const float k2 = kx * kx + kz * kz;
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index f0f8343420d..8989450e41b 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -242,7 +242,6 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const
return pf;
}
-/* no libraries for now */
void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
{
Image *ima;
@@ -373,14 +372,6 @@ int BKE_packedfile_write_to_file(ReportList *reports,
return ret_value;
}
-/**
- * This function compares a packed file to a 'real' file.
- * It returns an integer indicating if:
- *
- * - PF_EQUAL: the packed file and original file are identical
- * - PF_DIFFERENT: the packed file and original file differ
- * - PF_NOFILE: the original file doesn't exist
- */
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
const char *filename,
PackedFile *pf)
@@ -434,16 +425,6 @@ enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
return ret_val;
}
-/**
- * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name)
- * and a packed file.
- *
- * It returns a char *to the existing file name / new file name or NULL when
- * there was an error or when the user decides to cancel the operation.
- *
- * \warning 'abs_name' may be relative still! (use a "//" prefix)
- * be sure to run #BLI_path_abs on it first.
- */
char *BKE_packedfile_unpack_to_file(ReportList *reports,
const char *ref_file_name,
const char *abs_name,
@@ -804,7 +785,6 @@ void BKE_packedfile_unpack_all(Main *bmain, ReportList *reports, enum ePF_FileSt
}
}
-/* ID should be not NULL, return 1 if there's a packed file */
bool BKE_packedfile_id_check(const ID *id)
{
switch (GS(id->name)) {
@@ -834,7 +814,6 @@ bool BKE_packedfile_id_check(const ID *id)
return false;
}
-/* ID should be not NULL */
void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF_FileStatus how)
{
switch (GS(id->name)) {
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index d6030941c6d..72210eea71d 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -143,6 +143,7 @@ IDTypeInfo IDType_ID_PAL = {
.name_plural = "palettes",
.translation_context = BLT_I18NCONTEXT_ID_PALETTE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = palette_init_data,
.copy_data = palette_copy_data,
@@ -150,6 +151,7 @@ IDTypeInfo IDType_ID_PAL = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = palette_blend_write,
@@ -208,6 +210,7 @@ IDTypeInfo IDType_ID_PC = {
.name_plural = "paint_curves",
.translation_context = BLT_I18NCONTEXT_ID_PAINTCURVE,
.flags = IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = paint_curve_copy_data,
@@ -215,6 +218,7 @@ IDTypeInfo IDType_ID_PC = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = paint_curve_blend_write,
@@ -723,7 +727,6 @@ void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_inde
pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0;
}
-/** Remove color from palette. Must be certain color is inside the palette! */
void BKE_palette_color_remove(Palette *palette, PaletteColor *color)
{
if (BLI_listbase_count_at_most(&palette->colors, palette->active_color) ==
@@ -962,7 +965,6 @@ bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, co
return done;
}
-/* are we in vertex paint or weight paint face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
@@ -970,7 +972,6 @@ bool BKE_paint_select_face_test(Object *ob)
(ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)));
}
-/* are we in weight paint vertex select mode? */
bool BKE_paint_select_vert_test(Object *ob)
{
return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
@@ -978,10 +979,6 @@ bool BKE_paint_select_vert_test(Object *ob)
(ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT));
}
-/**
- * used to check if selection is possible
- * (when we don't care if its face or vert)
- */
bool BKE_paint_select_elem_test(Object *ob)
{
return (BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob));
@@ -1024,9 +1021,6 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
}
}
-/**
- * Call when entering each respective paint mode.
- */
bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
{
Paint *paint = NULL;
@@ -1147,10 +1141,6 @@ void BKE_paint_free(Paint *paint)
MEM_SAFE_FREE(paint->tool_slots);
}
-/* called when copying scene settings, so even if 'src' and 'tar' are the same
- * still do a id_us_plus(), rather than if we were copying between 2 existing
- * scenes where a matching value should decrease the existing user count as
- * with paint_brush_set() */
void BKE_paint_copy(Paint *src, Paint *tar, const int flag)
{
tar->brush = src->brush;
@@ -1230,8 +1220,6 @@ void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p)
}
}
-/* returns non-zero if any of the face's vertices
- * are hidden, zero otherwise */
bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *mloop)
{
return ((mvert[mloop[lt->tri[0]].v].flag & ME_HIDE) ||
@@ -1239,9 +1227,6 @@ bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *m
(mvert[mloop[lt->tri[2]].v].flag & ME_HIDE));
}
-/* returns non-zero if any of the corners of the grid
- * face whose inner corner is at (x, y) are hidden,
- * zero otherwise */
bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int y)
{
/* skip face if any of its corners are hidden */
@@ -1251,7 +1236,6 @@ bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int
BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x));
}
-/* Return true if all vertices in the face are visible, false otherwise */
bool paint_is_bmesh_face_hidden(BMFace *f)
{
BMLoop *l_iter;
@@ -1520,8 +1504,6 @@ void BKE_sculptsession_free(Object *ob)
}
}
-/* Sculpt mode handles multires differently from regular meshes, but only if
- * it's the last modifier on the stack and it is not on the first level */
MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
{
Mesh *me = (Mesh *)ob->data;
@@ -1811,7 +1793,6 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY_ALL_MODES);
}
-/** \warning Expects a fully evaluated depsgraph. */
void BKE_sculpt_update_object_for_edit(
Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors)
{
@@ -1941,10 +1922,6 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc
return deformed;
}
-/**
- * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
- * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
- * mesh to the Face Sets. */
void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh)
{
const int face_sets_default_visible_id = 1;
@@ -2046,12 +2023,6 @@ void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *su
BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg);
}
-/**
- * Ensures we do have expected mesh data in original mesh for the sculpt mode.
- *
- * \note IDs are expected to be original ones here, and calling code should ensure it updates its
- * depsgraph properly after calling this function if it needs up-to-date evaluated data.
- */
void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
{
Mesh *mesh = BKE_mesh_from_object(object);
@@ -2223,8 +2194,6 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
subdiv_ccg->grid_hidden);
}
-/* Test if PBVH can be used directly for drawing, which is faster than
- * drawing the mesh and all updates that come with it. */
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
index 0ea0173f8a3..bdb7b483997 100644
--- a/source/blender/blenkernel/intern/paint_toolslots.c
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -140,10 +140,6 @@ void BKE_paint_toolslots_brush_update(Paint *paint)
BKE_paint_toolslots_brush_update_ex(paint, paint->brush);
}
-/**
- * Run this to ensure brush types are set for each slot on entering modes
- * (for new scenes for example).
- */
void BKE_paint_toolslots_brush_validate(Main *bmain, Paint *paint)
{
/* Clear slots with invalid slots or mode (unlikely but possible). */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index b158633294e..674f264feb7 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -500,6 +500,7 @@ IDTypeInfo IDType_ID_PA = {
.name_plural = "particles",
.translation_context = BLT_I18NCONTEXT_ID_PARTICLESETTINGS,
.flags = 0,
+ .asset_type_info = NULL,
.init_data = particle_settings_init,
.copy_data = particle_settings_copy_data,
@@ -507,6 +508,7 @@ IDTypeInfo IDType_ID_PA = {
.make_local = NULL,
.foreach_id = particle_settings_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = particle_settings_blend_write,
@@ -554,7 +556,6 @@ static void get_cpa_texture(Mesh *mesh,
int event,
float cfra);
-/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
{
ParticleSettings *part = psys->part;
@@ -644,7 +645,7 @@ static void psys_free_path_cache_buffers(ParticleCacheKey **cache, ListBase *buf
/************************************************/
/* Getting stuff */
/************************************************/
-/* get object's active particle system safely */
+
ParticleSystem *psys_get_current(Object *ob)
{
ParticleSystem *psys;
@@ -912,9 +913,11 @@ int psys_uses_gravity(ParticleSimulationData *sim)
return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part &&
sim->psys->part->effector_weights->global_gravity != 0.0f;
}
+
/************************************************/
/* Freeing stuff */
/************************************************/
+
static void fluid_free_settings(SPHFluidSettings *fluid)
{
if (fluid) {
@@ -1054,7 +1057,6 @@ void psys_free_pdd(ParticleSystem *psys)
psys->pdd->partsize = 0;
}
}
-/* free everything */
void psys_free(Object *ob, ParticleSystem *psys)
{
if (psys) {
@@ -1202,6 +1204,7 @@ void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src)
/************************************************/
/* Interpolation */
/************************************************/
+
static float interpolate_particle_value(
float v1, float v2, float v3, float v4, const float w[4], int four)
{
@@ -1669,7 +1672,7 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
/************************************************/
/* Particles on a dm */
/************************************************/
-/* interpolate a location on a face based on face coordinates */
+
void psys_interpolate_face(MVert *mvert,
MFace *mface,
MTFace *tface,
@@ -1901,18 +1904,6 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
}
}
-/**
- * Find the final derived mesh tessface for a particle, from its original tessface index.
- * This is slow and can be optimized but only for many lookups.
- *
- * \param mesh_final: Final mesh, it may not have the same topology as original mesh.
- * \param mesh_original: Original mesh, use for accessing #MPoly to #MFace mapping.
- * \param findex_orig: The input tessface index.
- * \param fw: Face weights (position of the particle inside the \a findex_orig tessface).
- * \param poly_nodes: May be NULL, otherwise an array of linked list,
- * one for each final \a mesh_final polygon, containing all its tessfaces indices.
- * \return The \a mesh_final tessface index.
- */
int psys_particle_dm_face_lookup(Mesh *mesh_final,
Mesh *mesh_original,
int findex_orig,
@@ -2094,7 +2085,6 @@ static int psys_map_index_on_dm(Mesh *mesh,
return 1;
}
-/* interprets particle data to get a point on a mesh in object space */
void psys_particle_on_dm(Mesh *mesh_final,
int from,
int index,
@@ -2216,9 +2206,11 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
}
return NULL;
}
+
/************************************************/
/* Particles on a shape */
/************************************************/
+
/* ready for future use */
static void psys_particle_on_shape(int UNUSED(distr),
int UNUSED(index),
@@ -2247,6 +2239,7 @@ static void psys_particle_on_shape(int UNUSED(distr),
copy_v3_v3(orco, zerovec);
}
}
+
/************************************************/
/* Particles on emitter */
/************************************************/
@@ -2321,6 +2314,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd,
psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco);
}
}
+
/************************************************/
/* Path Cache */
/************************************************/
@@ -3273,11 +3267,6 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0,
}
}
-/**
- * Calculates paths ready for drawing/rendering
- * - Useful for making use of opengl vertex arrays for super fast strand drawing.
- * - Makes child strands possible and creates them too into the cache.
- * - Cached path data is also used to determine cut position for the editmode tool. */
void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
PARTICLE_PSMD;
@@ -3760,9 +3749,11 @@ void psys_cache_edit_paths(Depsgraph *depsgraph,
}
}
}
+
/************************************************/
/* Particle Key handling */
/************************************************/
+
void copy_particle_key(ParticleKey *to, ParticleKey *from, int time)
{
if (time) {
@@ -3922,6 +3913,7 @@ void psys_mat_hair_to_global(
/************************************************/
/* ParticleSettings handling */
/************************************************/
+
static ModifierData *object_add_or_copy_particle_system(
Main *bmain, Scene *scene, Object *ob, const char *name, const ParticleSystem *psys_orig)
{
@@ -4458,9 +4450,11 @@ void psys_get_texture(
CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
}
+
/************************************************/
/* Particle State */
/************************************************/
+
float psys_get_timestep(ParticleSimulationData *sim)
{
return 0.04f * sim->psys->part->timetweak;
@@ -4586,7 +4580,6 @@ static void get_child_modifier_parameters(ParticleSettings *part,
ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
}
}
-/* gets hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(ParticleSimulationData *sim,
int p,
ParticleKey *state,
@@ -4855,8 +4848,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim,
}
}
}
-/* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */
-int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *state, int always)
+bool psys_get_particle_state(ParticleSimulationData *sim,
+ int p,
+ ParticleKey *state,
+ const bool always)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -4871,12 +4866,12 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (p >= totpart) {
if (!psys->totchild) {
- return 0;
+ return false;
}
if (part->childtype == PART_CHILD_FACES) {
if (!(psys->flag & PSYS_KEYED)) {
- return 0;
+ return false;
}
cpa = psys->child + p - totpart;
@@ -4886,7 +4881,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (!always) {
if ((state->time < 0.0f && !(part->flag & PART_UNBORN)) ||
(state->time > 1.0f && !(part->flag & PART_DIED))) {
- return 0;
+ return false;
}
}
@@ -4894,7 +4889,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
(part->lifetime * psys_frand(psys, p + 24));
psys_get_particle_on_path(sim, p, state, 1);
- return 1;
+ return true;
}
cpa = sim->psys->child + p - totpart;
@@ -4908,7 +4903,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (!always) {
if ((cfra < pa->time && (part->flag & PART_UNBORN) == 0) ||
(cfra >= pa->dietime && (part->flag & PART_DIED) == 0)) {
- return 0;
+ return false;
}
}
@@ -4918,7 +4913,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
if (sim->psys->flag & PSYS_KEYED) {
state->time = -cfra;
psys_get_particle_on_path(sim, p, state, 1);
- return 1;
+ return true;
}
if (cpa) {
@@ -5018,7 +5013,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
}
}
- return 1;
+ return true;
}
void psys_get_dupli_texture(ParticleSystem *psys,
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 863476c6638..fd4f89e3f6d 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -997,12 +997,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
BKE_mesh_tessface_ensure(mesh);
/* we need orco for consistent distributions */
- if (!CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
- /* Orcos are stored in normalized 0..1 range by convention. */
- float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
- BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
- CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
- }
+ BKE_mesh_orco_ensure(ob, mesh);
if (from == PART_FROM_VERT) {
MVert *mv = mesh->mvert;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 8986847a034..e489f9e2bac 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -452,7 +452,6 @@ void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, Partic
}
}
-/* threaded child particle distribution and path caching */
void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData *sim)
{
memset(ctx, 0, sizeof(ParticleThreadContext));
@@ -591,7 +590,6 @@ static void init_particle_texture(ParticleSimulationData *sim, ParticleData *pa,
}
}
-/* set particle parameters that don't change during particle's life */
void init_particle(ParticleSimulationData *sim, ParticleData *pa)
{
ParticleSettings *part = sim->psys->part;
@@ -1066,7 +1064,6 @@ static void evaluate_emitter_anim(struct Depsgraph *depsgraph,
BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
}
-/* sets particle to the emitter surface with initial velocity & rotation */
void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra)
{
ParticleSystem *psys = sim->psys;
@@ -1157,9 +1154,11 @@ static void reset_all_particles(ParticleSimulationData *sim, float dtime, float
reset_particle(sim, pa, dtime, cfra);
}
}
+
/************************************************/
/* Particle targets */
/************************************************/
+
ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
{
ParticleSystem *psys = NULL;
@@ -1180,10 +1179,11 @@ ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
return psys;
}
+
/************************************************/
/* Keyed particles */
/************************************************/
-/* Counts valid keyed targets */
+
void psys_count_keyed_targets(ParticleSimulationData *sim)
{
ParticleSystem *psys = sim->psys, *kpsys;
@@ -1288,6 +1288,7 @@ static void set_keyed_keys(ParticleSimulationData *sim)
/************************************************/
/* Point Cache */
/************************************************/
+
void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
{
PointCache *cache = psys->pointcache;
@@ -1325,6 +1326,7 @@ static void bvhtree_balance_isolated(void *userdata)
/************************************************/
/* Effectors */
/************************************************/
+
static void psys_update_particle_bvhtree(ParticleSystem *psys, float cfra)
{
if (psys) {
@@ -2181,7 +2183,6 @@ void psys_sph_finalize(SPHData *sphdata)
}
}
-/* Sample the density field at a point in space. */
void psys_sph_density(BVHTree *tree, SPHData *sphdata, float co[3], float vars[2])
{
ParticleSystem **psys = sphdata->psys;
@@ -2234,6 +2235,7 @@ static void sph_integrate(ParticleSimulationData *sim,
/************************************************/
/* Basic physics */
/************************************************/
+
typedef struct EfData {
ParticleTexture ptex;
ParticleSimulationData *sim;
@@ -2787,7 +2789,6 @@ static int collision_sphere_to_verts(ParticleCollision *col,
return hit != NULL;
}
-/* Callback for BVHTree near test */
void BKE_psys_collision_neartest_cb(void *userdata,
int index,
const BVHTreeRay *ray,
@@ -3179,10 +3180,14 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
}
}
}
+
/************************************************/
/* Hair */
/************************************************/
-/* check if path cache or children need updating and do it if needed */
+
+/**
+ * Check if path cache or children need updating and do it if needed.
+ */
static void psys_update_path_cache(ParticleSimulationData *sim,
float cfra,
const bool use_render_params)
@@ -4627,7 +4632,6 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
}
}
-/* system type has changed so set sensible defaults and clear non applicable flags */
void psys_changed_type(Object *ob, ParticleSystem *psys)
{
ParticleSettings *part = psys->part;
@@ -4765,8 +4769,6 @@ static void particle_settings_free_local(ParticleSettings *particle_settings)
MEM_freeN(particle_settings);
}
-/* main particle update call, checks that things are ok on the large scale and
- * then advances in to actual particle calculations depending on particle type */
void particle_system_update(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 2318a05e635..2f22f94d142 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -78,7 +78,6 @@ void BB_reset(BB *bb)
bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
}
-/* Expand the bounding box to include a new coordinate */
void BB_expand(BB *bb, const float co[3])
{
for (int i = 0; i < 3; i++) {
@@ -87,7 +86,6 @@ void BB_expand(BB *bb, const float co[3])
}
}
-/* Expand the bounding box to include another bounding box */
void BB_expand_with_bb(BB *bb, BB *bb2)
{
for (int i = 0; i < 3; i++) {
@@ -96,7 +94,6 @@ void BB_expand_with_bb(BB *bb, BB *bb2)
}
}
-/* Return 0, 1, or 2 to indicate the widest axis of the bounding box */
int BB_widest_axis(const BB *bb)
{
float dim[3];
@@ -351,7 +348,6 @@ static void update_vb(PBVH *pbvh, PBVHNode *node, BBC *prim_bbc, int offset, int
node->orig_vb = node->vb;
}
-/* Returns the number of visible quads in the nodes' grids. */
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
const int *grid_indices,
int totgrid,
@@ -555,12 +551,6 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
build_sub(pbvh, 0, cb, prim_bbc, 0, totprim);
}
-/**
- * Do a full rebuild with on Mesh data structure.
- *
- * \note Unlike mpoly/mloop/verts, looptri is **totally owned** by PBVH
- * (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
- */
void BKE_pbvh_build_mesh(PBVH *pbvh,
const Mesh *mesh,
const MPoly *mpoly,
@@ -621,7 +611,6 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
MEM_freeN(pbvh->vert_bitmap);
}
-/* Do a full rebuild with on Grids data structure */
void BKE_pbvh_build_grids(PBVH *pbvh,
CCGElem **grids,
int totgrid,
@@ -1954,11 +1943,6 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
*r_orco_coords = node->bm_orco;
}
-/**
- * \note doing a full search on all vertices here seems expensive,
- * however this is important to avoid having to recalculate bound-box & sync the buffers to the
- * GPU (which is far more expensive!) See: T47232.
- */
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
{
BLI_assert(pbvh->type == PBVH_FACES);
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 679a8b378b9..6f57448b0ab 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1875,7 +1875,6 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
/***************************** Public API *****************************/
-/* Build a PBVH from a BMesh */
void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
bool smooth_shading,
@@ -1953,7 +1952,6 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
MEM_freeN(nodeinfo);
}
-/* Collapse short edges, subdivide long edges */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
@@ -2031,10 +2029,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
return modified;
}
-/* In order to perform operations on the original node coordinates
- * (currently just raycast), store the node's triangles and vertices.
- *
- * Skips triangles that are hidden. */
void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
{
/* Skip if original coords/triangles are already saved */
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 79b25c027ba..12c2d7aac78 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -180,9 +180,18 @@ struct PBVH {
/* pbvh.c */
void BB_reset(BB *bb);
+/**
+ * Expand the bounding box to include a new coordinate.
+ */
void BB_expand(BB *bb, const float co[3]);
+/**
+ * Expand the bounding box to include another bounding box.
+ */
void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
+/**
+ * Return 0, 1, or 2 to indicate the widest axis of the bounding box.
+ */
int BB_widest_axis(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
bool ray_face_intersection_quad(const float ray_start[3],
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 57225872c7e..df76f003498 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -266,7 +266,8 @@ static void ptcache_softbody_error(const ID *UNUSED(owner_id),
/* ignored for now */
}
-/* Particle functions */
+/* Particle functions. */
+
void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time)
{
PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, key->co);
@@ -873,6 +874,7 @@ static void ptcache_rigidbody_error(const struct ID *UNUSED(owner_id),
}
/* Creating ID's */
+
void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
{
memset(pid, 0, sizeof(PTCacheID));
@@ -1008,9 +1010,6 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-/* The fluid modifier does not actually use this anymore, but some parts of Blender expect that it
- * still has a point cache currently. For example, the fluid modifier uses
- * #DEG_add_collision_relations, which internally creates relations with the point cache. */
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *fmd)
{
FluidDomainSettings *fds = fmd->domain;
@@ -1104,10 +1103,6 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-/**
- * \param ob: Optional, may be NULL.
- * \param scene: Optional may be NULL.
- */
PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
{
PTCacheID result = {0};
@@ -1327,10 +1322,11 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
static int ptcache_path(PTCacheID *pid, char *filename)
{
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
lib->filepath_abs :
- BKE_main_blendfile_path_from_global();
+ blendfile_path;
size_t i;
if (pid->cache->flag & PTCACHE_EXTERNAL) {
@@ -1342,7 +1338,7 @@ static int ptcache_path(PTCacheID *pid, char *filename)
return BLI_path_slash_ensure(filename); /* new strlen() */
}
- if (G.relbase_valid || lib) {
+ if ((blendfile_path[0] != '\0') || lib) {
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
BLI_split_file_part(blendfilename, file, sizeof(file));
@@ -1427,8 +1423,11 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
filename[0] = '\0';
newname = filename;
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
- return 0; /* save blend file before using disk pointcache */
+ if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] == '\0') {
+ return 0; /* save blend file before using disk pointcache */
+ }
}
/* start with temp dir */
@@ -1474,8 +1473,11 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
return NULL;
}
#endif
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
- return NULL; /* save blend file before using disk pointcache */
+ if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] == '\0') {
+ return NULL; /* save blend file before using disk pointcache */
+ }
}
ptcache_filename(pid, filename, cfra, 1, 1);
@@ -1713,7 +1715,8 @@ static int ptcache_file_header_begin_write(PTCacheFile *pf)
return 1;
}
-/* Data pointer handling */
+/* Data pointer handling. */
+
int BKE_ptcache_data_size(int data_type)
{
return ptcache_data_size[data_type];
@@ -1734,7 +1737,6 @@ static void ptcache_file_pointers_init(PTCacheFile *pf)
pf->cur[BPHYS_DATA_BOIDS] = (data_types & (1 << BPHYS_DATA_BOIDS)) ? &pf->data.boids : NULL;
}
-/* Check to see if point number "index" is in pm, uses binary search for index data. */
int BKE_ptcache_mem_index_find(PTCacheMem *pm, unsigned int index)
{
if (pm->totpoint > 0 && pm->data[BPHYS_DATA_INDEX]) {
@@ -2288,7 +2290,6 @@ static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
return 1;
}
/* reads cache from disk or memory */
-/* possible to get old or interpolated result */
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
{
int cfrai = (int)floor(cfra), cfra1 = 0, cfra2 = 0;
@@ -2549,7 +2550,6 @@ static int ptcache_write_needed(PTCacheID *pid, int cfra, int *overwrite)
return 0;
}
-/* writes cache to disk or memory */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
{
PointCache *cache = pid->cache;
@@ -2600,7 +2600,8 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
* mode - PTCACHE_CLEAR_ALL,
*/
-/* Clears & resets */
+/* Clears & resets. */
+
void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
{
unsigned int len; /* store the length of the string */
@@ -2632,8 +2633,6 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
}
#endif
- // if (!G.relbase_valid) return; /* Save blend file before using pointcache. */
-
/* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
switch (mode) {
case PTCACHE_CLEAR_ALL:
@@ -3014,50 +3013,6 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
return reset;
}
-/* Use this when quitting blender, with unsaved files */
-void BKE_ptcache_remove(void)
-{
- char path[MAX_PTCACHE_PATH];
- char path_full[MAX_PTCACHE_PATH];
- int rmdir = 1;
-
- ptcache_path(NULL, path);
-
- if (BLI_exists(path)) {
- /* The pointcache dir exists? - remove all pointcache */
-
- DIR *dir;
- struct dirent *de;
-
- dir = opendir(path);
- if (dir == NULL) {
- return;
- }
-
- while ((de = readdir(dir)) != NULL) {
- if (FILENAME_IS_CURRPAR(de->d_name)) {
- /* do nothing */
- }
- else if (strstr(de->d_name, PTCACHE_EXT)) { /* Do we have the right extension? */
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
- }
- else {
- rmdir = 0; /* unknown file, don't remove the dir */
- }
- }
-
- closedir(dir);
- }
- else {
- rmdir = 0; /* Path doesn't exist. */
- }
-
- if (rmdir) {
- BLI_delete(path, true, false);
- }
-}
-
/* Point Cache handling */
PointCache *BKE_ptcache_add(ListBase *ptcaches)
@@ -3150,7 +3105,6 @@ static PointCache *ptcache_copy(PointCache *cache, const bool copy_data)
return ncache;
}
-/* returns first point cache */
PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new,
const ListBase *ptcaches_old,
const int flag)
@@ -3170,6 +3124,7 @@ PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new,
* every user action changing stuff, and then it runs a complete bake??? (ton) */
/* Baking */
+
void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
PTCacheBaker baker;
@@ -3202,7 +3157,6 @@ static void ptcache_dt_to_str(char *str, double dtime)
}
}
-/* if bake is not given run simulations to current frame */
void BKE_ptcache_bake(PTCacheBaker *baker)
{
Scene *scene = baker->scene;
@@ -3439,7 +3393,9 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
/* TODO: call redraw all windows somehow */
}
+
/* Helpers */
+
void BKE_ptcache_disk_to_mem(PTCacheID *pid)
{
PointCache *cache = pid->cache;
@@ -3495,8 +3451,9 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
{
PointCache *cache = pid->cache;
int last_exact = cache->last_exact;
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
cache->flag &= ~PTCACHE_DISK_CACHE;
if (G.debug & G_DEBUG) {
printf("File must be saved before using disk cache!\n");
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 15c5a809118..82dde79cff6 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -79,7 +79,7 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
{
PointCloud *pointcloud_dst = (PointCloud *)id_dst;
const PointCloud *pointcloud_src = (const PointCloud *)id_src;
- pointcloud_dst->mat = static_cast<Material **>(MEM_dupallocN(pointcloud_dst->mat));
+ pointcloud_dst->mat = static_cast<Material **>(MEM_dupallocN(pointcloud_src->mat));
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&pointcloud_src->pdata,
@@ -175,6 +175,7 @@ IDTypeInfo IDType_ID_PT = {
/* name_plural */ "pointclouds",
/* translation_context */ BLT_I18NCONTEXT_ID_POINTCLOUD,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ pointcloud_init_data,
/* copy_data */ pointcloud_copy_data,
@@ -182,6 +183,7 @@ IDTypeInfo IDType_ID_PT = {
/* make_local */ nullptr,
/* foreach_id */ pointcloud_foreach_id,
/* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
/* owner_get */ nullptr,
/* blend_write */ pointcloud_blend_write,
@@ -417,6 +419,7 @@ void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene
}
/* Draw Cache */
+
void (*BKE_pointcloud_batch_cache_dirty_tag_cb)(PointCloud *pointcloud, int mode) = nullptr;
void (*BKE_pointcloud_batch_cache_free_cb)(PointCloud *pointcloud) = nullptr;
diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c
index 41046563f98..4bb2231bbb1 100644
--- a/source/blender/blenkernel/intern/preferences.c
+++ b/source/blender/blenkernel/intern/preferences.c
@@ -62,10 +62,6 @@ bUserAssetLibrary *BKE_preferences_asset_library_add(UserDef *userdef,
return library;
}
-/**
- * Unlink and free a library preference member.
- * \note Free's \a library itself.
- */
void BKE_preferences_asset_library_remove(UserDef *userdef, bUserAssetLibrary *library)
{
BLI_freelinkN(&userdef->asset_libraries, library);
@@ -84,13 +80,9 @@ void BKE_preferences_asset_library_name_set(UserDef *userdef,
sizeof(library->name));
}
-/* Set the library path, ensuring it is pointing to a directory.
- * Single blend files can only act as "Current File" library; libraries on disk
- * should always be directories. If the path does not exist, that's fine; it can
- * created as directory if necessary later. */
void BKE_preferences_asset_library_path_set(bUserAssetLibrary *library, const char *path)
{
- BLI_strncpy_utf8(library->path, path, sizeof(library->path));
+ BLI_strncpy(library->path, path, sizeof(library->path));
if (BLI_is_file(library->path)) {
BLI_path_parent_dir(library->path);
}
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index 90e7ca3f11a..bc11861f2c8 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -76,11 +76,6 @@ void BKE_reports_init(ReportList *reports, int flag)
reports->flag = flag;
}
-/**
- * Only frees the list \a reports.
- * To make displayed reports disappear, either remove window-manager reports
- * (wmWindowManager.reports, or CTX_wm_reports()), or use #WM_report_banners_cancel().
- */
void BKE_reports_clear(ReportList *reports)
{
Report *report, *report_next;
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 4482285c271..75e9bc2fbee 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -103,7 +103,6 @@ static void RB_constraint_delete(void *UNUSED(con))
#endif
-/* Free rigidbody world */
void BKE_rigidbody_free_world(Scene *scene)
{
bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
@@ -160,7 +159,6 @@ void BKE_rigidbody_free_world(Scene *scene)
MEM_freeN(rbw);
}
-/* Free RigidBody settings and sim instances */
void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
{
bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
@@ -208,7 +206,6 @@ void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
ob->rigidbody_object = NULL;
}
-/* Free RigidBody constraint and sim instance */
void BKE_rigidbody_free_constraint(Object *ob)
{
RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
@@ -637,8 +634,6 @@ static void rigidbody_validate_sim_shape(RigidBodyWorld *rbw, Object *ob, bool r
/* --------------------- */
-/* helper function to calculate volume of rigidbody object */
-/* TODO: allow a parameter to specify method used to calculate this? */
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
{
RigidBodyOb *rbo = ob->rigidbody_object;
@@ -1133,12 +1128,6 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
/* --------------------- */
-/**
- * Create physics sim world given RigidBody world settings
- *
- * \note this does NOT update object references that the scene uses,
- * in case those aren't ready yet!
- */
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
/* sanity checks */
@@ -1161,7 +1150,6 @@ void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool re
/* ************************************** */
/* Setup Utilities - Create Settings Blocks */
-/* Set up RigidBody world */
RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
{
/* try to get whatever RigidBody world that might be representing this already */
@@ -1246,7 +1234,6 @@ void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func,
}
}
-/* Add rigid body settings to the specified object */
RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
{
RigidBodyOb *rbo;
@@ -1309,7 +1296,6 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
return rbo;
}
-/* Add rigid body constraint to the specified object */
RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type)
{
RigidBodyCon *rbc;
@@ -1429,11 +1415,6 @@ void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collectio
/* ************************************** */
/* Utilities API */
-/**
- * Get RigidBody world for the given scene, creating one if needed
- *
- * \param scene: Scene to find active Rigid Body world for.
- */
RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
{
/* sanity check */
@@ -2058,7 +2039,6 @@ bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe);
}
-/* Sync rigid body and object transformations */
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
{
if (!BKE_rigidbody_is_affected_by_simulation(ob)) {
@@ -2089,7 +2069,6 @@ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
}
}
-/* Used when canceling transforms - return rigidbody and object to initial states */
void BKE_rigidbody_aftertrans_update(
Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
{
@@ -2168,8 +2147,6 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* ------------------ */
-/* Rebuild rigid body world */
-/* NOTE: this needs to be called before frame update to work correctly */
void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -2209,7 +2186,6 @@ void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime
}
}
-/* Run RigidBody simulation for the specified physics world */
void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -2307,6 +2283,7 @@ void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
}
+
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
{
if (r_vol) {
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index a0bd3abbc1a..916a2786a98 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -71,6 +71,7 @@
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_bpath.h"
#include "BKE_cachefile.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
@@ -891,6 +892,45 @@ static void scene_foreach_cache(ID *id,
user_data);
}
+static bool seq_foreach_path_callback(Sequence *seq, void *user_data)
+{
+ if (SEQ_HAS_PATH(seq)) {
+ StripElem *se = seq->strip->stripdata;
+ BPathForeachPathData *bpath_data = (BPathForeachPathData *)user_data;
+
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
+ BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
+ }
+ else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
+ /* NOTE: An option not to loop over all strips could be useful? */
+ unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
+ unsigned int i;
+
+ if (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE) {
+ /* only operate on one path */
+ len = MIN2(1u, len);
+ }
+
+ for (i = 0; i < len; i++, se++) {
+ BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
+ }
+ }
+ else {
+ /* simple case */
+ BKE_bpath_foreach_path_fixed_process(bpath_data, seq->strip->dir);
+ }
+ }
+ return true;
+}
+
+static void scene_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Scene *scene = (Scene *)id;
+ if (scene->ed != NULL) {
+ SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_path_callback, bpath_data);
+ }
+}
+
static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Scene *sce = (Scene *)id;
@@ -1600,6 +1640,7 @@ IDTypeInfo IDType_ID_SCE = {
.name_plural = "scenes",
.translation_context = BLT_I18NCONTEXT_ID_SCENE,
.flags = 0,
+ .asset_type_info = NULL,
.init_data = scene_init_data,
.copy_data = scene_copy_data,
@@ -1609,6 +1650,7 @@ IDTypeInfo IDType_ID_SCE = {
.make_local = NULL,
.foreach_id = scene_foreach_id,
.foreach_cache = scene_foreach_cache,
+ .foreach_path = scene_foreach_path,
.owner_get = NULL,
.blend_write = scene_blend_write,
@@ -1659,7 +1701,6 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
-/* flag -- copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more). */
ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
{
if (toolsettings == NULL) {
@@ -1986,9 +2027,6 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
-/**
- * Check if there is any instance of the object in the scene
- */
bool BKE_scene_object_find(Scene *scene, Object *ob)
{
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
@@ -2011,12 +2049,6 @@ Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name)
return NULL;
}
-/**
- * Sets the active scene, mainly used when running in background mode
- * (`--scene` command line argument).
- * This is also called to set the scene directly, bypassing windowing code.
- * Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
- */
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
Object *ob;
@@ -2041,7 +2073,6 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
* (render code calls own animation updates). */
}
-/* called from creator_args.c */
Scene *BKE_scene_set_name(Main *bmain, const char *name)
{
Scene *sce = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, name);
@@ -2055,8 +2086,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-/* Used by meta-balls, return *all* objects (including duplis)
- * existing in the scene (including scene's sets). */
int BKE_scene_base_iter_next(
Depsgraph *depsgraph, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob)
{
@@ -2281,8 +2310,6 @@ const char *BKE_scene_find_marker_name(const Scene *scene, int frame)
return NULL;
}
-/* return the current marker for this frame,
- * we can have more than 1 marker per frame, this just returns the first :/ */
const char *BKE_scene_find_last_marker_name(const Scene *scene, int frame)
{
const TimeMarker *marker, *best_marker = NULL;
@@ -2326,7 +2353,6 @@ void BKE_scene_remove_rigidbody_object(struct Main *bmain,
}
}
-/* checks for cycle, returns 1 if it's all OK */
bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
{
Scene *sce_iter;
@@ -2349,16 +2375,11 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
return true;
}
-/* Return fractional frame number taking into account subframes and time
- * remapping. This the time value used by animation, modifiers and physics
- * evaluation. */
float BKE_scene_ctime_get(const Scene *scene)
{
return BKE_scene_frame_to_ctime(scene, scene->r.cfra);
}
-/* Convert integer frame number to fractional frame number taking into account
- * subframes and time remapping. */
float BKE_scene_frame_to_ctime(const Scene *scene, const int frame)
{
float ctime = frame;
@@ -2368,13 +2389,11 @@ float BKE_scene_frame_to_ctime(const Scene *scene, const int frame)
return ctime;
}
-/* Get current fractional frame based on frame and subframe. */
float BKE_scene_frame_get(const Scene *scene)
{
return scene->r.cfra + scene->r.subframe;
}
-/* Set current frame and subframe based on a fractional frame. */
void BKE_scene_frame_set(Scene *scene, float frame)
{
double intpart;
@@ -2411,12 +2430,6 @@ TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(Scene *scene,
return BKE_scene_orientation_slot_get(scene, slot_index);
}
-/**
- * Activate a transform orientation in a 3D view based on an enum value.
- *
- * \param orientation: If this is #V3D_ORIENT_CUSTOM or greater, the custom transform orientation
- * with index \a orientation - #V3D_ORIENT_CUSTOM gets activated.
- */
void BKE_scene_orientation_slot_set_index(TransformOrientationSlot *orient_slot, int orientation)
{
const bool is_custom = orientation >= V3D_ORIENT_CUSTOM;
@@ -2623,7 +2636,6 @@ void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
scene_graph_update_tagged(depsgraph, bmain, true);
}
-/* applies changes right away, does all sets too */
void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool clear_recalc)
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -2699,12 +2711,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
BKE_scene_graph_update_for_newframe_ex(depsgraph, true);
}
-/**
- * Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
- *
- * \warning Sets matching depsgraph as active,
- * so should only be called from the active editing context (usually, from operators).
- */
void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
@@ -2712,7 +2718,6 @@ void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, View
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
-/* return default view */
SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name)
{
SceneRenderView *srv;
@@ -2782,12 +2787,6 @@ int get_render_child_particle_number(const RenderData *r, int num, bool for_rend
return num;
}
-/**
- * Helper function for the SETLOOPER and SETLOOPER_VIEW_LAYER macros
- *
- * It iterates over the bases of the active layer and then the bases
- * of the active layer of the background (set) scenes recursively.
- */
Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base)
{
if (base && base->next) {
@@ -2852,7 +2851,6 @@ typedef enum eCyclesFeatureSet {
CYCLES_FEATURES_EXPERIMENTAL = 1,
} eCyclesFeatureSet;
-/* We cannot use const as RNA_id_pointer_create is not using a const ID. */
bool BKE_scene_uses_cycles_experimental_features(Scene *scene)
{
BLI_assert(BKE_scene_uses_cycles(scene));
@@ -2878,16 +2876,6 @@ void BKE_scene_base_flag_to_objects(ViewLayer *view_layer)
}
}
-/**
- * Synchronize object base flags
- *
- * This is usually handled by the depsgraph.
- * However, in rare occasions we need to use the latest object flags
- * before depsgraph is fully updated.
- *
- * It should (ideally) only run for copy-on-written objects since this is
- * runtime data generated per-viewlayer.
- */
void BKE_scene_object_base_flag_sync_from_base(Base *base)
{
Object *ob = base->object;
@@ -2960,10 +2948,6 @@ int BKE_render_preview_pixel_size(const RenderData *r)
return r->preview_pixel_size;
}
-/**
- * Apply the needed correction factor to value, based on unit_type
- * (only length-related are affected currently) and unit->scale_length.
- */
double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, double value)
{
if (unit->system == USER_UNIT_NONE) {
@@ -3038,7 +3022,6 @@ bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
}
-/* return whether to render this SceneRenderView */
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
{
if (srv == NULL) {
@@ -3065,7 +3048,6 @@ bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const Scene
return false;
}
-/* return true if viewname is the first or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
@@ -3087,7 +3069,6 @@ bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *
return true;
}
-/* return true if viewname is the last or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
@@ -3171,12 +3152,6 @@ void BKE_scene_multiview_filepath_get(SceneRenderView *srv, const char *filepath
BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
}
-/**
- * When multiview is not used the filepath is as usual (e.g., `Image.jpg`).
- * When multiview is on, even if only one view is enabled the view is incorporated
- * into the file name (e.g., `Image_L.jpg`). That allows for the user to re-render
- * individual views.
- */
void BKE_scene_multiview_view_filepath_get(const RenderData *rd,
const char *filepath,
const char *viewname,
@@ -3564,10 +3539,6 @@ TransformOrientation *BKE_scene_transform_orientation_find(const Scene *scene, c
return BLI_findlink(&scene->transform_spaces, index);
}
-/**
- * \return the index that \a orientation has within \a scene's transform-orientation list
- * or -1 if not found.
- */
int BKE_scene_transform_orientation_get_index(const Scene *scene,
const TransformOrientation *orientation)
{
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 6352e08ec4b..cd8493ee559 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -45,6 +45,7 @@
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_mempool.h"
@@ -97,10 +98,6 @@ static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *
}
}
-/**
- * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
- * `IDTypeInfo` structure).
- */
void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)
{
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, area->full, IDWALK_CB_NOP);
@@ -258,7 +255,6 @@ static void screen_blend_write(BlendWriter *writer, ID *id, const void *id_addre
BKE_screen_area_map_blend_write(writer, AREAMAP_FROM_SCREEN(screen));
}
-/* Cannot use IDTypeInfo callback yet, because of the return value. */
bool BKE_screen_blend_read_data(BlendDataReader *reader, bScreen *screen)
{
bool success = true;
@@ -304,6 +300,7 @@ IDTypeInfo IDType_ID_SCR = {
.name_plural = "screens",
.translation_context = BLT_I18NCONTEXT_ID_SCREEN,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -311,6 +308,7 @@ IDTypeInfo IDType_ID_SCR = {
.make_local = NULL,
.foreach_id = screen_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = screen_blend_write,
@@ -502,39 +500,35 @@ ARegion *BKE_area_region_copy(const SpaceType *st, const ARegion *region)
return newar;
}
-/* from lb2 to lb1, lb1 is supposed to be freed */
-static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
+/* from lb_src to lb_dst, lb_dst is supposed to be freed */
+static void region_copylist(SpaceType *st, ListBase *lb_dst, ListBase *lb_src)
{
/* to be sure */
- BLI_listbase_clear(lb1);
+ BLI_listbase_clear(lb_dst);
- LISTBASE_FOREACH (ARegion *, region, lb2) {
+ LISTBASE_FOREACH (ARegion *, region, lb_src) {
ARegion *region_new = BKE_area_region_copy(st, region);
- BLI_addtail(lb1, region_new);
+ BLI_addtail(lb_dst, region_new);
}
}
-/* lb1 should be empty */
-void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
+void BKE_spacedata_copylist(ListBase *lb_dst, ListBase *lb_src)
{
- BLI_listbase_clear(lb1); /* to be sure */
+ BLI_listbase_clear(lb_dst); /* to be sure */
- LISTBASE_FOREACH (SpaceLink *, sl, lb2) {
+ LISTBASE_FOREACH (SpaceLink *, sl, lb_src) {
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->duplicate) {
SpaceLink *slnew = st->duplicate(sl);
- BLI_addtail(lb1, slnew);
+ BLI_addtail(lb_dst, slnew);
region_copylist(st, &slnew->regionbase, &sl->regionbase);
}
}
}
-/* facility to set locks for drawing to survive (render) threads accessing drawing data */
-/* lock can become bitflag too */
-/* should be replaced in future by better local data handling for threads */
void BKE_spacedata_draw_locks(bool set)
{
LISTBASE_FOREACH (SpaceType *, st, &spacetypes) {
@@ -549,10 +543,6 @@ void BKE_spacedata_draw_locks(bool set)
}
}
-/**
- * Version of #BKE_area_find_region_type that also works if \a slink
- * is not the active space of \a area.
- */
ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink,
const ScrArea *area,
int region_type)
@@ -586,7 +576,6 @@ void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *area, SpaceLink *
spacedata_id_remap_cb = func;
}
-/* UNUSED!!! */
void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id)
{
if (spacedata_id_remap_cb) {
@@ -650,7 +639,6 @@ void BKE_area_region_panels_free(ListBase *panels)
BLI_listbase_clear(panels);
}
-/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *region)
{
if (st) {
@@ -684,13 +672,17 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
region_free_gizmomap_callback(region->gizmo_map);
}
+ if (region->runtime.block_name_map != NULL) {
+ BLI_ghash_free(region->runtime.block_name_map, NULL, NULL);
+ region->runtime.block_name_map = NULL;
+ }
+
BLI_freelistN(&region->ui_lists);
BLI_freelistN(&region->ui_previews);
BLI_freelistN(&region->panels_category);
BLI_freelistN(&region->panels_category_active);
}
-/* not area itself */
void BKE_screen_area_free(ScrArea *area)
{
SpaceType *st = BKE_spacetype_from_id(area->spacetype);
@@ -718,7 +710,6 @@ void BKE_screen_area_map_free(ScrAreaMap *area_map)
BLI_freelistN(&area_map->areabase);
}
-/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free_data(bScreen *screen)
{
screen_free_data(&screen->id);
@@ -881,12 +872,6 @@ void BKE_screen_remove_unused_scrverts(bScreen *screen)
/* ***************** Utilities ********************** */
-/**
- * Find a region of type \a region_type in the currently active space of \a area.
- *
- * \note This does _not_ work if the region to look up is not in the active
- * space. Use #BKE_spacedata_find_region_type if that may be the case.
- */
ARegion *BKE_area_find_region_type(const ScrArea *area, int region_type)
{
if (area) {
@@ -931,9 +916,6 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int
return NULL;
}
-/**
- * \note This is only for screen level regions (typically menus/popups).
- */
ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
{
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
@@ -946,10 +928,6 @@ ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x,
return NULL;
}
-/**
- * \note Ideally we can get the area from the context,
- * there are a few places however where this isn't practical.
- */
ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
{
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
@@ -961,10 +939,6 @@ ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
return NULL;
}
-/**
- * \note Using this function is generally a last resort, you really want to be
- * using the context when you can - campbell
- */
ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const short min)
{
ScrArea *big = NULL;
@@ -1054,14 +1028,11 @@ ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen,
return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, x, y);
}
-/* magic zoom calculation, no idea what
- * it signifies, if you find out, tell me! -zr
- */
+/* Magic zoom calculation, no idea what it signifies, if you find out, tell me! -zr
+ *
+ * Simple, its magic dude! Well, to be honest,
+ * this gives a natural feeling zooming with multiple keypad presses (ton). */
-/* simple, its magic dude!
- * well, to be honest, this gives a natural feeling zooming
- * with multiple keypad presses (ton)
- */
float BKE_screen_view3d_zoom_to_fac(float camzoom)
{
return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
@@ -1476,7 +1447,6 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
}
/* for the saved 2.50 files without regiondata */
-/* and as patch for 2.48 and older */
void BKE_screen_view3d_do_versions_250(View3D *v3d, ListBase *regions)
{
LISTBASE_FOREACH (ARegion *, region, regions) {
@@ -1783,9 +1753,6 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
BLO_read_data_address(reader, &area->v4);
}
-/**
- * \return false on error.
- */
bool BKE_screen_area_map_blend_read_data(BlendDataReader *reader, ScrAreaMap *area_map)
{
BLO_read_list(reader, &area_map->vertbase);
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
index 12017907038..a0d67a78d0f 100644
--- a/source/blender/blenkernel/intern/shader_fx.c
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -57,7 +57,6 @@ static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = {NULL};
/* *************************************************** */
/* Methods - Evaluation Loops, etc. */
-/* check if exist grease pencil effects */
bool BKE_shaderfx_has_gpencil(const Object *ob)
{
const ShaderFxData *fx;
@@ -136,7 +135,6 @@ void BKE_shaderfx_free(ShaderFxData *fx)
BKE_shaderfx_free_ex(fx, 0);
}
-/* check unique name */
bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
{
if (shaders && fx) {
@@ -164,24 +162,12 @@ const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type)
return NULL;
}
-/**
- * Check whether given shaderfx is not local (i.e. from linked data) when the object is a library
- * override.
- *
- * \param shaderfx: May be NULL, in which case we consider it as a non-local shaderfx case.
- */
bool BKE_shaderfx_is_nonlocal_in_liboverride(const Object *ob, const ShaderFxData *shaderfx)
{
return (ID_IS_OVERRIDE_LIBRARY(ob) &&
((shaderfx == NULL) || (shaderfx->flag & eShaderFxFlag_OverrideLibrary_Local) == 0));
}
-/**
- * Get an effect's panel type, which was defined in the #panelRegister callback.
- *
- * \note ShaderFx panel types are assumed to be named with the struct name field concatenated to
- * the defined prefix.
- */
void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname)
{
const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index dd863f1ce06..7618323f488 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -28,6 +28,7 @@
#include <string.h>
#include <time.h>
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -101,7 +102,6 @@ typedef struct ShrinkwrapCalcCBData {
SpaceTransform *local2aux;
} ShrinkwrapCalcCBData;
-/* Checks if the modifier needs target normals with these settings. */
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
{
return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
@@ -109,7 +109,6 @@ bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
}
-/* Initializes the mesh data structure from the given mesh and settings. */
bool BKE_shrinkwrap_init_tree(
ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
{
@@ -160,13 +159,11 @@ bool BKE_shrinkwrap_init_tree(
return true;
}
-/* Frees the tree data if necessary. */
void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
{
free_bvhtree_from_mesh(&data->treeData);
}
-/* Free boundary data for target project */
void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh)
{
struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
@@ -434,14 +431,6 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
0, calc->numVerts, &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings);
}
-/*
- * This function raycast a single vertex and updates the hit if the "hit" is considered valid.
- * Returns true if "hit" was updated.
- * Opts control whether an hit is valid or not
- * Supported options are:
- * - MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
- * - MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
- */
bool BKE_shrinkwrap_project_normal(char options,
const float vert[3],
const float dir[3],
@@ -1089,9 +1078,6 @@ static void mesh_looptri_target_project(void *userdata,
}
}
-/*
- * Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
- */
void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
BVHTreeNearest *nearest,
float co[3],
@@ -1196,13 +1182,6 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdat
}
}
-/**
- * Compute a smooth normal of the target (if applicable) at the hit location.
- *
- * \param tree: information about the mesh
- * \param transform: transform from the hit coordinate space to the object space; may be null
- * \param r_no: output in hit coordinate space; may be shared with inputs
- */
void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int looptri_idx,
@@ -1318,13 +1297,6 @@ static void shrinkwrap_snap_with_side(float r_point_co[3],
}
}
-/**
- * Apply the shrink to surface modes to the given original coordinates and nearest point.
- *
- * \param tree: mesh data for smooth normals
- * \param transform: transform from the hit coordinate space to the object space; may be null
- * \param r_point_co: may be the same memory location as point_co, hit_co, or hit_no.
- */
void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int mode,
@@ -1404,7 +1376,6 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
0, calc->numVerts, &data, shrinkwrap_calc_nearest_surface_point_cb_ex, &settings);
}
-/* Main shrinkwrap function */
void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
const ModifierEvalContext *ctx,
struct Scene *scene,
@@ -1513,6 +1484,55 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
}
}
+void shrinkwrapGpencilModifier_deform(ShrinkwrapGpencilModifierData *mmd,
+ Object *ob,
+ MDeformVert *dvert,
+ const int defgrp_index,
+ float (*vertexCos)[3],
+ int numVerts)
+{
+
+ ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+ /* Convert gpencil struct to use the same struct and function used with meshes. */
+ ShrinkwrapModifierData smd;
+ smd.target = mmd->target;
+ smd.auxTarget = mmd->aux_target;
+ smd.keepDist = mmd->keep_dist;
+ smd.shrinkType = mmd->shrink_type;
+ smd.shrinkOpts = mmd->shrink_opts;
+ smd.shrinkMode = mmd->shrink_mode;
+ smd.projLimit = mmd->proj_limit;
+ smd.projAxis = mmd->proj_axis;
+
+ /* Configure Shrinkwrap calc data. */
+ calc.smd = &smd;
+ calc.ob = ob;
+ calc.numVerts = numVerts;
+ calc.vertexCos = vertexCos;
+ calc.dvert = dvert;
+ calc.vgroup = defgrp_index;
+ calc.invert_vgroup = (mmd->flag & GP_SHRINKWRAP_INVERT_VGROUP) != 0;
+
+ BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, mmd->target);
+ calc.keepDist = mmd->keep_dist;
+ calc.tree = mmd->cache_data;
+
+ switch (mmd->shrink_type) {
+ case MOD_SHRINKWRAP_NEAREST_SURFACE:
+ case MOD_SHRINKWRAP_TARGET_PROJECT:
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), gpdeform_surface);
+ break;
+
+ case MOD_SHRINKWRAP_PROJECT:
+ TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), gpdeform_project);
+ break;
+
+ case MOD_SHRINKWRAP_NEAREST_VERTEX:
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), gpdeform_vertex);
+ break;
+ }
+}
+
void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
Object *ob_source,
Object *ob_target)
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 98e7405bde6..b0f9de5963a 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -154,6 +154,7 @@ IDTypeInfo IDType_ID_SIM = {
/* name_plural */ "simulations",
/* translation_context */ BLT_I18NCONTEXT_ID_SIMULATION,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ simulation_init_data,
/* copy_data */ simulation_copy_data,
@@ -161,6 +162,7 @@ IDTypeInfo IDType_ID_SIM = {
/* make_local */ nullptr,
/* foreach_id */ simulation_foreach_id,
/* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
/* owner_get */ nullptr,
/* blend_write */ simulation_blend_write,
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index a008edd038a..b811c17a3bc 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -3112,7 +3112,6 @@ static void sb_new_scratch(SoftBody *sb)
/* ************ Object level, exported functions *************** */
-/* allocates and initializes general main data */
SoftBody *sbNew(void)
{
SoftBody *sb;
@@ -3162,7 +3161,6 @@ SoftBody *sbNew(void)
return sb;
}
-/* frees all */
void sbFree(Object *ob)
{
SoftBody *sb = ob->soft;
@@ -3193,7 +3191,6 @@ void sbFreeSimulation(SoftBody *sb)
free_softbody_intern(sb);
}
-/* makes totally fresh start situation */
void sbObjectToSoftbody(Object *ob)
{
// ob->softflag |= OB_SB_REDO;
@@ -3213,7 +3210,6 @@ static bool object_has_edges(const Object *ob)
return false;
}
-/* SB global visible functions */
void sbSetInterruptCallBack(int (*f)(void))
{
SB_localInterruptCallBack = f;
@@ -3244,20 +3240,6 @@ static void softbody_update_positions(Object *ob,
}
}
-/* void SB_estimate_transform */
-/* input Object *ob out (says any object that can do SB like mesh, lattice, curve )
- * output float lloc[3], float lrot[3][3], float lscale[3][3]
- * that is:
- * a precise position vector denoting the motion of the center of mass
- * give a rotation/scale matrix using averaging method, that's why estimate and not calculate
- * see: this is kind of reverse engineering: having to states of a point cloud and recover what
- * happened our advantage here we know the identity of the vertex there are others methods giving
- * other results. lloc, lrot, lscale are allowed to be NULL, just in case you don't need it.
- * should be pretty useful for pythoneers :)
- * not! velocity .. 2nd order stuff
- * vcloud_estimate_transform_v3 see
- */
-
void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3])
{
BodyPoint *bp;
@@ -3523,7 +3505,6 @@ static void sbStoreLastFrame(struct Depsgraph *depsgraph, Object *object, float
object_orig->soft->last_frame = framenr;
}
-/* simulates one step. framenr is in frames */
void sbObjectStep(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index f523c5e02bd..b27231e6a17 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -54,6 +54,7 @@
# include <AUD_Special.h>
#endif
+#include "BKE_bpath.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -133,6 +134,17 @@ static void sound_foreach_cache(ID *id,
function_callback(id, &key, &sound->waveform, 0, user_data);
}
+static void sound_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ bSound *sound = (bSound *)id;
+ if (sound->packedfile != NULL && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ /* FIXME: This does not check for empty path... */
+ BKE_bpath_foreach_path_fixed_process(bpath_data, sound->filepath);
+}
+
static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
bSound *sound = (bSound *)id;
@@ -205,6 +217,7 @@ IDTypeInfo IDType_ID_SO = {
.name_plural = "sounds",
.translation_context = BLT_I18NCONTEXT_ID_SOUND,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
/* A fuzzy case, think NULLified content is OK here... */
.init_data = NULL,
@@ -213,6 +226,7 @@ IDTypeInfo IDType_ID_SO = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = sound_foreach_cache,
+ .foreach_path = sound_foreach_path,
.owner_get = NULL,
.blend_write = sound_blend_write,
@@ -257,14 +271,11 @@ BLI_INLINE void sound_verify_evaluated_id(const ID *id)
bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
{
bSound *sound;
- const char *path;
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
char str[FILE_MAX];
BLI_strncpy(str, filepath, sizeof(str));
-
- path = BKE_main_blendfile_path(bmain);
-
- BLI_path_abs(str, path);
+ BLI_path_abs(str, blendfile_path);
sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
BLI_strncpy(sound->filepath, filepath, FILE_MAX);
@@ -1235,15 +1246,14 @@ bool BKE_sound_stream_info_get(struct Main *main,
int stream,
SoundStreamInfo *sound_info)
{
- const char *path;
+ const char *blendfile_path = BKE_main_blendfile_path(main);
char str[FILE_MAX];
AUD_Sound *sound;
AUD_StreamInfo *stream_infos;
int stream_count;
BLI_strncpy(str, filepath, sizeof(str));
- path = BKE_main_blendfile_path(main);
- BLI_path_abs(str, path);
+ BLI_path_abs(str, blendfile_path);
sound = AUD_Sound_file(str);
if (!sound) {
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index 230ff9d6da0..b7199dc1e20 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -99,6 +99,7 @@ IDTypeInfo IDType_ID_SPK = {
.name_plural = "speakers",
.translation_context = BLT_I18NCONTEXT_ID_SPEAKER,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = speaker_init_data,
.copy_data = NULL,
@@ -106,6 +107,7 @@ IDTypeInfo IDType_ID_SPK = {
.make_local = NULL,
.foreach_id = speaker_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = speaker_blend_write,
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 52bbd2bec57..4ff392a5ddb 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -62,9 +62,6 @@ static SplinePtr create_spline(const Spline::Type type)
return {};
}
-/**
- * Return a new spline with the same data, settings, and attributes.
- */
SplinePtr Spline::copy() const
{
SplinePtr dst = this->copy_without_attributes();
@@ -72,9 +69,6 @@ SplinePtr Spline::copy() const
return dst;
}
-/**
- * Return a new spline with the same type and settings like "cyclic", but without any data.
- */
SplinePtr Spline::copy_only_settings() const
{
SplinePtr dst = create_spline(type_);
@@ -83,9 +77,6 @@ SplinePtr Spline::copy_only_settings() const
return dst;
}
-/**
- * The same as #copy, but skips copying dynamic attributes to the new spline.
- */
SplinePtr Spline::copy_without_attributes() const
{
SplinePtr dst = this->copy_only_settings();
@@ -185,12 +176,6 @@ static void accumulate_lengths(Span<float3> positions,
}
}
-/**
- * Return non-owning access to the cache of accumulated lengths along the spline. Each item is the
- * length of the subsequent segment, i.e. the first value is the length of the first segment rather
- * than 0. This calculation is rather trivial, and only depends on the evaluated positions.
- * However, the results are used often, and it is necessarily single threaded, so it is cached.
- */
Span<float> Spline::evaluated_lengths() const
{
if (!length_cache_dirty_) {
@@ -252,9 +237,6 @@ static void calculate_tangents(Span<float3> positions,
}
}
-/**
- * Return non-owning access to the direction of the curve at each evaluated point.
- */
Span<float3> Spline::evaluated_tangents() const
{
if (!tangent_cache_dirty_) {
@@ -375,10 +357,6 @@ static void calculate_normals_minimum(Span<float3> tangents,
}
}
-/**
- * Return non-owning access to the direction vectors perpendicular to the tangents at every
- * evaluated point. The method used to generate the normal vectors depends on Spline.normal_mode.
- */
Span<float3> Spline::evaluated_normals() const
{
if (!normal_cache_dirty_) {
@@ -428,9 +406,6 @@ Spline::LookupResult Spline::lookup_evaluated_factor(const float factor) const
return this->lookup_evaluated_length(this->length() * factor);
}
-/**
- * \note This does not support extrapolation currently.
- */
Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
{
BLI_assert(length >= 0.0f && length <= this->length());
@@ -447,11 +422,6 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
return LookupResult{index, next_index, factor};
}
-/**
- * Return an array of evenly spaced samples along the length of the spline. The samples are indices
- * and factors to the next index encoded in floats. The logic for converting from the float values
- * to interpolation data is in #lookup_data_from_index_factor.
- */
Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
{
const Span<float> lengths = this->evaluated_lengths();
@@ -532,11 +502,6 @@ GVArray Spline::interpolate_to_evaluated(GSpan data) const
return this->interpolate_to_evaluated(GVArray::ForSpan(data));
}
-/**
- * Sample any input data with a value for each evaluated point (already interpolated to evaluated
- * points) to arbitrary parameters in between the evaluated points. The interpolation is quite
- * simple, but this handles the cyclic and end point special cases.
- */
void Spline::sample_with_index_factors(const GVArray &src,
Span<float> index_factors,
GMutableSpan dst) const
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index 0cadab998f5..9ce285cebb8 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -70,9 +70,6 @@ void BezierSpline::set_resolution(const int value)
this->mark_cache_invalid();
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
void BezierSpline::add_point(const float3 position,
const HandleType handle_type_left,
const float3 handle_position_left,
@@ -203,10 +200,6 @@ static float3 next_position(Span<float3> positions, const bool cyclic, const int
return positions[i + 1];
}
-/**
- * Recalculate all #Auto and #Vector handles with positions automatically
- * derived from the neighboring control points.
- */
void BezierSpline::ensure_auto_handles() const
{
if (!auto_handles_dirty_) {
@@ -315,10 +308,6 @@ static void set_handle_position(const float3 &position,
}
}
-/**
- * Set positions for the right handle of the control point, ensuring that
- * aligned handles stay aligned. Has no effect for auto and vector type handles.
- */
void BezierSpline::set_handle_position_right(const int index, const blender::float3 &value)
{
set_handle_position(positions_[index],
@@ -329,10 +318,6 @@ void BezierSpline::set_handle_position_right(const int index, const blender::flo
handle_positions_left_[index]);
}
-/**
- * Set positions for the left handle of the control point, ensuring that
- * aligned handles stay aligned. Has no effect for auto and vector type handles.
- */
void BezierSpline::set_handle_position_left(const int index, const blender::float3 &value)
{
set_handle_position(positions_[index],
@@ -349,9 +334,6 @@ bool BezierSpline::point_is_sharp(const int index) const
ELEM(handle_types_right_[index], HandleType::Vector, HandleType::Free);
}
-/**
- * \warning This functional assumes that the spline has more than one point.
- */
bool BezierSpline::segment_is_vector(const int index) const
{
/* Two control points are necessary to form a segment, that should be checked by the caller. */
@@ -387,12 +369,6 @@ int BezierSpline::evaluated_points_size() const
return this->control_point_offsets().last();
}
-/**
- * If the spline is not cyclic, the direction for the first and last points is just the
- * direction formed by the corresponding handles and control points. In the unlikely situation
- * that the handles define a zero direction, fallback to using the direction defined by the
- * first and last evaluated segments already calculated in #Spline::evaluated_tangents().
- */
void BezierSpline::correct_end_tangents() const
{
if (is_cyclic_) {
@@ -409,25 +385,6 @@ void BezierSpline::correct_end_tangents() const
}
}
-/**
- * De Casteljau Bezier subdivision.
- * \param index: The index of the segment's start control point.
- * \param next_index: The index of the control point at the end of the segment. Could be 0,
- * if the spline is cyclic.
- * \param parameter: The factor along the segment, between 0 and 1. Note that this is used
- * directly by the calculation, it doesn't correspond to a portion of the evaluated length.
- *
- * <pre>
- * handle_prev handle_next
- * x----------------x
- * / \
- * / x---O---x \
- * / result \
- * / \
- * O O
- * point_prev point_next
- * </pre>
- */
BezierSpline::InsertResult BezierSpline::calculate_segment_insertion(const int index,
const int next_index,
const float parameter)
@@ -493,15 +450,6 @@ void BezierSpline::evaluate_segment(const int index,
}
}
-/**
- * Returns access to a cache of offsets into the evaluated point array for each control point.
- * While most control point edges generate the number of edges specified by the resolution, vector
- * segments only generate one edge.
- *
- * \note The length of the result is one greater than the number of points, so that the last item
- * is the total number of evaluated points. This is useful to avoid recalculating the size of the
- * last segment everywhere.
- */
Span<int> BezierSpline::control_point_offsets() const
{
if (!offset_cache_dirty_) {
@@ -568,12 +516,6 @@ static void calculate_mappings_linear_resolution(Span<int> offsets,
}
}
-/**
- * Returns non-owning access to an array of values containing the information necessary to
- * interpolate values from the original control points to evaluated points. The control point
- * index is the integer part of each value, and the factor used for interpolating to the next
- * control point is the remaining factional part.
- */
Span<float> BezierSpline::evaluated_mappings() const
{
if (!mapping_cache_dirty_) {
@@ -659,11 +601,6 @@ Span<float3> BezierSpline::evaluated_positions() const
return positions;
}
-/**
- * Convert the data encoded in #evaulated_mappings into its parts-- the information necessary
- * to interpolate data from control points to evaluated points between them. The next control
- * point index result will not overflow the size of the control point vectors.
- */
BezierSpline::InterpolationData BezierSpline::interpolation_data_from_index_factor(
const float index_factor) const
{
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index 7fa332a0330..69afb82baa8 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -81,9 +81,6 @@ void NURBSpline::set_order(const uint8_t value)
this->mark_cache_invalid();
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
void NURBSpline::add_point(const float3 position,
const float radius,
const float tilt,
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index d495c977285..4af68b5f270 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -45,9 +45,6 @@ int PolySpline::size() const
return size;
}
-/**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
void PolySpline::add_point(const float3 position, const float radius, const float tilt)
{
positions_.append(position);
@@ -115,12 +112,6 @@ Span<float3> PolySpline::evaluated_positions() const
return this->positions();
}
-/**
- * Poly spline interpolation from control points to evaluated points is a special case, since
- * the result data is the same as the input data. This function returns a GVArray that points to
- * the original data. Therefore the lifetime of the returned virtual array must not be longer than
- * the source data.
- */
GVArray PolySpline::interpolate_to_evaluated(const GVArray &src) const
{
BLI_assert(src.size() == this->size());
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 29f726ece71..b7690e69aa1 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -1402,7 +1402,6 @@ void BKE_studiolight_default(SolidLight lights[4], float light_ambient[3])
lights[3].vec[2] = -0.542269f;
}
-/* API */
void BKE_studiolight_init(void)
{
/* Add default studio light */
@@ -1532,7 +1531,6 @@ void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_typ
}
}
-/* Ensure state of Studiolights */
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
{
if ((sl->flag & flag) == flag) {
@@ -1570,8 +1568,9 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
}
/*
- * Python API Functions
+ * Python API Functions.
*/
+
void BKE_studiolight_remove(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
@@ -1608,7 +1607,6 @@ StudioLight *BKE_studiolight_create(const char *path,
return sl;
}
-/* Only useful for workbench while editing the userprefs. */
StudioLight *BKE_studiolight_studio_edit_get(void)
{
static StudioLight sl = {0};
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 6796b1ac397..2669da98488 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -717,7 +717,6 @@ static void minmax_v3_v3v3(const float vec[3], float min[3], float max[3])
}
}
-/* UNUSED, keep since this functionality may be useful in the future. */
static void UNUSED_FUNCTION(ccgDM_getMinMax)(DerivedMesh *dm, float r_min[3], float r_max[3])
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
@@ -912,8 +911,6 @@ static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
normal_short_to_float_v3(r_no, mvert.no);
}
-/* Translate GridHidden into the ME_HIDE flag for MVerts. Assumes
- * vertices are in the order output by ccgDM_copyFinalVertArray. */
void subsurf_copy_grid_hidden(DerivedMesh *dm,
const MPoly *mpoly,
MVert *mvert,
@@ -955,8 +952,6 @@ void subsurf_copy_grid_hidden(DerivedMesh *dm,
}
}
-/* Translate GridPaintMask into vertex paint masks. Assumes vertices
- * are in the order output by ccgDM_copyFinalVertArray. */
void subsurf_copy_grid_paint_mask(DerivedMesh *dm,
const MPoly *mpoly,
float *paint_mask,
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 7ac9e20d1a7..4406647bd2c 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -49,6 +49,7 @@
#include "DNA_text_types.h"
#include "DNA_userdef_types.h"
+#include "BKE_bpath.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -169,6 +170,15 @@ static void text_free_data(ID *id)
#endif
}
+static void text_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Text *text = (Text *)id;
+
+ if (text->filepath != NULL) {
+ BKE_bpath_foreach_path_allocated_process(bpath_data, &text->filepath);
+ }
+}
+
static void text_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Text *text = (Text *)id;
@@ -242,6 +252,7 @@ IDTypeInfo IDType_ID_TXT = {
.name_plural = "texts",
.translation_context = BLT_I18NCONTEXT_ID_TEXT,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = text_init_data,
.copy_data = text_copy_data,
@@ -249,6 +260,7 @@ IDTypeInfo IDType_ID_TXT = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = text_foreach_path,
.owner_get = NULL,
.blend_write = text_blend_write,
@@ -267,9 +279,6 @@ IDTypeInfo IDType_ID_TXT = {
/** \name Text Add, Free, Validation
* \{ */
-/**
- * \note caller must handle `compiled` member.
- */
void BKE_text_free_lines(Text *text)
{
for (TextLine *tmp = text->lines.first, *tmp_next; tmp; tmp = tmp_next) {
@@ -299,8 +308,6 @@ Text *BKE_text_add(Main *bmain, const char *name)
return ta;
}
-/* this function replaces extended ascii characters */
-/* to a valid utf-8 sequences */
int txt_extended_ascii_as_utf8(char **str)
{
ptrdiff_t bad_char, i = 0;
@@ -463,14 +470,6 @@ bool BKE_text_reload(Text *text)
return true;
}
-/**
- * Load a text file.
- *
- * \param is_internal: If \a true, this text data-block only exists in memory,
- * not as a file on disk.
- *
- * \note text data-blocks have no real user but have 'fake user' enabled by default
- */
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
{
unsigned char *buffer;
@@ -523,11 +522,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
return ta;
}
-/**
- * Load a text file.
- *
- * \note Text data-blocks have no user by default, only the 'real user' flag.
- */
Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
{
return BKE_text_load_ex(bmain, file, relpath, false);
@@ -547,11 +541,6 @@ void BKE_text_write(Text *text, const char *str) /* called directly from rna */
txt_make_dirty(text);
}
-/* returns 0 if file on disk is the same or Text is in memory only
- * returns 1 if file has been modified on disk since last local edit
- * returns 2 if file on disk has been deleted
- * -1 is returned if an error occurs */
-
int BKE_text_file_modified_check(Text *text)
{
BLI_stat_t st;
@@ -1131,7 +1120,6 @@ void txt_move_toline(Text *text, unsigned int line, const bool sel)
txt_move_to(text, line, 0, sel);
}
-/* Moves to a certain byte in a line, not a certain utf8-character! */
void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
{
TextLine **linep;
@@ -1291,11 +1279,6 @@ void txt_sel_all(Text *text)
text->selc = text->sell->len;
}
-/**
- * Reverse of #txt_pop_sel
- * Clears the selection and ensures the cursor is located
- * at the selection (where the cursor is visually while editing).
- */
void txt_sel_clear(Text *text)
{
if (text->sell) {
@@ -1382,9 +1365,6 @@ void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
* - Are not null terminated.
* \{ */
-/**
- * Create a buffer, the only requirement is #txt_from_buf_for_undo can decode it.
- */
char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
{
int buf_len = 0;
@@ -1402,9 +1382,6 @@ char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
return buf;
}
-/**
- * Decode a buffer from #txt_to_buf_for_undo.
- */
void txt_from_buf_for_undo(Text *text, const char *buf, int buf_len)
{
const char *buf_end = buf + buf_len;
@@ -2401,10 +2378,11 @@ int text_check_bracket(const char ch)
return 0;
}
-/* TODO: have a function for operators -
- * http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
bool text_check_delim(const char ch)
{
+ /* TODO: have a function for operators:
+ * http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
+
int a;
char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index a8c8eaa6a1c..ee9247e6e60 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -211,6 +211,7 @@ IDTypeInfo IDType_ID_TE = {
.name_plural = "textures",
.translation_context = BLT_I18NCONTEXT_ID_TEXTURE,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = texture_init_data,
.copy_data = texture_copy_data,
@@ -218,6 +219,7 @@ IDTypeInfo IDType_ID_TE = {
.make_local = NULL,
.foreach_id = texture_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = texture_blend_write,
@@ -230,7 +232,6 @@ IDTypeInfo IDType_ID_TE = {
.lib_override_apply_post = NULL,
};
-/* Utils for all IDs using those texture slots. */
void BKE_texture_mtex_foreach_id(LibraryForeachIDData *data, MTex *mtex)
{
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mtex->object, IDWALK_CB_NOP);
@@ -412,7 +413,6 @@ MTex *BKE_texture_mtex_add(void)
return mtex;
}
-/* slot -1 for first free ID */
MTex *BKE_texture_mtex_add_id(ID *id, int slot)
{
MTex **mtex_ar;
@@ -670,9 +670,6 @@ void BKE_texture_pointdensity_free(PointDensity *pd)
}
/* ------------------------------------------------------------------------- */
-/**
- * \returns true if this texture can use its #Texture.ima (even if its NULL)
- */
bool BKE_texture_is_image_user(const struct Tex *tex)
{
switch (tex->type) {
@@ -684,7 +681,6 @@ bool BKE_texture_is_image_user(const struct Tex *tex)
return false;
}
-/* ------------------------------------------------------------------------- */
bool BKE_texture_dependsOnTime(const struct Tex *texture)
{
if (texture->ima && BKE_image_is_animated(texture->ima)) {
@@ -758,7 +754,6 @@ static void texture_nodes_fetch_images_for_pool(Tex *texture,
}
}
-/* Make sure all images used by texture are loaded into pool. */
void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool)
{
if (texture->nodetree != NULL) {
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 3cdb8e927a6..3878d3b1c98 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -160,11 +160,6 @@ static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet)
dopesheet->tot_channel = 0;
}
-/* Free tracking structure, only frees structure contents
- * (if structure is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside structure becomes invalid after this call.
- */
void BKE_tracking_free(MovieTracking *tracking)
{
tracking_tracks_free(&tracking->tracks);
@@ -276,7 +271,6 @@ static void tracking_objects_copy(ListBase *objects_dst,
}
}
-/* Copy tracking structure content. */
void BKE_tracking_copy(MovieTracking *tracking_dst,
const MovieTracking *tracking_src,
const int flag)
@@ -321,9 +315,6 @@ void BKE_tracking_copy(MovieTracking *tracking_dst,
BLI_ghash_free(tracks_mapping, NULL, NULL);
}
-/* Initialize motion tracking settings to default values,
- * used when new movie clip datablock is created.
- */
void BKE_tracking_settings_init(MovieTracking *tracking)
{
tracking->camera.sensor_width = 35.0f;
@@ -361,7 +352,6 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
BKE_tracking_object_add(tracking, "Camera");
}
-/* Get list base of active object's tracks. */
ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -373,7 +363,6 @@ ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
return &tracking->tracks;
}
-/* Get list base of active object's plane tracks. */
ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -385,7 +374,6 @@ ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
return &tracking->plane_tracks;
}
-/* Get reconstruction data of active object. */
MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
@@ -393,9 +381,6 @@ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTrackin
return BKE_tracking_object_get_reconstruction(tracking, object);
}
-/* Get transformation matrix for a given object which is used
- * for parenting motion tracker reconstruction to 3D world.
- */
void BKE_tracking_get_camera_object_matrix(Object *camera_object, float mat[4][4])
{
BLI_assert(camera_object != NULL);
@@ -412,11 +397,6 @@ void BKE_tracking_get_camera_object_matrix(Object *camera_object, float mat[4][4
BKE_object_where_is_calc_mat4(camera_object, mat);
}
-/* Get projection matrix for camera specified by given tracking object
- * and frame number.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
MovieTrackingObject *object,
int framenr,
@@ -472,7 +452,6 @@ void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
/*********************** clipboard *************************/
-/* Free clipboard by freeing memory used by all tracks in it. */
void BKE_tracking_clipboard_free(void)
{
MovieTrackingTrack *track = tracking_clipboard.tracks.first, *next_track;
@@ -489,7 +468,6 @@ void BKE_tracking_clipboard_free(void)
BLI_listbase_clear(&tracking_clipboard.tracks);
}
-/* Copy selected tracks from specified object to the clipboard. */
void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
@@ -510,17 +488,11 @@ void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingOb
}
}
-/* Check whether there are any tracks in the clipboard. */
bool BKE_tracking_clipboard_has_tracks(void)
{
return (BLI_listbase_is_empty(&tracking_clipboard.tracks) == false);
}
-/* Paste tracks from clipboard to specified object.
- *
- * Names of new tracks in object are guaranteed to
- * be unique here.
- */
void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
@@ -541,10 +513,6 @@ void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingO
/*********************** Tracks *************************/
-/* Add new empty track to the given list of tracks.
- *
- * It is required that caller will append at least one marker to avoid degenerate tracks.
- */
MovieTrackingTrack *BKE_tracking_track_add_empty(MovieTracking *tracking, ListBase *tracks_list)
{
const MovieTrackingSettings *settings = &tracking->settings;
@@ -569,14 +537,6 @@ MovieTrackingTrack *BKE_tracking_track_add_empty(MovieTracking *tracking, ListBa
return track;
}
-/* Add new track to a specified tracks base.
- *
- * Coordinates are expected to be in normalized 0..1 space,
- * frame number is expected to be in clip space.
- *
- * Width and height are clip's dimension used to scale track's
- * pattern and search regions.
- */
MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
ListBase *tracksbase,
float x,
@@ -618,7 +578,6 @@ MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
return track;
}
-/* Duplicate the specified track, result will no belong to any list. */
MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
{
MovieTrackingTrack *new_track;
@@ -639,10 +598,6 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
return new_track;
}
-/* Ensure specified track has got unique name,
- * if it's not name of specified track will be changed
- * keeping names of all other tracks unchanged.
- */
void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *track)
{
BLI_uniquename(tracksbase,
@@ -653,11 +608,6 @@ void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *tr
sizeof(track->name));
}
-/* Free specified track, only frees contents of a structure
- * (if track is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside track becomes invalid after this call.
- */
void BKE_tracking_track_free(MovieTrackingTrack *track)
{
if (track->markers) {
@@ -665,8 +615,6 @@ void BKE_tracking_track_free(MovieTrackingTrack *track)
}
}
-/* Get frame numbers of the very first and last markers.
- * There is no check on whether the marker is enabled or not. */
void BKE_tracking_track_first_last_frame_get(const MovieTrackingTrack *track,
int *r_first_frame,
int *r_last_frame)
@@ -677,9 +625,6 @@ void BKE_tracking_track_first_last_frame_get(const MovieTrackingTrack *track,
*r_last_frame = track->markers[last_marker_index].framenr;
}
-/* Find the minimum starting frame and maximum ending frame within given set of
- * tracks.
- */
void BKE_tracking_tracks_first_last_frame_minmax(/*const*/ MovieTrackingTrack **tracks,
const int num_tracks,
int *r_first_frame,
@@ -745,11 +690,6 @@ MovieTrackingTrack **BKE_tracking_selected_tracks_in_active_object(MovieTracking
return source_tracks;
}
-/* Set flag for all specified track's areas.
- *
- * area - which part of marker should be selected. see TRACK_AREA_* constants.
- * flag - flag to be set for areas.
- */
void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
{
if (area == TRACK_AREA_NONE) {
@@ -767,11 +707,6 @@ void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
}
}
-/* Clear flag from all specified track's areas.
- *
- * area - which part of marker should be selected. see TRACK_AREA_* constants.
- * flag - flag to be cleared for areas.
- */
void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag)
{
if (area == TRACK_AREA_NONE) {
@@ -789,19 +724,11 @@ void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag
}
}
-/* Check whether track has got marker at specified frame.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
bool BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int framenr)
{
return BKE_tracking_marker_get_exact(track, framenr) != NULL;
}
-/* Check whether track has got enabled marker at specified frame.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, int framenr)
{
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
@@ -809,18 +736,6 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, i
return marker && (marker->flag & MARKER_DISABLED) == 0;
}
-/* Clear track's path:
- *
- * - If action is TRACK_CLEAR_REMAINED path from ref_frame+1 up to
- * end will be clear.
- *
- * - If action is TRACK_CLEAR_UPTO path from the beginning up to
- * ref_frame-1 will be clear.
- *
- * - If action is TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
- *
- * NOTE: frame number should be in clip space, not scene space
- */
void BKE_tracking_track_path_clear(MovieTrackingTrack *track, int ref_frame, int action)
{
int a;
@@ -1281,7 +1196,6 @@ static void track_mask_gpencil_layer_rasterize(int frame_width,
}
}
-/* Region is in pixel space, relative to marker's center. */
float *tracking_track_get_mask_for_region(int frame_width,
int frame_height,
const float region_min[2],
@@ -1336,7 +1250,6 @@ float BKE_tracking_track_get_weight_for_marker(MovieClip *clip,
return weight;
}
-/* area - which part of marker should be selected. see TRACK_AREA_* constants */
void BKE_tracking_track_select(ListBase *tracksbase,
MovieTrackingTrack *track,
int area,
@@ -1510,16 +1423,6 @@ void BKE_tracking_marker_clamp(MovieTrackingMarker *marker, int event)
}
}
-/**
- * Get marker closest to the given frame number.
- *
- * If there is maker with exact frame number it returned.
- * Otherwise, marker with highest frame number but lower than the requested
- * frame is returned if such marker exists. Otherwise, the marker with lowest
- * frame number greater than the requested frame number is returned.
- *
- * This function has complexity of `O(log number_of_markers)`.
- */
MovieTrackingMarker *BKE_tracking_marker_get(MovieTrackingTrack *track, int framenr)
{
const int num_markers = track->markersnr;
@@ -1705,7 +1608,6 @@ void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track,
/*********************** Plane Track *************************/
-/* Creates new plane track out of selected point tracks */
MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking,
ListBase *plane_tracks_base,
ListBase *tracks,
@@ -1789,11 +1691,6 @@ void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base,
sizeof(plane_track->name));
}
-/* Free specified plane track, only frees contents of a structure
- * (if track is allocated in heap, it shall be handled outside).
- *
- * All the pointers inside track becomes invalid after this call.
- */
void BKE_tracking_plane_track_free(MovieTrackingPlaneTrack *plane_track)
{
if (plane_track->markers) {
@@ -1988,9 +1885,6 @@ void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int
* would be nice to de-duplicate them somehow..
*/
-/* Get a plane marker at given frame,
- * If there's no such marker, closest one from the left side will be returned.
- */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2039,9 +1933,6 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack
return NULL;
}
-/* Get a plane marker at exact given frame, if there's no marker at the frame,
- * NULL will be returned.
- */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2054,7 +1945,6 @@ MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlane
return plane_marker;
}
-/* Ensure there's a marker for the given frame. */
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track,
int framenr)
{
@@ -2326,7 +2216,6 @@ static void reconstructed_camera_scale_set(MovieTrackingObject *object, float ma
}
}
-/* converts principal offset from center to offset of blender's camera */
void BKE_tracking_camera_shift_get(
MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
{
@@ -2899,10 +2788,6 @@ ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf,
return searchibuf;
}
-/* zap channels from the imbuf that are disabled by the user. this can lead to
- * better tracks sometimes. however, instead of simply zeroing the channels
- * out, do a partial grayscale conversion so the display is better.
- */
void BKE_tracking_disable_channels(
ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale)
{
@@ -3417,9 +3302,6 @@ static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
MEM_freeN(per_frame_counter);
}
-/* Tag dopesheet for update, actual update will happen later
- * when it'll be actually needed.
- */
void BKE_tracking_dopesheet_tag_update(MovieTracking *tracking)
{
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
@@ -3427,7 +3309,6 @@ void BKE_tracking_dopesheet_tag_update(MovieTracking *tracking)
dopesheet->ok = false;
}
-/* Do dopesheet update, if update is not needed nothing will happen. */
void BKE_tracking_dopesheet_update(MovieTracking *tracking)
{
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
@@ -3451,7 +3332,6 @@ void BKE_tracking_dopesheet_update(MovieTracking *tracking)
dopesheet->ok = true;
}
-/* NOTE: Returns NULL if the track comes from camera object, */
MovieTrackingObject *BKE_tracking_find_object_for_track(const MovieTracking *tracking,
const MovieTrackingTrack *track)
{
@@ -3479,7 +3359,6 @@ ListBase *BKE_tracking_find_tracks_list_for_track(MovieTracking *tracking,
return &tracking->tracks;
}
-/* NOTE: Returns NULL if the track comes from camera object, */
MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
const MovieTracking *tracking, const MovieTrackingPlaneTrack *plane_track)
{
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index e2a29d7858d..c83e595c611 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -775,7 +775,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
}
/* TODO(sergey): Find a way to avoid this, somehow making all needed logic in
- * BKE_autotrack_context_sync(). */
+ * #BKE_autotrack_context_sync(). */
void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user)
{
user->framenr = context->synchronized_scene_frame;
diff --git a/source/blender/blenkernel/intern/tracking_detect.c b/source/blender/blenkernel/intern/tracking_detect.c
index 08719161e1a..be680ef8a8b 100644
--- a/source/blender/blenkernel/intern/tracking_detect.c
+++ b/source/blender/blenkernel/intern/tracking_detect.c
@@ -148,7 +148,6 @@ static void run_configured_detector(MovieTracking *tracking,
}
}
-/* Detect features using FAST detector */
void BKE_tracking_detect_fast(MovieTracking *tracking,
ListBase *tracksbase,
ImBuf *ibuf,
@@ -170,7 +169,6 @@ void BKE_tracking_detect_fast(MovieTracking *tracking,
tracking, tracksbase, ibuf, framenr, layer, place_outside_layer, &options);
}
-/* Detect features using Harris detector */
void BKE_tracking_detect_harris(MovieTracking *tracking,
ListBase *tracksbase,
ImBuf *ibuf,
diff --git a/source/blender/blenkernel/intern/tracking_plane_tracker.c b/source/blender/blenkernel/intern/tracking_plane_tracker.c
index b787cd366c5..d4a5bb2aa9d 100644
--- a/source/blender/blenkernel/intern/tracking_plane_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_plane_tracker.c
@@ -167,7 +167,6 @@ static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_trac
}
}
-/* NOTE: frame number should be in clip space, not scene space */
void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track,
int start_frame)
{
diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c
index 179def0a6f2..ad3f226fa92 100644
--- a/source/blender/blenkernel/intern/tracking_region_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_region_tracker.c
@@ -180,7 +180,6 @@ static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip,
return ibuf;
}
-/* Fill in libmv tracker options structure with settings need to be used to perform track. */
void tracking_configure_tracker(const MovieTrackingTrack *track,
float *mask,
const bool is_backwards,
@@ -311,11 +310,6 @@ static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
return (reference->flag & MARKER_DISABLED) == 0;
}
-/* Refine marker's position using previously known keyframe.
- * Direction of searching for a keyframe depends on backwards flag,
- * which means if backwards is false, previous keyframe will be as
- * reference.
- */
void BKE_tracking_refine_marker(MovieClip *clip,
MovieTrackingTrack *track,
MovieTrackingMarker *marker,
diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c
index d89d36f85ea..47a955c9d93 100644
--- a/source/blender/blenkernel/intern/tracking_solver.c
+++ b/source/blender/blenkernel/intern/tracking_solver.c
@@ -325,7 +325,6 @@ static int reconstruct_count_tracks_on_both_keyframes(MovieTracking *tracking,
return tot;
}
-/* Perform early check on whether everything is fine to start reconstruction. */
bool BKE_tracking_reconstruction_check(MovieTracking *tracking,
MovieTrackingObject *object,
char *error_msg,
@@ -354,11 +353,6 @@ bool BKE_tracking_reconstruction_check(MovieTracking *tracking,
return true;
}
-/* Create context for camera/object motion reconstruction.
- * Copies all data needed for reconstruction from movie
- * clip datablock, so editing this clip is safe during
- * reconstruction job is in progress.
- */
MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip,
MovieTrackingObject *object,
int keyframe1,
@@ -446,7 +440,6 @@ const char *BKE_tracking_reconstruction_error_message_get(const MovieReconstruct
return context->error_message;
}
-/* Free memory used by a reconstruction process. */
void BKE_tracking_reconstruction_context_free(MovieReconstructContext *context)
{
if (context->reconstruction) {
@@ -486,15 +479,6 @@ static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *recons
reconstruction_options->refine_intrinsics = context->refine_flags;
}
-/* Solve camera/object motion and reconstruct 3D markers position
- * from a prepared reconstruction context.
- *
- * stop is not actually used at this moment, so reconstruction
- * job could not be stopped.
- *
- * do_update, progress and stat_message are set by reconstruction
- * callback in libmv side and passing to an interface.
- */
void BKE_tracking_reconstruction_solve(MovieReconstructContext *context,
short *stop,
short *do_update,
@@ -542,9 +526,6 @@ void BKE_tracking_reconstruction_solve(MovieReconstructContext *context,
context->reprojection_error = error;
}
-/* Finish reconstruction process by copying reconstructed data
- * to an actual movie clip datablock.
- */
bool BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTracking *tracking)
{
MovieTrackingReconstruction *reconstruction;
@@ -608,9 +589,6 @@ static void tracking_scale_reconstruction(ListBase *tracksbase,
}
}
-/* Apply scale on all reconstructed cameras and bundles,
- * used by camera scale apply operator.
- */
void BKE_tracking_reconstruction_scale(MovieTracking *tracking, float scale[3])
{
LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index d5585116f7e..fe9a2f2268a 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -1252,24 +1252,6 @@ static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect)
/* === public interface functions === */
-/* Get stabilization data (translation, scaling and angle) for a given frame.
- * Returned data describes how to compensate the detected movement, but with any
- * chosen scale factor already applied and any target frame position already
- * compensated. In case stabilization fails or is disabled, neutral values are
- * returned.
- *
- * framenr is a frame number, relative to the clip (not relative to the scene
- * timeline)
- * width is an effective width of the canvas (square pixels), used to scale the
- * determined translation
- *
- * Outputs:
- * - translation of the lateral shift, absolute canvas coordinates
- * (square pixels).
- * - scale of the scaling to apply
- * - angle of the rotation angle, relative to the frame center
- */
-/* TODO(sergey): Use r_ prefix for output parameters here. */
void BKE_tracking_stabilization_data_get(MovieClip *clip,
int framenr,
int width,
@@ -1307,7 +1289,7 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
discard_stabilization_working_context(ctx);
}
-typedef void (*interpolation_func)(struct ImBuf *, struct ImBuf *, float, float, int, int);
+typedef void (*interpolation_func)(const struct ImBuf *, struct ImBuf *, float, float, int, int);
typedef struct TrackingStabilizeFrameInterpolationData {
ImBuf *ibuf;
@@ -1336,12 +1318,6 @@ static void tracking_stabilize_frame_interpolation_cb(
}
}
-/* Stabilize given image buffer using stabilization data for a specified
- * frame number.
- *
- * NOTE: frame number should be in clip space, not scene space.
- */
-/* TODO(sergey): Use r_ prefix for output parameters here. */
ImBuf *BKE_tracking_stabilize_frame(
MovieClip *clip, int framenr, ImBuf *ibuf, float translation[2], float *scale, float *angle)
{
@@ -1449,16 +1425,6 @@ ImBuf *BKE_tracking_stabilize_frame(
return tmpibuf;
}
-/* Build a 4x4 transformation matrix based on the given 2D stabilization data.
- * mat is a 4x4 matrix in homogeneous coordinates, adapted to the
- * final image buffer size and compensated for pixel aspect ratio,
- * ready for direct OpenGL drawing.
- *
- * TODO(sergey): The signature of this function should be changed. we actually
- * don't need the dimensions of the image buffer. Instead we
- * should consider to provide the pivot point of the rotation as a
- * further stabilization data parameter.
- */
void BKE_tracking_stabilization_data_to_mat4(int buffer_width,
int buffer_height,
float pixel_aspect,
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 16b36e94328..f1fd3a13e0e 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -338,11 +338,6 @@ static void search_pixel_to_marker_unified(int frame_width,
sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
}
-/* Each marker has 5 coordinates associated with it that get warped with
- * tracking: the four corners ("pattern_corners"), and the center ("pos").
- * This function puts those 5 points into the appropriate frame for tracking
- * (the "search" coordinate frame).
- */
void tracking_get_marker_coords_for_tracking(int frame_width,
int frame_height,
const MovieTrackingMarker *marker,
@@ -369,7 +364,6 @@ void tracking_get_marker_coords_for_tracking(int frame_width,
search_pixel_y[4] = pixel_coords[1] - 0.5f;
}
-/* Inverse of above. */
void tracking_set_marker_coords_from_tracking(int frame_width,
int frame_height,
MovieTrackingMarker *marker,
@@ -411,15 +405,6 @@ void tracking_set_marker_coords_from_tracking(int frame_width,
/** \name General Purpose Utility Functions
* \{ */
-/* Place a disabled marker before or after specified ref_marker.
- *
- * If before is truth, disabled marker is placed before reference
- * one, and it's placed after it otherwise.
- *
- * If there's already a marker at the frame where disabled one
- * is expected to be placed, nothing will happen if overwrite
- * is false.
- */
void tracking_marker_insert_disabled(MovieTrackingTrack *track,
const MovieTrackingMarker *ref_marker,
bool before,
@@ -526,7 +511,6 @@ static void distortion_model_parameters_from_options(
BLI_assert_msg(0, "Unknown distortion model");
}
-/* Fill in Libmv C-API camera intrinsics options from tracking structure. */
void tracking_cameraIntrinscisOptionsFromTracking(
MovieTracking *tracking,
int calibration_width,
@@ -563,7 +547,6 @@ void tracking_trackingCameraFromIntrinscisOptions(
distortion_model_parameters_from_options(camera_intrinsics_options, camera);
}
-/* Get previous keyframed marker. */
MovieTrackingMarker *tracking_get_keyframed_marker(MovieTrackingTrack *track,
int current_frame,
bool backwards)
diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc
index b1611679ced..b23220286e6 100644
--- a/source/blender/nodes/intern/type_conversions.cc
+++ b/source/blender/blenkernel/intern/type_conversions.cc
@@ -14,7 +14,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "NOD_type_conversions.hh"
+#include "BKE_type_conversions.hh"
#include "FN_multi_function_builder.hh"
@@ -22,18 +22,18 @@
#include "BLI_float2.hh"
#include "BLI_float3.hh"
-namespace blender::nodes {
+namespace blender::bke {
using fn::MFDataType;
template<typename From, typename To, To (*ConversionF)(const From &)>
static void add_implicit_conversion(DataTypeConversions &conversions)
{
- const CPPType &from_type = CPPType::get<From>();
- const CPPType &to_type = CPPType::get<To>();
- const std::string conversion_name = from_type.name() + " to " + to_type.name();
+ static const CPPType &from_type = CPPType::get<From>();
+ static const CPPType &to_type = CPPType::get<To>();
+ static const std::string conversion_name = from_type.name() + " to " + to_type.name();
- static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF};
+ static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name.c_str(), ConversionF};
static auto convert_single_to_initialized = [](const void *src, void *dst) {
*(To *)dst = ConversionF(*(const From *)src);
};
@@ -239,6 +239,23 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type,
functions->convert_single_to_uninitialized(from_value, to_value);
}
+void DataTypeConversions::convert_to_initialized_n(fn::GSpan from_span,
+ fn::GMutableSpan to_span) const
+{
+ const CPPType &from_type = from_span.type();
+ const CPPType &to_type = to_span.type();
+ BLI_assert(from_span.size() == to_span.size());
+ BLI_assert(this->is_convertible(from_type, to_type));
+ const fn::MultiFunction *fn = this->get_conversion_multi_function(
+ MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type));
+ fn::MFParamsBuilder params{*fn, from_span.size()};
+ params.add_readonly_single_input(from_span);
+ to_type.destruct_n(to_span.data(), to_span.size());
+ params.add_uninitialized_single_output(to_span);
+ fn::MFContextBuilder context;
+ fn->call_auto(IndexRange(from_span.size()), params, context);
+}
+
class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl {
private:
fn::GVArray varray_;
@@ -344,4 +361,4 @@ fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray,
std::move(varray), to_type, *this);
}
-} // namespace blender::nodes
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 26d37489e35..3e263fafe28 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -61,13 +61,39 @@
static CLG_LogRef LOG = {"bke.undosys"};
/* -------------------------------------------------------------------- */
+/** \name Undo Types
+ * \{ */
+
+const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL;
+const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL;
+
+static ListBase g_undo_types = {NULL, NULL};
+
+static const UndoType *BKE_undosys_type_from_context(bContext *C)
+{
+ LISTBASE_FOREACH (const UndoType *, ut, &g_undo_types) {
+ /* No poll means we don't check context. */
+ if (ut->poll && ut->poll(C)) {
+ return ut;
+ }
+ }
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Internal Nested Undo Checks
*
* Make sure we're not running undo operations from 'step_encode', 'step_decode' callbacks.
* bugs caused by this situation aren't _that_ hard to spot but aren't always so obvious.
* Best we have a check which shows the problem immediately.
- *
* \{ */
+
#define WITH_NESTED_UNDO_CHECK
#ifdef WITH_NESTED_UNDO_CHECK
@@ -90,36 +116,9 @@ static bool g_undo_callback_running = false;
# define UNDO_NESTED_CHECK_BEGIN ((void)0)
# define UNDO_NESTED_CHECK_END ((void)0)
#endif
-/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Public Undo Types
- *
- * Unfortunately we need this for a handful of places.
- * \{ */
-const UndoType *BKE_UNDOSYS_TYPE_IMAGE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_MEMFILE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_PAINTCURVE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_PARTICLE = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_SCULPT = NULL;
-const UndoType *BKE_UNDOSYS_TYPE_TEXT = NULL;
/** \} */
-/* UndoType */
-
-static ListBase g_undo_types = {NULL, NULL};
-
-static const UndoType *BKE_undosys_type_from_context(bContext *C)
-{
- LISTBASE_FOREACH (const UndoType *, ut, &g_undo_types) {
- /* No poll means we don't check context. */
- if (ut->poll && ut->poll(C)) {
- return ut;
- }
- }
- return NULL;
-}
-
/* -------------------------------------------------------------------- */
/** \name Internal Callback Wrappers
*
@@ -358,7 +357,6 @@ void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
undosys_stack_push_main(ustack, IFACE_("Original"), bmain);
}
-/* called after 'BKE_undosys_stack_init_from_main' */
void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C)
{
const UndoType *ut = BKE_undosys_type_from_context(C);
@@ -367,7 +365,6 @@ void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C)
}
}
-/* name optional */
bool BKE_undosys_stack_has_undo(const UndoStack *ustack, const char *name)
{
if (name) {
@@ -397,10 +394,6 @@ UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const Un
return BKE_undosys_stack_active_with_type(ustack, ut);
}
-/**
- * \param steps: Limit the number of undo steps.
- * \param memory_limit: Limit the amount of memory used by the undo stack.
- */
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
{
UNDO_NESTED_ASSERT(false);
@@ -455,6 +448,10 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Undo Step
+ * \{ */
+
UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
bContext *C,
const char *name,
@@ -497,9 +494,6 @@ UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
}
-/**
- * \param C: Can be NULL from some callers if their encoding function doesn't need it
- */
eUndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
bContext *C,
const char *name,
@@ -613,9 +607,6 @@ eUndoPushReturn BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_with_type(ustack, C, name, ut);
}
-/**
- * Useful when we want to diff against previous undo data but can't be sure the types match.
- */
UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
{
if (us) {
@@ -629,9 +620,6 @@ UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
return us;
}
-/**
- * Useful when we want to diff against previous undo data but can't be sure the types match.
- */
UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us)
{
if (us) {
@@ -674,14 +662,6 @@ UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut)
return NULL;
}
-/**
- * Return direction of the undo/redo from `us_reference` (or `ustack->step_active` if NULL), and
- * `us_target`.
- *
- * \note If `us_reference` and `us_target` are the same, we consider this is an undo.
- *
- * \return -1 for undo, 1 for redo, 0 in case of error.
- */
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack,
const UndoStep *us_target,
const UndoStep *us_reference)
@@ -741,19 +721,6 @@ static UndoStep *undosys_step_iter_first(UndoStep *us_reference, const eUndoStep
return (undo_dir == -1) ? us_reference->prev : us_reference->next;
}
-/**
- * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target`
- * will become the active step.
- *
- * \note In case `use_skip` is true, the final target will always be **beyond** the given one
- * (if the given one has to be skipped).
- *
- * \param us_reference: If NULL, will be set to current active step in the undo stack. Otherwise,
- * it is assumed to match the current state, and will be used as basis for the undo/redo process
- * (i.e. all steps in-between `us_reference` and `us_target` will be processed).
- */
bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -842,37 +809,22 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
return false;
}
-/**
- * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
- */
bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
/* Note that here we do not skip 'skipped' steps by default. */
return BKE_undosys_step_load_data_ex(ustack, C, us_target, NULL, false);
}
-/**
- * Undo/Redo until the step matching given `index` in the undo stack becomes the active (currently
- * loaded) one.
- */
void BKE_undosys_step_load_from_index(UndoStack *ustack, bContext *C, const int index)
{
UndoStep *us_target = BLI_findlink(&ustack->steps, index);
BLI_assert(us_target->skip == false);
+ if (us_target == ustack->step_active) {
+ return;
+ }
BKE_undosys_step_load_data(ustack, C, us_target);
}
-/**
- * Undo until `us_target` step becomes the active (currently loaded) one.
- *
- * \warning This function assumes that the given target step is _before_ current active one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the
- * active step.
- *
- * \note In case `use_skip` is true, the final target will always be **before** the given one (if
- * the given one has to be skipped).
- */
bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -888,19 +840,11 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
return BKE_undosys_step_load_data_ex(ustack, C, us_target, us_reference, use_skip);
}
-/**
- * Undo until `us_target` step becomes the active (currently loaded) one.
- *
- * \note See #BKE_undosys_step_undo_with_data_ex for details.
- */
bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
return BKE_undosys_step_undo_with_data_ex(ustack, C, us_target, true);
}
-/**
- * Undo one step from current active (currently loaded) one.
- */
bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
{
if (ustack->step_active != NULL) {
@@ -909,17 +853,6 @@ bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
return false;
}
-/**
- * Redo until `us_target` step becomes the active (currently loaded) one.
- *
- * \warning This function assumes that the given target step is _after_ current active one.
- *
- * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target` will become the
- * active step.
- *
- * \note In case `use_skip` is true, the final target will always be **after** the given one (if
- * the given one has to be skipped).
- */
bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
bContext *C,
UndoStep *us_target,
@@ -934,19 +867,11 @@ bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
return BKE_undosys_step_load_data_ex(ustack, C, us_target, us_reference, use_skip);
}
-/**
- * Redo until `us_target` step becomes the active (currently loaded) one.
- *
- * \note See #BKE_undosys_step_redo_with_data_ex for details.
- */
bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
{
return BKE_undosys_step_redo_with_data_ex(ustack, C, us_target, true);
}
-/**
- * Redo one step from current active one.
- */
bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
{
if (ustack->step_active != NULL) {
@@ -955,9 +880,6 @@ bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
return false;
}
-/**
- * Similar to #WM_operatortype_append
- */
UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *))
{
UndoType *ut;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 4e9a3c9fb2e..fde3ac13ceb 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -1091,22 +1091,6 @@ double BKE_unit_apply_preferred_unit(const struct UnitSettings *settings, int ty
return value * scalar + bias;
}
-/**
- * Make a copy of the string that replaces the units with numbers.
- *
- * This is only used when evaluating user input and can afford to be a bit slower
- *
- * This is to be used before python evaluation so..
- * 10.1km -> 10.1*1000.0
- * ...will be resolved by python.
- *
- * Values will be split by an add sign.
- * 5'2" -> 5*0.3048 + 2*0.0254
- *
- * \param str_prev: is optional, when valid it is used to get a base unit when none is set.
- *
- * \return True of a change was made.
- */
bool BKE_unit_replace_string(
char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
@@ -1196,7 +1180,6 @@ bool BKE_unit_replace_string(
return changed;
}
-/* 45µm --> 45um */
void BKE_unit_name_to_alt(char *str, int len_max, const char *orig_str, int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c
index 43c8a59baad..4a598288ee6 100644
--- a/source/blender/blenkernel/intern/vfont.c
+++ b/source/blender/blenkernel/intern/vfont.c
@@ -49,6 +49,7 @@
#include "DNA_vfont_types.h"
#include "BKE_anim_path.h"
+#include "BKE_bpath.h"
#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -123,6 +124,21 @@ static void vfont_free_data(ID *id)
}
}
+static void vfont_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ VFont *vfont = (VFont *)id;
+
+ if (vfont->packedfile != NULL && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ if (BKE_vfont_is_builtin(vfont)) {
+ return;
+ }
+
+ BKE_bpath_foreach_path_fixed_process(bpath_data, vfont->filepath);
+}
+
static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
VFont *vf = (VFont *)id;
@@ -162,6 +178,7 @@ IDTypeInfo IDType_ID_VF = {
.name_plural = "fonts",
.translation_context = BLT_I18NCONTEXT_ID_VFONT,
.flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = vfont_init_data,
.copy_data = vfont_copy_data,
@@ -169,6 +186,7 @@ IDTypeInfo IDType_ID_VF = {
.make_local = NULL,
.foreach_id = NULL,
.foreach_cache = NULL,
+ .foreach_path = vfont_foreach_path,
.owner_get = NULL,
.blend_write = vfont_blend_write,
@@ -183,7 +201,6 @@ IDTypeInfo IDType_ID_VF = {
/***************************** VFont *******************************/
-/* The vfont code */
void BKE_vfont_free_data(struct VFont *vfont)
{
if (vfont->data) {
@@ -1743,10 +1760,6 @@ bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
return BKE_vfont_to_curve_ex(ob, ob->data, mode, r_nubase, NULL, NULL, NULL, NULL);
}
-/**
- * Warning: expects to have access to evaluated data
- * (i.e. passed object should be evaluated one...).
- */
bool BKE_vfont_to_curve(Object *ob, int mode)
{
Curve *cu = ob->data;
diff --git a/source/blender/blenkernel/intern/vfontdata_freetype.c b/source/blender/blenkernel/intern/vfontdata_freetype.c
index bd58d156d06..9b79d5635d1 100644
--- a/source/blender/blenkernel/intern/vfontdata_freetype.c
+++ b/source/blender/blenkernel/intern/vfontdata_freetype.c
@@ -396,14 +396,6 @@ static bool check_freetypefont(PackedFile *pf)
return success;
}
-/**
- * Construct a new VFontData structure from
- * Freetype font data in a PackedFile.
- *
- * \param pf: The font data.
- * \retval A new VFontData structure, or NULL
- * if unable to load.
- */
VFontData *BKE_vfontdata_from_freetypefont(PackedFile *pf)
{
VFontData *vfd = NULL;
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index a72b5268e1d..130aa957491 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -41,6 +41,7 @@
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
+#include "BKE_bpath.h"
#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -576,6 +577,18 @@ static void volume_foreach_cache(ID *id,
function_callback(id, &key, (void **)&volume->runtime.grids, 0, user_data);
}
+static void volume_foreach_path(ID *id, BPathForeachPathData *bpath_data)
+{
+ Volume *volume = reinterpret_cast<Volume *>(id);
+
+ if (volume->packedfile != nullptr &&
+ (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
+ return;
+ }
+
+ BKE_bpath_foreach_path_fixed_process(bpath_data, volume->filepath);
+}
+
static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
Volume *volume = (Volume *)id;
@@ -645,6 +658,7 @@ IDTypeInfo IDType_ID_VO = {
/* name_plural */ "volumes",
/* translation_context */ BLT_I18NCONTEXT_ID_VOLUME,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /* asset_type_info */ nullptr,
/* init_data */ volume_init_data,
/* copy_data */ volume_copy_data,
@@ -652,6 +666,7 @@ IDTypeInfo IDType_ID_VO = {
/* make_local */ nullptr,
/* foreach_id */ volume_foreach_id,
/* foreach_cache */ volume_foreach_cache,
+ /* foreach_path */ volume_foreach_path,
/* owner_get */ nullptr,
/* blend_write */ volume_blend_write,
@@ -1225,7 +1240,6 @@ const VolumeGrid *BKE_volume_grid_active_get_for_read(const Volume *volume)
return BKE_volume_grid_get_for_read(volume, index);
}
-/* Tries to find a grid with the given name. Make sure that the volume has been loaded. */
const VolumeGrid *BKE_volume_grid_find_for_read(const Volume *volume, const char *name)
{
int num_grids = BKE_volume_num_grids(volume);
@@ -1365,7 +1379,6 @@ int BKE_volume_grid_channels(const VolumeGrid *grid)
return 0;
}
-/* Transformation from index space to object space. */
void BKE_volume_grid_transform_matrix(const VolumeGrid *volume_grid, float mat[4][4])
{
#ifdef WITH_OPENVDB
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 6269cfc4349..e3fe1e04368 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -187,6 +187,7 @@ IDTypeInfo IDType_ID_WS = {
.name_plural = "workspaces",
.translation_context = BLT_I18NCONTEXT_ID_WORKSPACE,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = workspace_init_data,
.copy_data = NULL,
@@ -194,6 +195,7 @@ IDTypeInfo IDType_ID_WS = {
.make_local = NULL,
.foreach_id = workspace_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = workspace_blend_write,
@@ -319,13 +321,6 @@ WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
return new_workspace;
}
-/**
- * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
- * calls #workspace_free_data (through #BKE_id_free) to free the workspace data, and frees
- * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
- *
- * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
- */
void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
{
for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout;
@@ -369,9 +364,6 @@ void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *
MEM_freeN(hook);
}
-/**
- * Add a new layout to \a workspace for \a screen.
- */
WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain,
WorkSpace *workspace,
bScreen *screen,
@@ -434,13 +426,6 @@ WorkSpaceLayout *BKE_workspace_layout_find(const WorkSpace *workspace, const bSc
return NULL;
}
-/**
- * Find the layout for \a screen without knowing which workspace to look in.
- * Can also be used to find the workspace that contains \a screen.
- *
- * \param r_workspace: Optionally return the workspace that contains the
- * looked up layout (if found).
- */
WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
const bScreen *screen,
WorkSpace **r_workspace)
@@ -464,15 +449,6 @@ WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
return NULL;
}
-/**
- * Circular workspace layout iterator.
- *
- * \param callback: Custom function which gets executed for each layout.
- * Can return false to stop iterating.
- * \param arg: Custom data passed to each \a callback call.
- *
- * \return the layout at which \a callback returned false.
- */
WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace,
WorkSpaceLayout *start,
bool (*callback)(const WorkSpaceLayout *layout,
@@ -564,18 +540,11 @@ void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
}
}
-/**
- * Get the layout that is active for \a hook (which is the visible layout for the active workspace
- * in \a hook).
- */
WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
{
return hook->act_layout;
}
-/**
- * Get the layout to be activated should \a workspace become or be the active workspace in \a hook.
- */
WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceInstanceHook *hook,
const WorkSpace *workspace)
{
@@ -588,17 +557,6 @@ WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceIn
return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
}
-/**
- * \brief Activate a layout
- *
- * Sets \a layout as active for \a workspace when activated through or already active in \a hook.
- * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of
- * \a hook too. See #BKE_workspace_active_set().
- *
- * \a workspace does not need to be active for this.
- *
- * WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer.
- */
void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook,
const int winid,
WorkSpace *workspace,
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 2f0a282a298..b2e90b7ba12 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -192,6 +192,7 @@ IDTypeInfo IDType_ID_WO = {
.name_plural = "worlds",
.translation_context = BLT_I18NCONTEXT_ID_WORLD,
.flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ .asset_type_info = NULL,
.init_data = world_init_data,
.copy_data = world_copy_data,
@@ -199,6 +200,7 @@ IDTypeInfo IDType_ID_WO = {
.make_local = NULL,
.foreach_id = world_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = world_blend_write,
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 4635db98514..a4f20f980b4 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -315,7 +315,6 @@ static void context_free_avi(void *context_v)
#endif /* WITH_AVI */
-/* similar to BKE_image_path_from_imformat() */
void BKE_movie_filepath_get(char *string, const RenderData *rd, bool preview, const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index a20c918c517..035e56993f9 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -87,6 +87,7 @@ typedef struct FFMpegContext {
AVStream *video_stream;
AVStream *audio_stream;
AVFrame *current_frame; /* Image frame in output pixel format. */
+ int video_time;
/* Image frame in Blender's own pixel format, may need conversion to the output pixel format. */
AVFrame *img_convert_frame;
@@ -96,6 +97,7 @@ typedef struct FFMpegContext {
uint8_t *audio_deinterleave_buffer;
int audio_input_samples;
double audio_time;
+ double audio_time_total;
bool audio_deinterleave;
int audio_sample_size;
@@ -318,14 +320,15 @@ static const char **get_file_extensions(int format)
}
/* Write a frame to the output file */
-static int write_video_frame(FFMpegContext *context, int cfra, AVFrame *frame, ReportList *reports)
+static int write_video_frame(FFMpegContext *context, AVFrame *frame, ReportList *reports)
{
int ret, success = 1;
AVPacket *packet = av_packet_alloc();
AVCodecContext *c = context->video_codec;
- frame->pts = cfra;
+ frame->pts = context->video_time;
+ context->video_time++;
ret = avcodec_send_frame(c, frame);
if (ret < 0) {
@@ -804,6 +807,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
avcodec_parameters_from_context(st->codecpar, c);
+ context->video_time = 0.0f;
+
return st;
}
@@ -1397,9 +1402,10 @@ static void write_audio_frames(FFMpegContext *context, double to_pts)
AVCodecContext *c = context->audio_codec;
while (context->audio_stream) {
- if ((context->audio_time >= to_pts) || !write_audio_frame(context)) {
+ if ((context->audio_time_total >= to_pts) || !write_audio_frame(context)) {
break;
}
+ context->audio_time_total += (double)context->audio_input_samples / (double)c->sample_rate;
context->audio_time += (double)context->audio_input_samples / (double)c->sample_rate;
}
}
@@ -1423,22 +1429,23 @@ int BKE_ffmpeg_append(void *context_v,
if (context->video_stream) {
avframe = generate_video_frame(context, (unsigned char *)pixels);
- success = (avframe && write_video_frame(context, frame - start_frame, avframe, reports));
+ success = (avframe && write_video_frame(context, avframe, reports));
+# ifdef WITH_AUDASPACE
+ /* Add +1 frame because we want to encode audio up until the next video frame. */
+ write_audio_frames(
+ context, (frame - start_frame + 1) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
+# endif
if (context->ffmpeg_autosplit) {
if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
end_ffmpeg_impl(context, true);
context->ffmpeg_autosplit_count++;
+
success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
}
}
}
-# ifdef WITH_AUDASPACE
- /* Add +1 frame because we want to encode audio up until the next video frame. */
- write_audio_frames(
- context, (frame - start_frame + 1) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
-# endif
return success;
}
@@ -1881,6 +1888,7 @@ void *BKE_ffmpeg_context_create(void)
context->ffmpeg_autosplit_count = 0;
context->ffmpeg_preview = false;
context->stamp_data = NULL;
+ context->audio_time_total = 0.0;
return context;
}
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
index 3e13ba602a4..93014c1b859 100644
--- a/source/blender/blenkernel/nla_private.h
+++ b/source/blender/blenkernel/nla_private.h
@@ -165,18 +165,30 @@ typedef struct NlaKeyframingContext {
/* --------------- NLA Functions (not to be used as a proper API) ----------------------- */
-/* convert from strip time <-> global time */
+/**
+ * Convert non clipped mapping for strip-time <-> global time:
+ * `mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_*`
+ *
+ * Only secure for 'internal' (i.e. within AnimSys evaluation) operations,
+ * but should not be directly relied on for stuff which interacts with editors.
+ */
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode);
/* --------------- NLA Evaluation (very-private stuff) ----------------------- */
/* these functions are only defined here to avoid problems with the order
* in which they get defined. */
+/**
+ * Gets the strip active at the current time for a list of strips for evaluation purposes.
+ */
NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
ListBase *strips,
short index,
const struct AnimationEvalContext *anim_eval_context,
const bool flush_to_original);
+/**
+ * Evaluates the given evaluation strip.
+ */
void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalData *channels,
ListBase *modifiers,
@@ -184,6 +196,9 @@ void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalSnapshot *snapshot,
const struct AnimationEvalContext *anim_eval_context,
const bool flush_to_original);
+/**
+ * write the accumulated settings to.
+ */
void nladata_flush_channels(PointerRNA *ptr,
NlaEvalData *channels,
NlaEvalSnapshot *snapshot,
@@ -193,6 +208,14 @@ void nlasnapshot_enable_all_blend_domain(NlaEvalSnapshot *snapshot);
void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapshot);
+/**
+ * Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
+ * to the given \a upper_blendmode and \a upper_influence.
+ *
+ * For \a upper_snapshot, blending limited to values in the \a blend_domain.
+ * For Replace blend-mode, this allows the upper snapshot to have a location XYZ channel
+ * where only a subset of values are blended.
+ */
void nlasnapshot_blend(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *upper_snapshot,
@@ -200,6 +223,14 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
const float upper_influence,
NlaEvalSnapshot *r_blended_snapshot);
+/**
+ * Using \a blended_snapshot and \a lower_snapshot, we can solve for the \a r_upper_snapshot.
+ *
+ * Only channels that exist within \a blended_snapshot are inverted.
+ *
+ * For \a r_upper_snapshot, disables \a NlaEvalChannelSnapshot->remap_domain for failed inversions.
+ * Only values within the \a remap_domain are processed.
+ */
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
diff --git a/source/blender/blenkernel/tracking_private.h b/source/blender/blenkernel/tracking_private.h
index 8de6ec93a7c..0c1f73fa4b6 100644
--- a/source/blender/blenkernel/tracking_private.h
+++ b/source/blender/blenkernel/tracking_private.h
@@ -78,12 +78,21 @@ void tracking_get_search_origin_frame_pixel(int frame_width,
const struct MovieTrackingMarker *marker,
float frame_pixel[2]);
+/**
+ * Each marker has 5 coordinates associated with it that get warped with
+ * tracking: the four corners ("pattern_corners"), and the center ("pos").
+ * This function puts those 5 points into the appropriate frame for tracking
+ * (the "search" coordinate frame).
+ */
void tracking_get_marker_coords_for_tracking(int frame_width,
int frame_height,
const struct MovieTrackingMarker *marker,
double search_pixel_x[5],
double search_pixel_y[5]);
+/**
+ * Inverse of #tracking_get_marker_coords_for_tracking.
+ */
void tracking_set_marker_coords_from_tracking(int frame_width,
int frame_height,
struct MovieTrackingMarker *marker,
@@ -92,11 +101,23 @@ void tracking_set_marker_coords_from_tracking(int frame_width,
/*********************** General purpose utility functions *************************/
+/**
+ * Place a disabled marker before or after specified ref_marker.
+ *
+ * If before is truth, disabled marker is placed before reference
+ * one, and it's placed after it otherwise.
+ *
+ * If there's already a marker at the frame where disabled one is expected to be placed,
+ * nothing will happen if overwrite is false.
+ */
void tracking_marker_insert_disabled(struct MovieTrackingTrack *track,
const struct MovieTrackingMarker *ref_marker,
bool before,
bool overwrite);
+/**
+ * Fill in Libmv C-API camera intrinsics options from tracking structure.
+ */
void tracking_cameraIntrinscisOptionsFromTracking(
struct MovieTracking *tracking,
int calibration_width,
@@ -109,17 +130,26 @@ void tracking_trackingCameraFromIntrinscisOptions(
struct libmv_TrackRegionOptions;
+/**
+ * Fill in libmv tracker options structure with settings need to be used to perform track.
+ */
void tracking_configure_tracker(const MovieTrackingTrack *track,
float *mask,
bool is_backwards,
struct libmv_TrackRegionOptions *options);
+/**
+ * Get previous keyframed marker.
+ */
struct MovieTrackingMarker *tracking_get_keyframed_marker(struct MovieTrackingTrack *track,
int current_frame,
bool backwards);
/*********************** Masking *************************/
+/**
+ * Region is in pixel space, relative to marker's center.
+ */
float *tracking_track_get_mask_for_region(int frame_width,
int frame_height,
const float region_min[2],
@@ -145,11 +175,13 @@ typedef struct TrackingImageAccessor {
SpinLock cache_lock;
} TrackingImageAccessor;
-/* Clips are used to access images of an actual footage.
+/**
+ * Clips are used to access images of an actual footage.
* Tracks are used to access masks associated with the tracks.
*
- * NOTE: Both clips and tracks arrays are copied into the image accessor. It means that the caller
- * is allowed to pass temporary arrays which are only valid during initialization. */
+ * \note Both clips and tracks arrays are copied into the image accessor. It means that the caller
+ * is allowed to pass temporary arrays which are only valid during initialization.
+ */
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
MovieTrackingTrack **tracks,
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index 084f573e8c7..5b15bb979f5 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -28,7 +28,7 @@
/** \name Internal defines
* \{ */
-/** this returns the entire size of the array, including any buffering. */
+/** This returns the entire size of the array, including any buffering. */
#define _bli_array_totalsize_dynamic(arr) \
(((arr) == NULL) ? 0 : MEM_allocN_len(arr) / sizeof(*(arr)))
@@ -44,8 +44,12 @@
/**
* BLI_array.c
*
- * Doing the realloc in a macro isn't so simple,
+ * Doing the reallocation in a macro isn't so simple,
* so use a function the macros can use.
+ *
+ * This function is only to be called via macros.
+ *
+ * \note The caller must adjust \a arr_len
*/
void _bli_array_grow_func(void **arr_p,
const void *arr_static,
@@ -64,8 +68,9 @@ void _bli_array_grow_func(void **arr_p,
void *_##arr##_static = NULL
/**
- * this will use stack space, up to maxstatic array elements, before
- * switching to dynamic heap allocation */
+ * This will use stack space, up to `maxstatic` array elements,
+ * before switching to dynamic heap allocation.
+ */
#define BLI_array_staticdeclare(arr, maxstatic) \
int _##arr##_len = 0; \
char _##arr##_static[maxstatic * sizeof(*(arr))]
@@ -77,7 +82,8 @@ void _bli_array_grow_func(void **arr_p,
* Grow the array by a fixed number of items.
*
* Allow for a large 'num' value when the new size is more than double
- * to allocate the exact sized array. */
+ * to allocate the exact sized array.
+ */
#define BLI_array_reserve(arr, num) \
(void)((((void *)(arr) == NULL) && \
((void *)(_##arr##_static) != \
@@ -95,12 +101,16 @@ void _bli_array_grow_func(void **arr_p,
num, \
"BLI_array." #arr)))
-/** returns length of array */
+/**
+ * Returns length of array.
+ */
#define BLI_array_grow_items(arr, num) (BLI_array_reserve(arr, num), (_##arr##_len += num))
#define BLI_array_grow_one(arr) BLI_array_grow_items(arr, 1)
-/** appends an item to the array. */
+/**
+ * Appends an item to the array.
+ */
#define BLI_array_append(arr, item) \
((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item))
@@ -111,7 +121,9 @@ void _bli_array_grow_func(void **arr_p,
#define BLI_array_append_r(arr, item) \
((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item), (&arr[_##arr##_len - 1]))
-/** appends (grows) & returns a pointer to the uninitialized memory */
+/**
+ * Appends (grows) & returns a pointer to the uninitialized memory.
+ */
#define BLI_array_append_ret(arr) (BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)])
#define BLI_array_free(arr) \
@@ -127,7 +139,8 @@ void _bli_array_grow_func(void **arr_p,
/**
* Resets the logical size of an array to zero, but doesn't
- * free the memory. */
+ * free the memory.
+ */
#define BLI_array_clear(arr) \
{ \
_##arr##_len = 0; \
@@ -135,30 +148,32 @@ void _bli_array_grow_func(void **arr_p,
((void)0)
/**
- * Set the length of the array, doesn't actually increase the allocated array
- * size. don't use this unless you know what you're doing. */
+ * Set the length of the array, doesn't actually increase the allocated array size.
+ * Don't use this unless you know what you're doing.
+ */
#define BLI_array_len_set(arr, len) \
{ \
_##arr##_len = (len); \
} \
((void)0)
-/** only to prevent unused warnings */
+/**
+ * Only to prevent unused warnings.
+ */
#define BLI_array_fake_user(arr) ((void)_##arr##_len, (void)_##arr##_static)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Generic Array Utils
- * other useful defines
- * (unrelated to the main array macros)
*
+ * Other useful defines (unrelated to the main array macros).
* \{ */
/**
- * Not part of the 'API' but handy functions,
- * same purpose as #BLI_array_staticdeclare()
- * but use when the max size is known ahead of time */
+ * Not part of the 'API' but handy functions, same purpose as #BLI_array_staticdeclare()
+ * but use when the max size is known ahead of time.
+ */
#define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \
char _##arr##_static[maxstatic * sizeof(*(arr))]; \
const bool _##arr##_is_static = ((void *)_##arr##_static) != \
diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h
index 78d718117ba..0be361d4ab9 100644
--- a/source/blender/blenlib/BLI_array_store.h
+++ b/source/blender/blenlib/BLI_array_store.h
@@ -28,25 +28,88 @@ extern "C" {
typedef struct BArrayState BArrayState;
typedef struct BArrayStore BArrayStore;
+/**
+ * Create a new array store, which can store any number of arrays
+ * as long as their stride matches.
+ *
+ * \param stride: `sizeof()` each element,
+ *
+ * \note while a stride of `1` will always work,
+ * its less efficient since duplicate chunks of memory will be searched
+ * at positions unaligned with the array data.
+ *
+ * \param chunk_count: Number of elements to split each chunk into.
+ * - A small value increases the ability to de-duplicate chunks,
+ * but adds overhead by increasing the number of chunks to look up when searching for duplicates,
+ * as well as some overhead constructing the original array again, with more calls to `memcpy`.
+ * - Larger values reduce the *book keeping* overhead,
+ * but increase the chance a small,
+ * isolated change will cause a larger amount of data to be duplicated.
+ *
+ * \return A new array store, to be freed with #BLI_array_store_destroy.
+ */
BArrayStore *BLI_array_store_create(unsigned int stride, unsigned int chunk_count);
+/**
+ * Free the #BArrayStore, including all states and chunks.
+ */
void BLI_array_store_destroy(BArrayStore *bs);
+/**
+ * Clear all contents, allowing reuse of \a bs.
+ */
void BLI_array_store_clear(BArrayStore *bs);
-/* find the memory used by all states (expanded & real) */
+/**
+ * Find the memory used by all states (expanded & real).
+ *
+ * \return the total amount of memory that would be used by getting the arrays for all states.
+ */
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs);
+/**
+ * \return the amount of memory used by all #BChunk.data
+ * (duplicate chunks are only counted once).
+ */
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs);
+/**
+ *
+ * \param data: Data used to create
+ * \param state_reference: The state to use as a reference when adding the new state,
+ * typically this is the previous state,
+ * however it can be any previously created state from this \a bs.
+ *
+ * \return The new state,
+ * which is used by the caller as a handle to get back the contents of \a data.
+ * This may be removed using #BLI_array_store_state_remove,
+ * otherwise it will be removed with #BLI_array_store_destroy.
+ */
BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data,
const size_t data_len,
const BArrayState *state_reference);
+/**
+ * Remove a state and free any unused #BChunk data.
+ *
+ * The states can be freed in any order.
+ */
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state);
+/**
+ * \return the expanded size of the array,
+ * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
+ */
size_t BLI_array_store_state_size_get(BArrayState *state);
+/**
+ * Fill in existing allocated memory with the contents of \a state.
+ */
void BLI_array_store_state_data_get(BArrayState *state, void *data);
+/**
+ * Allocate an array for \a state and return it.
+ */
void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len);
-/* only for tests */
+/**
+ * \note Only for tests.
+ */
bool BLI_array_store_is_valid(BArrayStore *bs);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 52d41173a0e..eb14b030bf9 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -28,12 +28,29 @@
extern "C" {
#endif
+/**
+ * In-place array reverse.
+ *
+ * Access via #BLI_array_reverse
+ */
void _bli_array_reverse(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_reverse(arr, arr_len) _bli_array_reverse(arr, arr_len, sizeof(*(arr)))
+/**
+ * In-place array wrap.
+ * (rotate the array one step forward or backwards).
+ *
+ * Access via #BLI_array_wrap
+ */
void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir);
#define BLI_array_wrap(arr, arr_len, dir) _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir)
+/**
+ *In-place array permute.
+ * (re-arrange elements based on an array of indices).
+ *
+ * Access via #BLI_array_wrap
+ */
void _bli_array_permute(
void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp);
#define BLI_array_permute(arr, arr_len, order) \
@@ -41,13 +58,30 @@ void _bli_array_permute(
#define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp)
+/**
+ * In-place array de-duplication of an ordered array.
+ *
+ * \return The new length of the array.
+ *
+ * Access via #BLI_array_deduplicate_ordered
+ */
uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_deduplicate_ordered(arr, arr_len) \
_bli_array_deduplicate_ordered(arr, arr_len, sizeof(*(arr)))
+/**
+ * Find the first index of an item in an array.
+ *
+ * Access via #BLI_array_findindex
+ *
+ * \note Not efficient, use for error checks/asserts.
+ */
int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_findindex(arr, arr_len, p) _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
+/**
+ * A version of #BLI_array_findindex that searches from the end of the list.
+ */
int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_rfindindex(arr, arr_len, p) \
_bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
@@ -66,6 +100,22 @@ void _bli_array_binary_or(
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
+/**
+ * Utility function to iterate over contiguous items in an array.
+ *
+ * \param use_wrap: Detect contiguous ranges across the first/last points.
+ * In this case the second index of \a span_step may be lower than the first,
+ * which indicates the values are wrapped.
+ * \param use_delimit_bounds: When false,
+ * ranges that defined by the start/end indices are excluded.
+ * This option has no effect when \a use_wrap is enabled.
+ * \param test_fn: Function to test if the item should be included in the range.
+ * \param user_data: User data for \a test_fn.
+ * \param span_step: Indices to iterate over,
+ * initialize both values to the array length to initialize iteration.
+ * \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
+ * where calculating the length isn't a simple subtraction.
+ */
bool _bli_array_iter_span(const void *arr,
uint arr_len,
size_t arr_stride,
@@ -87,9 +137,19 @@ bool _bli_array_iter_span(const void *arr,
span_step, \
r_span_len)
+/**
+ * Simple utility to check memory is zeroed.
+ */
bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr)))
+/**
+ * Smart function to sample a rectangle spiraling outside.
+ * Nice for selection ID.
+ *
+ * \param arr_shape: dimensions [w, h].
+ * \param center: coordinates [x, y] indicating where to start traversing.
+ */
bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2],
const size_t elem_size,
diff --git a/source/blender/blenlib/BLI_astar.h b/source/blender/blenlib/BLI_astar.h
index fe5c4ddad69..a1d4e28dad9 100644
--- a/source/blender/blenlib/BLI_astar.h
+++ b/source/blender/blenlib/BLI_astar.h
@@ -76,18 +76,52 @@ typedef struct BLI_AStarGraph {
struct MemArena *mem; /* Memory arena. */
} BLI_AStarGraph;
+/**
+ * Initialize a node in A* graph.
+ *
+ * \param custom_data: an opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data);
+/**
+ * Add a link between two nodes of our A* graph.
+ *
+ * \param cost: The 'length' of the link
+ * (actual distance between two vertices or face centers e.g.).
+ * \param custom_data: An opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
const int node1_index,
const int node2_index,
const float cost,
void *custom_data);
+/**
+ * \return The index of the other node of given link.
+ */
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx);
+/**
+ * Initialize a solution data for given A* graph. Does not compute anything!
+ *
+ * \param custom_data: an opaque pointer attached to this link, available e.g
+ * . to cost callback function.
+ *
+ * \note BLI_AStarSolution stores nearly all data needed during solution compute.
+ */
void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution,
void *custom_data);
+/**
+ * Clear given solution's data, but does not release its memory.
+ * Avoids having to recreate/allocate a memarena in loops, e.g.
+ *
+ * \note This *has to be called* between each path solving.
+ */
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution);
+/**
+ * Release the memory allocated for this solution.
+ */
void BLI_astar_solution_free(BLI_AStarSolution *as_solution);
/**
@@ -108,8 +142,24 @@ typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph,
const int node_idx_next,
const int node_idx_dst);
+/**
+ * Initialize an A* graph. Total number of nodes must be known.
+ *
+ * Nodes might be e.g. vertices, faces, ... etc.
+ *
+ * \param custom_data: an opaque pointer attached to this link,
+ * available e.g. to cost callback function.
+ */
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data);
void BLI_astar_graph_free(BLI_AStarGraph *as_graph);
+/**
+ * Solve a path in given graph, using given 'cost' callback function.
+ *
+ * \param max_steps: maximum number of nodes the found path may have.
+ * Useful in performance-critical usages.
+ * If no path is found within given steps, returns false too.
+ * \return true if a path was found, false otherwise.
+ */
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph,
const int node_index_src,
const int node_index_dst,
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index c97be6eed3c..b5ef08e9e60 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -40,26 +40,38 @@ typedef unsigned int BLI_bitmap;
/* 0b11111 */
#define _BITMAP_MASK 31
-/* number of blocks needed to hold '_tot' bits */
+/**
+ * Number of blocks needed to hold '_tot' bits.
+ */
#define _BITMAP_NUM_BLOCKS(_tot) (((_tot) >> _BITMAP_POWER) + 1)
-/* size (in bytes) used to hold '_tot' bits */
+/**
+ * Size (in bytes) used to hold '_tot' bits.
+ */
#define BLI_BITMAP_SIZE(_tot) ((size_t)(_BITMAP_NUM_BLOCKS(_tot)) * sizeof(BLI_bitmap))
-/* allocate memory for a bitmap with '_tot' bits; free with MEM_freeN() */
+/**
+ * Allocate memory for a bitmap with '_tot' bits; free with MEM_freeN().
+ */
#define BLI_BITMAP_NEW(_tot, _alloc_string) \
((BLI_bitmap *)MEM_callocN(BLI_BITMAP_SIZE(_tot), _alloc_string))
-/* allocate a bitmap on the stack */
+/**
+ * Allocate a bitmap on the stack.
+ */
#define BLI_BITMAP_NEW_ALLOCA(_tot) \
((BLI_bitmap *)memset(alloca(BLI_BITMAP_SIZE(_tot)), 0, BLI_BITMAP_SIZE(_tot)))
-/* Allocate using given MemArena */
+/**
+ * Allocate using given MemArena.
+ */
#define BLI_BITMAP_NEW_MEMARENA(_mem, _tot) \
(CHECK_TYPE_INLINE(_mem, MemArena *), \
((BLI_bitmap *)BLI_memarena_calloc(_mem, BLI_BITMAP_SIZE(_tot))))
-/* get the value of a single bit at '_index' */
+/**
+ * Get the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_TEST(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] & (1u << ((_index)&_BITMAP_MASK))))
@@ -74,22 +86,30 @@ typedef unsigned int BLI_bitmap;
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
(BLI_BITMAP_TEST(_bitmap, _index) != 0))
-/* set the value of a single bit at '_index' */
+/**
+ * Set the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_ENABLE(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] |= (1u << ((_index)&_BITMAP_MASK))))
-/* clear the value of a single bit at '_index' */
+/**
+ * Clear the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_DISABLE(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] &= ~(1u << ((_index)&_BITMAP_MASK))))
-/* flip the value of a single bit at '_index' */
+/**
+ * Flip the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_FLIP(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] ^= (1u << ((_index)&_BITMAP_MASK))))
-/* set or clear the value of a single bit at '_index' */
+/**
+ * Set or clear the value of a single bit at '_index'.
+ */
#define BLI_BITMAP_SET(_bitmap, _index, _set) \
{ \
CHECK_TYPE(_bitmap, BLI_bitmap *); \
@@ -102,7 +122,9 @@ typedef unsigned int BLI_bitmap;
} \
(void)0
-/* resize bitmap to have space for '_tot' bits */
+/**
+ * Resize bitmap to have space for '_tot' bits.
+ */
#define BLI_BITMAP_RESIZE(_bitmap, _tot) \
{ \
CHECK_TYPE(_bitmap, BLI_bitmap *); \
@@ -110,10 +132,25 @@ typedef unsigned int BLI_bitmap;
} \
(void)0
+/**
+ * Set or clear all bits in the bitmap.
+ */
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits);
+/**
+ * Invert all bits in the bitmap.
+ */
void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits);
+/**
+ * Copy all bits from one bitmap to another.
+ */
void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
+/**
+ * Combine two bitmaps with boolean AND.
+ */
void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
+/**
+ * Combine two bitmaps with boolean OR.
+ */
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h
index 8331d8fac08..1b9ff2162e3 100644
--- a/source/blender/blenlib/BLI_bitmap_draw_2d.h
+++ b/source/blender/blenlib/BLI_bitmap_draw_2d.h
@@ -24,17 +24,37 @@
extern "C" {
#endif
+/**
+ * Plot a line from \a p1 to \a p2 (inclusive).
+ *
+ * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
+ */
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2],
const int p2[2],
bool (*callback)(int, int, void *),
void *user_data);
+/**
+ * \note Unclipped (clipped version can be added if needed).
+ */
void BLI_bitmap_draw_2d_tri_v2i(const int p1[2],
const int p2[2],
const int p3[2],
void (*callback)(int x, int x_end, int y, void *),
void *user_data);
+/**
+ * Draws a filled polygon with support for self intersections.
+ *
+ * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
+ * note that \a x_end will always be greater than \a x, so we can use:
+ *
+ * \code{.c}
+ * do {
+ * func(x, y);
+ * } while (++x != x_end);
+ * \endcode
+ */
void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
const int ymin,
const int xmax,
diff --git a/source/blender/blenlib/BLI_boxpack_2d.h b/source/blender/blenlib/BLI_boxpack_2d.h
index 7e347d0b0d7..e743424db59 100644
--- a/source/blender/blenlib/BLI_boxpack_2d.h
+++ b/source/blender/blenlib/BLI_boxpack_2d.h
@@ -44,6 +44,20 @@ typedef struct BoxPack {
int index;
} BoxPack;
+/**
+ * Main box-packing function accessed from other functions
+ * This sets boxes x,y to positive values, sorting from 0,0 outwards.
+ * There is no limit to the space boxes may take, only that they will be packed
+ * tightly into the lower left hand corner (0,0)
+ *
+ * \param boxarray: a pre-allocated array of boxes.
+ * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
+ * 'box->index' is not used at all, the only reason its there
+ * is that the box array is sorted by area and programs need to be able
+ * to have some way of writing the boxes back to the original data.
+ * \param len: the number of boxes in the array.
+ * \param r_tot_x, r_tot_y: set so you can normalize the data.
+ */
void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x, float *r_tot_y);
typedef struct FixedSizeBoxPack {
@@ -52,6 +66,21 @@ typedef struct FixedSizeBoxPack {
int w, h;
} FixedSizeBoxPack;
+/**
+ * Packs boxes into a fixed area.
+ *
+ * Boxes and packed are linked lists containing structs that can be cast to
+ * #FixedSizeBoxPack (i.e. contains a #FixedSizeBoxPack as its first element).
+ * Boxes that were packed successfully are placed into *packed and removed from *boxes.
+ *
+ * The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
+ * Better ones could be used, but for the current use case (packing Image tiles into GPU
+ * textures) this is fine.
+ *
+ * Note that packing efficiency depends on the order of the input boxes. Generally speaking,
+ * larger boxes should come first, though how exactly size is best defined (e.g. area, perimeter)
+ * depends on the particular application.
+ */
void BLI_box_pack_2d_fixedarea(struct ListBase *boxes,
int width,
int height,
diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h
index 9d66fe9a14e..7f577443cf7 100644
--- a/source/blender/blenlib/BLI_buffer.h
+++ b/source/blender/blenlib/BLI_buffer.h
@@ -71,13 +71,25 @@ enum {
} \
(void)0
-/* Never decreases the amount of memory allocated */
+/**
+ * \note Never decreases the amount of memory allocated.
+ */
void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count);
-/* Ensure size, throwing away old data, respecting BLI_BUFFER_USE_CALLOC */
+/**
+ * Ensure size, throwing away old data, respecting #BLI_BUFFER_USE_CALLOC.
+ *
+ * Similar to #BLI_buffer_resize, but use when the existing data can be:
+ * - Ignored (malloc'd).
+ * - Cleared (when #BLI_BUFFER_USE_CALLOC is set).
+ */
void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count);
-/* Append an array of elements. */
+/**
+ * Append an array of elements.
+ *
+ * Callers use #BLI_buffer_append_array.
+ */
void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count);
#define BLI_buffer_append_array(buffer_, type_, data_, count_) \
{ \
@@ -87,7 +99,11 @@ void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count);
} \
(void)0
-/* Does not free the buffer structure itself */
+/**
+ * Does not free the buffer structure itself.
+ *
+ * Callers use #BLI_buffer_free.
+ */
void _bli_buffer_free(BLI_Buffer *buffer);
#define BLI_buffer_free(name_) \
{ \
@@ -96,7 +112,9 @@ void _bli_buffer_free(BLI_Buffer *buffer);
} \
(void)0
-/* A buffer embedded in a struct. Using memcpy is allowed until first resize. */
+/**
+ * A buffer embedded in a struct. Using #memcpy is allowed until first resize.
+ */
#define BLI_buffer_field_init(name_, type_) \
{ \
memset(name_, 0, sizeof(*name_)); \
diff --git a/source/blender/blenlib/BLI_convexhull_2d.h b/source/blender/blenlib/BLI_convexhull_2d.h
index e930117822f..44758fb3880 100644
--- a/source/blender/blenlib/BLI_convexhull_2d.h
+++ b/source/blender/blenlib/BLI_convexhull_2d.h
@@ -24,10 +24,43 @@
extern "C" {
#endif
+/**
+ * A.M. Andrew's monotone chain 2D convex hull algorithm.
+ *
+ * \param points: An array of 2D points presorted by increasing x and y-coords.
+ * \param n: The number of points in points.
+ * \param r_points: An array of the convex hull vertex indices (max is n).
+ * \returns the number of points in r_points.
+ */
int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[]);
+/**
+ * A.M. Andrew's monotone chain 2D convex hull algorithm.
+ *
+ * \param points: An array of 2D points.
+ * \param n: The number of points in points.
+ * \param r_points: An array of the convex hull vertex indices (max is n).
+ * _must_ be allocated as `n * 2` because of how its used internally,
+ * even though the final result will be no more than \a n in size.
+ * \returns the number of points in r_points.
+ */
int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]);
+/**
+ * \return The best angle for fitting the convex hull to an axis aligned bounding box.
+ *
+ * Intended to be used with #BLI_convexhull_2d
+ *
+ * \param points_hull: Ordered hull points
+ * (result of #BLI_convexhull_2d mapped to a contiguous array).
+ *
+ * \note we could return the index of the best edge too if its needed.
+ */
float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n);
+/**
+ * Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation.
+ *
+ * \param points: arbitrary 2d points.
+ */
float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h
index 03aab8d2895..72f18244d5b 100644
--- a/source/blender/blenlib/BLI_dlrbTree.h
+++ b/source/blender/blenlib/BLI_dlrbTree.h
@@ -21,23 +21,24 @@
/** \file
* \ingroup bli
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Double-Linked Red-Black Tree Implementation:
+ *
+ * Double-Linked Red-Black Tree Implementation:
*
* This is simply a Red-Black Tree implementation whose nodes can later
* be arranged + retrieved as elements in a Double-Linked list (i.e. ListBase).
* The Red-Black Tree implementation is based on the methods defined by Wikipedia.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ********************************************** */
/* Data Types and Type Defines */
-/* Base Structs --------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Base Structs
+ * \{ */
/* Basic Layout for a Node */
typedef struct DLRBT_Node {
@@ -69,101 +70,150 @@ typedef struct DLRBT_Tree {
void *root; /* this should be based on DLRBT_Node-s */
} DLRBT_Tree;
-/* Callback Types --------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callback Types
+ * \{ */
-/* Return -1, 0, 1 for whether the given data is less than,
+/**
+ * Return -1, 0, 1 for whether the given data is less than,
* equal to, or greater than the given node.
- * - node: <DLRBT_Node> the node to compare to.
- * - data: pointer to the relevant data or values stored in the bit-pattern.
- * dependent on the function.
+ * \param node: <DLRBT_Node> the node to compare to.
+ * \param data: pointer to the relevant data or values stored in the bit-pattern.
+ * Dependent on the function.
*/
typedef short (*DLRBT_Comparator_FP)(void *node, void *data);
-/* Return a new node instance wrapping the given data
- * - data: Pointer to the relevant data to create a subclass of node from
+/**
+ * Return a new node instance wrapping the given data
+ * - data: Pointer to the relevant data to create a subclass of node from.
*/
typedef DLRBT_Node *(*DLRBT_NAlloc_FP)(void *data);
-/* Update an existing node instance accordingly to be in sync with the given data.
- * - node: <DLRBT_Node> the node to update.
- * - data: Pointer to the relevant data or values stored in the bit-pattern.
- * dependent on the function.
+/**
+ * Update an existing node instance accordingly to be in sync with the given data.
+ * \param node: <DLRBT_Node> the node to update.
+ * \param data: Pointer to the relevant data or values stored in the bit-pattern.
+ * Dependent on the function.
*/
typedef void (*DLRBT_NUpdate_FP)(void *node, void *data);
/* ********************************************** */
/* Public API */
-/* ADT Management ------------------------------- */
+/** \} */
-/* Create a new tree, and initialize as necessary */
+/* -------------------------------------------------------------------- */
+/** \name ADT Management
+ * \{ */
+
+/**
+ * Create a new tree, and initialize as necessary.
+ */
DLRBT_Tree *BLI_dlrbTree_new(void);
-/* Initializes some given trees */
+/**
+ * Initializes some given trees.
+ * Just zero out the pointers used.
+ */
void BLI_dlrbTree_init(DLRBT_Tree *tree);
-/* Free some tree */
+/**
+ * Free the given tree's data but not the tree itself.
+ */
void BLI_dlrbTree_free(DLRBT_Tree *tree);
-/* Make sure the tree's Double-Linked list representation is valid */
+/**
+ * Make sure the tree's Double-Linked list representation is valid.
+ */
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree);
-/* Searching ------------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tree Searching Utilities
+ * \{ */
-/* Find the node which matches or is the closest to the requested node */
+/**
+ * Find the node which matches or is the closest to the requested node.
+ */
DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which exactly matches the required data */
+/**
+ * Find the node which exactly matches the required data.
+ */
DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which occurs immediately before the best matching node */
+/**
+ * Find the node which occurs immediately before the best matching node.
+ */
DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Find the node which occurs immediately after the best matching node */
+/**
+ * Find the node which occurs immediately after the best matching node.
+ */
DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data);
-/* Check whether there is a node matching the requested node */
+/**
+ * Check whether there is a node matching the requested node.
+ */
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data);
-/* Node Operations (Managed) --------------------- */
-/* These methods automate the process of adding/removing nodes from the BST,
- * using the supplied data and callbacks
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Operations (Managed)
+ * \{ */
+
+/**
+ * These methods automate the process of adding/removing nodes from the BST,
+ * using the supplied data and callbacks.
*/
-/* Add the given data to the tree, and return the node added */
-/* NOTE: for duplicates, the update_cb is called (if available),
- * and the existing node is returned. */
+/**
+ * Add the given data to the tree, and return the node added.
+ * \note for duplicates, the update_cb is called (if available),
+ * and the existing node is returned.
+ */
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb,
DLRBT_NUpdate_FP update_cb,
void *data);
-/* Remove the given element from the tree and balance again */
-/* FIXME: this is not implemented yet... */
+/* FIXME: this is not implemented yet. */
+/**
+ * Remove the given element from the tree and balance again.
+ */
// void BLI_dlrbTree_remove(DLRBT_Tree *tree, DLRBT_Node *node);
-/* Node Operations (Manual) --------------------- */
-/* These methods require custom code for creating BST nodes and adding them to the
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Operations (Manual)
+ *
+ * These methods require custom code for creating BST nodes and adding them to the
* tree in special ways, such that the node can then be balanced.
*
- * It is recommended that these methods are only used where the other method is too cumbersome...
- */
+ * It is recommended that these methods are only used where the other method is too cumbersome.
+ * \{ */
-/* Balance the tree after the given node has been added to it
+/**
+ * Balance the tree after the given node has been added to it
* (using custom code, in the Binary Tree way).
*/
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node);
-/* ********************************************** */
+/** \} */
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h
index 4df773c7cc6..90d93f29bcb 100644
--- a/source/blender/blenlib/BLI_dynstr.h
+++ b/source/blender/blenlib/BLI_dynstr.h
@@ -39,25 +39,85 @@ extern "C" {
struct DynStr;
-/** The abstract DynStr type */
+/** The abstract DynStr type. */
typedef struct DynStr DynStr;
+/**
+ * Create a new #DynStr.
+ *
+ * \return Pointer to a new #DynStr.
+ */
DynStr *BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Create a new #DynStr.
+ *
+ * \return Pointer to a new #DynStr.
+ */
DynStr *BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Append a c-string to a #DynStr.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param cstr: The c-string to append.
+ */
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL();
+/**
+ * Append a length clamped c-string to a #DynStr.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param cstr: The c-string to append.
+ * \param len: The maximum length of the c-string to copy.
+ */
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL();
+/**
+ * Append a c-string to a #DynStr, but with formatting like `printf`.
+ *
+ * \param ds: The #DynStr to append to.
+ * \param format: The `printf` format string to use.
+ */
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
ATTR_PRINTF_FORMAT(2, 3) ATTR_NONNULL(1, 2);
void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args)
ATTR_PRINTF_FORMAT(2, 0) ATTR_NONNULL(1, 2);
+/**
+ * Find the length of a #DynStr.
+ *
+ * \param ds: The #DynStr of interest.
+ * \return The length of \a ds.
+ */
int BLI_dynstr_get_len(const DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get a #DynStr's contents as a c-string.
+ * \return The c-string which must be freed using #MEM_freeN.
+ *
+ * \param ds: The #DynStr of interest.
+ * \return The contents of \a ds as a c-string.
+ */
char *BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get a #DynStr's contents as a c-string.
+ * The \a rets argument must be allocated to be at
+ * least the size of `BLI_dynstr_get_len(ds) + 1`.
+ *
+ * \param ds: The DynStr of interest.
+ * \param rets: The string to fill.
+ */
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets) ATTR_NONNULL();
+/**
+ * Clear the #DynStr
+ *
+ * \param ds: The DynStr to clear.
+ */
void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL();
+/**
+ * Free the #DynStr
+ *
+ * \param ds: The DynStr to free.
+ */
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
index 41f0d41d1e0..b0f71655c19 100644
--- a/source/blender/blenlib/BLI_edgehash.h
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -48,42 +48,120 @@ typedef struct EdgeHashIterator {
typedef void (*EdgeHashFreeFP)(void *key);
enum {
- EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0), /* only checked for in debug mode */
+ /**
+ * Only checked for in debug mode.
+ */
+ EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0),
};
EdgeHash *BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve);
EdgeHash *BLI_edgehash_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value);
void BLI_edgehash_print(EdgeHash *eh);
+/**
+ * Insert edge (\a v0, \a v1) into hash with given value, does
+ * not check for duplicates.
+ */
void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
+/**
+ * Assign a new value to a key that may already be in edgehash.
+ */
bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
+/**
+ * Return value for given edge (\a v0, \a v1), or NULL if
+ * if key does not exist in hash. (If need exists
+ * to differentiate between key-value being NULL and
+ * lack of key then see #BLI_edgehash_lookup_p().
+ */
void *BLI_edgehash_lookup(const EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_edgehash_lookup which accepts a fallback argument.
+ */
void *BLI_edgehash_lookup_default(const EdgeHash *eh,
unsigned int v0,
unsigned int v1,
void *default_value) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return pointer to value for given edge (\a v0, \a v1),
+ * or NULL if key does not exist in hash.
+ */
void **BLI_edgehash_lookup_p(EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Ensure \a (v0, v1) is exists in \a eh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a eh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \return true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
+ *
+ * \param v0, v1: The key to remove.
+ * \param free_value: Optional callback to free the value.
+ * \return true if \a key was removed from \a eh.
+ */
bool BLI_edgehash_remove(EdgeHash *eh,
unsigned int v0,
unsigned int v1,
EdgeHashFreeFP free_value);
+/**
+ * Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
+ *
+ * \param v0, v1: The key to remove.
+ * \return the value of \a key int \a eh or NULL.
+ */
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return boolean true/false if edge (v0,v1) in hash.
+ */
bool BLI_edgehash_haskey(const EdgeHash *eh,
unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return number of keys in hash.
+ */
int BLI_edgehash_len(const EdgeHash *eh) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove all edges from hash.
+ */
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint reserve);
+/**
+ * Wraps #BLI_edgehash_clear_ex with zero entries reserved.
+ */
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value);
+/**
+ * Create a new #EdgeHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * #BLI_edgehash_len(eh) times before becoming done.
+ */
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Initialize an already allocated #EdgeHashIterator. The hash table must not
+ * be mutated while the iterator is in use, and the iterator will
+ * step exactly BLI_edgehash_len(eh) times before becoming done.
+ *
+ * \param ehi: The #EdgeHashIterator to initialize.
+ * \param eh: The #EdgeHash to iterate over.
+ */
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh);
+/**
+ * Free an #EdgeHashIterator.
+ */
void BLI_edgehashIterator_free(EdgeHashIterator *ehi);
BLI_INLINE void BLI_edgehashIterator_step(EdgeHashIterator *ehi)
@@ -133,7 +211,17 @@ EdgeSet *BLI_edgeset_new_ex(const char *info, const unsigned int nentries_reserv
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
EdgeSet *BLI_edgeset_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
int BLI_edgeset_len(const EdgeSet *es) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of BLI_edgeset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note #EdgeHash has no equivalent to this because typically the value would be different.
+ */
bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1);
+/**
+ * Adds the key to the set (no checks for unique keys!).
+ * Matching #BLI_edgehash_insert
+ */
void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1);
bool BLI_edgeset_haskey(const EdgeSet *es,
unsigned int v0,
@@ -141,6 +229,7 @@ bool BLI_edgeset_haskey(const EdgeSet *es,
void BLI_edgeset_free(EdgeSet *es);
/* rely on inline api for now */
+
EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *es);
void BLI_edgesetIterator_free(EdgeSetIterator *esi);
diff --git a/source/blender/blenlib/BLI_expr_pylike_eval.h b/source/blender/blenlib/BLI_expr_pylike_eval.h
index c074b5d8130..dccb1863b4b 100644
--- a/source/blender/blenlib/BLI_expr_pylike_eval.h
+++ b/source/blender/blenlib/BLI_expr_pylike_eval.h
@@ -41,13 +41,35 @@ typedef enum eExprPyLike_EvalStatus {
EXPR_PYLIKE_FATAL_ERROR,
} eExprPyLike_EvalStatus;
+/**
+ * Free the parsed data; NULL argument is ok.
+ */
void BLI_expr_pylike_free(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsing result is valid for evaluation.
+ */
bool BLI_expr_pylike_is_valid(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsed expression always evaluates to the same value.
+ */
bool BLI_expr_pylike_is_constant(struct ExprPyLike_Parsed *expr);
+/**
+ * Check if the parsed expression uses the parameter with the given index.
+ */
bool BLI_expr_pylike_is_using_param(struct ExprPyLike_Parsed *expr, int index);
+/**
+ * Compile the expression and return the result.
+ *
+ * Parse the expression for evaluation later.
+ * Returns non-NULL even on failure; use is_valid to check.
+ */
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names,
int param_names_len);
+/**
+ * Evaluate the expression with the given parameters.
+ * The order and number of parameters must match the names given to parse.
+ */
eExprPyLike_EvalStatus BLI_expr_pylike_eval(struct ExprPyLike_Parsed *expr,
const double *param_values,
int param_values_len,
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 906a56ce909..2ef9b8f6c36 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -45,19 +45,40 @@ extern "C" {
# define PATH_MAX 4096
#endif
-/* Common */
+/* -------------------------------------------------------------------- */
+/** \name Common
+ * \{ */
+/**
+ * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails
+ * (most likely doesn't exist or no access).
+ */
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_copy(const char *file, const char *to) ATTR_NONNULL();
+/**
+ * \return zero on success (matching 'rename' behavior).
+ */
int BLI_rename(const char *from, const char *to) ATTR_NONNULL();
+/**
+ * Deletes the specified file or directory (depending on dir), optionally
+ * doing recursive delete of directory contents.
+ *
+ * \return zero on success (matching 'remove' behavior).
+ */
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL();
+/**
+ * Soft deletes the specified file or directory (depending on dir) by moving the files to the
+ * recycling bin, optionally doing recursive delete of directory contents.
+ *
+ * \return zero on success (matching 'remove' behavior).
+ */
int BLI_delete_soft(const char *file, const char **error_message) ATTR_NONNULL();
#if 0 /* Unused */
int BLI_move(const char *path, const char *to) ATTR_NONNULL();
int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL();
#endif
-/* keep in sync with the definition of struct direntry in BLI_fileops_types.h */
+/* Keep in sync with the definition of struct `direntry` in `BLI_fileops_types.h`. */
#ifdef WIN32
# if defined(_MSC_VER)
typedef struct _stat64 BLI_stat_t;
@@ -101,40 +122,102 @@ typedef enum eFileAttributes {
(FILE_ATTR_ALIAS | FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYMLINK | FILE_ATTR_JUNCTION_POINT | \
FILE_ATTR_MOUNT_POINT | FILE_ATTR_HARDLINK)
-/* Directories */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Directories
+ * \{ */
struct direntry;
+/**
+ * Does the specified path point to a directory?
+ * \note Would be better in `fileops.c` except that it needs `stat.h` so add here.
+ */
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Does the specified path point to a non-directory?
+ */
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return true on success (i.e. given path now exists on FS), false otherwise.
+ */
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL();
+/**
+ * Returns the number of free bytes on the volume containing the specified pathname.
+ *
+ * \note Not actually used anywhere.
+ */
double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Copies the current working directory into *dir (max size maxncpy), and
+ * returns a pointer to same.
+ *
+ * \note can return NULL when the size is not big enough
+ */
char *BLI_current_working_dir(char *dir, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
eFileAttributes BLI_file_attributes(const char *path);
-/* Filelist */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name File-List
+ * \{ */
+/**
+ * Scans the contents of the directory named *dirname, and allocates and fills in an
+ * array of entries describing them in *filelist.
+ *
+ * \return The length of filelist array.
+ */
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist);
+/**
+ * Deep-duplicate of a single direntry.
+ */
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src);
+/**
+ * Deep-duplicate of a #direntry array including the array itself.
+ */
void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist,
const unsigned int nrentries);
+/**
+ * Frees storage for a single direntry, not the direntry itself.
+ */
void BLI_filelist_entry_free(struct direntry *entry);
+/**
+ * Frees storage for an array of #direntry, including the array itself.
+ */
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries);
+/**
+ * Convert given entry's size into human-readable strings.
+ */
void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz,
const bool compact,
char r_size[FILELIST_DIRENTRY_SIZE_LEN]);
+/**
+ * Convert given entry's modes into human-readable strings.
+ */
void BLI_filelist_entry_mode_to_string(const struct stat *st,
const bool compact,
char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
char r_mode2[FILELIST_DIRENTRY_MODE_LEN],
char r_mode3[FILELIST_DIRENTRY_MODE_LEN]);
+/**
+ * Convert given entry's owner into human-readable strings.
+ */
void BLI_filelist_entry_owner_to_string(const struct stat *st,
const bool compact,
char r_owner[FILELIST_DIRENTRY_OWNER_LEN]);
+/**
+ * Convert given entry's time into human-readable strings.
+ *
+ * \param r_is_today: optional, returns true if the date matches today's.
+ * \param r_is_yesterday: optional, returns true if the date matches yesterday's.
+ */
void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts,
const bool compact,
@@ -143,14 +226,28 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
bool *r_is_today,
bool *r_is_yesterday);
-/* Files */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Files
+ * \{ */
FILE *BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BLI_gzopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_open(const char *filename, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the file with the specified name can be written.
+ * This implementation uses access(2), which makes the check according
+ * to the real UID and GID of the process, not its effective UID and GID.
+ * This shouldn't matter for Blender, which is not going to run privileged anyway.
+ */
bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Creates the file with nothing in it, or updates its last-modified date if it already exists.
+ * Returns true if successful (like the unix touch command).
+ */
bool BLI_file_touch(const char *file) ATTR_NONNULL();
bool BLI_file_alias_target(const char *filepath, char *r_targetpath) ATTR_WARN_UNUSED_RESULT;
@@ -165,23 +262,75 @@ size_t BLI_file_unzstd_to_mem_at_pos(void *buf, size_t len, FILE *file, size_t f
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_file_magic_is_zstd(const char header[4]);
+/**
+ * Returns the file size of an opened file descriptor.
+ */
size_t BLI_file_descriptor_size(int file) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns the size of a file.
+ */
size_t BLI_file_size(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* compare if one was last modified before the other */
+/**
+ * Compare if one was last modified before the other.
+ *
+ * \return true when is `file1` older than `file2`.
+ */
bool BLI_file_older(const char *file1, const char *file2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* read ascii file as lines, empty list if reading fails */
+/**
+ * Reads the contents of a text file.
+ *
+ * \return the lines in a linked list (an empty list when file reading fails).
+ */
struct LinkNode *BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
+/**
+ * Return the text file data with:
+
+ * - Newlines replaced with '\0'.
+ * - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'.
+ *
+ * This is an alternative to using #BLI_file_read_as_lines,
+ * allowing us to loop over lines without converting it into a linked list
+ * with individual allocations.
+ *
+ * \param trim_trailing_space: Replace trailing spaces & tabs with nil.
+ * This arguments prevents the caller from counting blank lines (if that's important).
+ * \param pad_bytes: When this is non-zero, the first byte is set to nil,
+ * to simplify parsing the file.
+ * It's recommended to pass in 1, so all text is nil terminated.
+ *
+ * Example looping over lines:
+ *
+ * \code{.c}
+ * size_t data_len;
+ * char *data = BLI_file_read_text_as_mem_with_newline_as_nil(filepath, true, 1, &data_len);
+ * char *data_end = data + data_len;
+ * for (char *line = data; line != data_end; line = strlen(line) + 1) {
+ * printf("line='%s'\n", line);
+ * }
+ * \endcode
+ */
void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
bool trim_trailing_space,
size_t pad_bytes,
size_t *r_size);
void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
+/**
+ * Frees memory from a previous call to #BLI_file_read_as_lines.
+ */
void BLI_file_free_lines(struct LinkNode *lines);
-/* this weirdo pops up in two places ... */
+#ifdef __APPLE__
+/**
+ * Expand the leading `~` in the given path to `/Users/$USER`.
+ * This doesn't preserve the trailing path separator.
+ * Giving a path without leading `~` is not an error.
+ */
+const char *BLI_expand_tilde(const char *path_with_tilde);
+#endif
+/* This weirdo pops up in two places. */
#if !defined(WIN32)
# ifndef O_BINARY
# define O_BINARY 0
@@ -190,6 +339,8 @@ void BLI_file_free_lines(struct LinkNode *lines);
void BLI_get_short_name(char short_name[256], const char *filename);
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index a2c5c6349a5..0194f9aad40 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -43,6 +43,10 @@ extern "C" {
# endif
#endif
+/* -------------------------------------------------------------------- */
+/** \name GHash Types
+ * \{ */
+
typedef unsigned int (*GHashHashFP)(const void *key);
/** returns false when equal */
typedef bool (*GHashCmpFP)(const void *a, const void *b);
@@ -74,53 +78,191 @@ enum {
#endif
};
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name GHash API
*
* Defined in `BLI_ghash.c`
* \{ */
+/**
+ * Creates a new, empty GHash.
+ *
+ * \param hashfp: Hash callback.
+ * \param cmpfp: Comparison callback.
+ * \param info: Identifier string for the GHash.
+ * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
+ * Use this to avoid resizing buckets if the size is known or can be closely approximated.
+ * \return An empty GHash.
+ */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info,
const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Wraps #BLI_ghash_new_ex with zero entries reserved.
+ */
GHash *BLI_ghash_new(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Copy given GHash. Keys and values are also copied if relevant callback is provided,
+ * else pointers remain the same.
+ */
GHash *BLI_ghash_copy(const GHash *gh,
GHashKeyCopyFP keycopyfp,
GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Frees the GHash and its members.
+ *
+ * \param gh: The GHash to free.
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ */
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Reserve given amount of entries (resize \a gh accordingly if needed).
+ */
void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
+/**
+ * Insert a key/value pair into the \a gh.
+ *
+ * \note Duplicates are not checked,
+ * the caller is expected to ensure elements are unique unless
+ * GHASH_FLAG_ALLOW_DUPES flag is set.
+ */
void BLI_ghash_insert(GHash *gh, void *key, void *val);
+/**
+ * Inserts a new value to a key that may already be in ghash.
+ *
+ * Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Replaces the key of an item in the \a gh.
+ *
+ * Use when a key is re-allocated or its memory location is changed.
+ *
+ * \returns The previous key or NULL if not found, the caller may free if it's needed.
+ */
void *BLI_ghash_replace_key(GHash *gh, void *key);
+/**
+ * Lookup the value of \a key in \a gh.
+ *
+ * \param key: The key to lookup.
+ * \returns the value for \a key or NULL.
+ *
+ * \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
+ * from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
+ */
void *BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_ghash_lookup which accepts a fallback argument.
+ */
void *BLI_ghash_lookup_default(const GHash *gh,
const void *key,
void *val_default) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Lookup a pointer to the value of \a key in \a gh.
+ *
+ * \param key: The key to lookup.
+ * \returns the pointer to value for \a key or NULL.
+ *
+ * \note This has 2 main benefits over #BLI_ghash_lookup.
+ * - A NULL return always means that \a key isn't in \a gh.
+ * - The value can be modified in-place without further function calls (faster).
+ */
void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Ensure \a key is exists in \a gh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a gh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \returns true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
+ * Typically used when the key is to be duplicated.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove \a key from \a gh, or return false if the key wasn't found.
+ *
+ * \param key: The key to remove.
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ * \return true if \a key was removed from \a gh.
+ */
bool BLI_ghash_remove(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp);
+/**
+ * Wraps #BLI_ghash_clear_ex with zero entries reserved.
+ */
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Reset \a gh clearing all entries.
+ *
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
+ */
void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp,
const unsigned int nentries_reserve);
+/**
+ * Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
+ *
+ * \param key: The key to remove.
+ * \param keyfreefp: Optional callback to free the key.
+ * \return the value of \a key int \a gh or NULL.
+ */
void *BLI_ghash_popkey(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \return true if the \a key is in \a gh.
+ */
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove a random entry from \a gh, returning true
+ * if a key/value pair could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param r_val: The removed value.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if ghash was already empty.
+ */
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return size of the GHash.
+ */
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Sets a GHash flag.
+ */
void BLI_ghash_flag_set(GHash *gh, unsigned int flag);
+/**
+ * Clear a GHash flag.
+ */
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \} */
@@ -129,10 +271,36 @@ void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \name GHash Iterator
* \{ */
+/**
+ * Create a new GHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * #BLI_ghash_len(gh) times before becoming done.
+ *
+ * \param gh: The GHash to iterate over.
+ * \return Pointer to a new iterator.
+ */
GHashIterator *BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Init an already allocated GHashIterator. The hash table must not
+ * be mutated while the iterator is in use, and the iterator will
+ * step exactly #BLI_ghash_len(gh) times before becoming done.
+ *
+ * \param ghi: The GHashIterator to initialize.
+ * \param gh: The GHash to iterate over.
+ */
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh);
+/**
+ * Free a GHashIterator.
+ *
+ * \param ghi: The iterator to free.
+ */
void BLI_ghashIterator_free(GHashIterator *ghi);
+/**
+ * Steps the iterator to the next index.
+ *
+ * \param ghi: The iterator.
+ */
void BLI_ghashIterator_step(GHashIterator *ghi);
BLI_INLINE void *BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT;
@@ -178,12 +346,11 @@ BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name GSet API
+/** \name GSet Types
* A 'set' implementation (unordered collection of unique elements).
*
* Internally this is a 'GHash' without any keys,
* which is why this API's are in the same header & source file.
- *
* \{ */
typedef struct GSet GSet;
@@ -195,6 +362,13 @@ typedef GHashKeyCopyFP GSetKeyCopyFP;
typedef GHashIterState GSetIterState;
+/** \} */
+
+/** \name GSet Public API
+ *
+ * Use ghash API to give 'set' functionality
+ * \{ */
+
GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info,
@@ -202,17 +376,55 @@ GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSet *BLI_gset_new(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
+ */
GSet *BLI_gset_copy(const GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT;
void BLI_gset_flag_set(GSet *gs, unsigned int flag);
void BLI_gset_flag_clear(GSet *gs, unsigned int flag);
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp);
+/**
+ * Adds the key to the set (no checks for unique keys!).
+ * Matching #BLI_ghash_insert
+ */
void BLI_gset_insert(GSet *gs, void *key);
+/**
+ * A version of BLI_gset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note GHash has no equivalent to this because typically the value would be different.
+ */
bool BLI_gset_add(GSet *gs, void *key);
+/**
+ * Set counterpart to #BLI_ghash_ensure_p_ex.
+ * similar to BLI_gset_add, except it returns the key pointer.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key);
+/**
+ * Adds the key to the set (duplicates are managed).
+ * Matching #BLI_ghash_reinsert
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
+/**
+ * Replaces the key to the set if it's found.
+ * Matching #BLI_ghash_replace_key
+ *
+ * \returns The old key or NULL if not found.
+ */
void *BLI_gset_replace_key(GSet *gs, void *key);
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if gset was already empty.
+ */
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
@@ -220,7 +432,14 @@ void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, const unsigned int nen
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
/* When set's are used for key & value. */
+/**
+ * Returns the pointer to the key if it's found.
+ */
void *BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns the pointer to the key if it's found, removing it from the GSet.
+ * \note Caller must handle freeing.
+ */
void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/** \} */
@@ -282,9 +501,19 @@ BLI_INLINE bool BLI_gsetIterator_done(const GSetIterator *gsi)
/* For testing, debugging only */
#ifdef GHASH_INTERNAL_API
+/**
+ * \return number of buckets in the GHash.
+ */
int BLI_ghash_buckets_len(const GHash *gh);
int BLI_gset_buckets_len(const GSet *gs);
+/**
+ * Measure how well the hash function performs (1.0 is approx as good as random distribution),
+ * and return a few other stats like load,
+ * variance of the distribution of the entries in the buckets, etc.
+ *
+ * Smaller is better!
+ */
double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load,
double *r_variance,
@@ -300,6 +529,7 @@ double BLI_gset_calc_quality_ex(GSet *gs,
double BLI_ghash_calc_quality(GHash *gh);
double BLI_gset_calc_quality(GSet *gs);
#endif /* GHASH_INTERNAL_API */
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -346,6 +576,15 @@ double BLI_gset_calc_quality(GSet *gs);
unsigned int BLI_ghashutil_ptrhash(const void *key);
bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
+/**
+ * This function implements the widely used `djb` hash apparently posted
+ * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit
+ * unsigned hash value starts at 5381 and for each byte 'c' in the
+ * string, is updated: `hash = hash * 33 + c`.
+ * This function uses the signed value of each byte.
+ *
+ * NOTE: this is the same hash method that glib 2.34.0 uses.
+ */
unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n);
#define BLI_ghashutil_strhash(key) \
(CHECK_TYPE_ANY(key, char *, const char *, const char *const), BLI_ghashutil_strhash_p(key))
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index 9cc61bc8059..8b32c09b56b 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -32,10 +32,30 @@ extern "C" {
typedef struct _GSQueue GSQueue;
GSQueue *BLI_gsqueue_new(const size_t elem_size);
+/**
+ * Returns true if the queue is empty, false otherwise.
+ */
bool BLI_gsqueue_is_empty(const GSQueue *queue);
size_t BLI_gsqueue_len(const GSQueue *queue);
+/**
+ * Retrieves and removes the first element from the queue.
+ * The value is copies to \a r_item, which must be at least \a elem_size bytes.
+ *
+ * Does not reduce amount of allocated memory.
+ */
void BLI_gsqueue_pop(GSQueue *queue, void *r_item);
+/**
+ * Copies the source value onto the end of the queue
+ *
+ * \note This copies #GSQueue.elem_size bytes from \a item,
+ * (the pointer itself is not stored).
+ *
+ * \param item: source data to be copied to the queue.
+ */
void BLI_gsqueue_push(GSQueue *queue, const void *item);
+/**
+ * Free the queue's data and the queue itself.
+ */
void BLI_gsqueue_free(GSQueue *queue);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_hash_md5.h b/source/blender/blenlib/BLI_hash_md5.h
index 227cfcc8876..7b5868d7ffc 100644
--- a/source/blender/blenlib/BLI_hash_md5.h
+++ b/source/blender/blenlib/BLI_hash_md5.h
@@ -24,17 +24,18 @@
extern "C" {
#endif
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
- * result is always in little endian byte order, so that a byte-wise
- * output yields to the wanted ASCII representation of the message
- * digest. */
-
+/**
+ * Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
+ * The result is always in little endian byte order,
+ * so that a byte-wise output yields to the wanted ASCII representation of the message digest.
+ */
void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock);
-/* Compute MD5 message digest for bytes read from STREAM. The
- * resulting message digest number will be written into the 16 bytes
- * beginning at RESBLOCK. */
-
+/**
+ * Compute MD5 message digest for bytes read from 'stream'.
+ * The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
+ * \return Non-zero if an error occurred.
+ */
int BLI_hash_md5_stream(FILE *stream, void *resblock);
char *BLI_hash_md5_to_hexdigest(void *resblock, char r_hex_digest[33]);
diff --git a/source/blender/blenlib/BLI_hash_mm2a.h b/source/blender/blenlib/BLI_hash_mm2a.h
index 193a78e6293..2619e516861 100644
--- a/source/blender/blenlib/BLI_hash_mm2a.h
+++ b/source/blender/blenlib/BLI_hash_mm2a.h
@@ -41,6 +41,9 @@ void BLI_hash_mm2a_add_int(BLI_HashMurmur2A *mm2, int data);
uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2);
+/**
+ * Non-incremental version, quicker for small keys.
+ */
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h
index 4cfb7945303..b6a12521fff 100644
--- a/source/blender/blenlib/BLI_heap.h
+++ b/source/blender/blenlib/BLI_heap.h
@@ -34,27 +34,59 @@ typedef struct HeapNode HeapNode;
typedef void (*HeapFreeFP)(void *ptr);
+/**
+ * Creates a new heap. Removed nodes are recycled, so memory usage will not shrink.
+ *
+ * \note Use when the size of the heap is known in advance.
+ */
Heap *BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
Heap *BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT;
void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
+/**
+ * Insert heap node with a value (often a 'cost') and pointer into the heap,
+ * duplicate values are allowed.
+ */
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1);
+/**
+ * Convenience function since this is a common pattern.
+ */
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
ATTR_NONNULL(1, 2);
void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1, 2);
bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1);
unsigned int BLI_heap_len(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the top node of the heap.
+ * This is the node with the lowest value.
+ */
HeapNode *BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the value of top node of the heap.
+ * This is the node with the lowest value.
+ */
float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Pop the top node off the heap and return its pointer.
+ */
void *BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1);
+/**
+ * Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls,
+ * balancing the tree still has a performance cost,
+ * but is often much less than remove/insert, difference is most noticeable with large heaps.
+ */
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) ATTR_NONNULL(1, 2);
void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr)
ATTR_NONNULL(1, 2);
-/* Return the value or pointer of a heap node. */
+/**
+ * Return the value or pointer of a heap node.
+ */
float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void *BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* only for gtest */
+/**
+ * Only for checking internal errors (gtest).
+ */
bool BLI_heap_is_valid(const Heap *heap);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_heap_simple.h b/source/blender/blenlib/BLI_heap_simple.h
index b2a1b5582e5..5583f209de0 100644
--- a/source/blender/blenlib/BLI_heap_simple.h
+++ b/source/blender/blenlib/BLI_heap_simple.h
@@ -30,14 +30,29 @@ typedef struct HeapSimple HeapSimple;
typedef void (*HeapSimpleFreeFP)(void *ptr);
+/**
+ * Creates a new simple heap, which only supports insertion and removal from top.
+ *
+ * \note Use when the size of the heap is known in advance.
+ */
HeapSimple *BLI_heapsimple_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
HeapSimple *BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT;
void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
+/**
+ * Insert heap node with a value (often a 'cost') and pointer into the heap,
+ * duplicate values are allowed.
+ */
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1);
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1);
uint BLI_heapsimple_len(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return the lowest value of the heap.
+ */
float BLI_heapsimple_top_value(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Pop the top node off the heap and return its pointer.
+ */
void *BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh
index ad030e127fe..2dca3689cb1 100644
--- a/source/blender/blenlib/BLI_index_mask.hh
+++ b/source/blender/blenlib/BLI_index_mask.hh
@@ -45,11 +45,11 @@ namespace blender {
class IndexMask {
private:
- /* The underlying reference to sorted integers. */
+ /** The underlying reference to sorted integers. */
Span<int64_t> indices_;
public:
- /* Creates an IndexMask that contains no indices. */
+ /** Creates an IndexMask that contains no indices. */
IndexMask() = default;
/**
@@ -223,6 +223,25 @@ class IndexMask {
return indices_.is_empty();
}
+ IndexMask slice(IndexRange slice) const;
+ /**
+ * Create a sub-mask that is also shifted to the beginning.
+ * The shifting to the beginning allows code to work with smaller indices,
+ * which is more memory efficient.
+ *
+ * \return New index mask with the size of #slice. It is either empty or starts with 0.
+ * It might reference indices that have been appended to #r_new_indices.
+ *
+ * Example:
+ * \code{.unparsed}
+ * this: [2, 3, 5, 7, 8, 9, 10]
+ * slice: ^--------^
+ * output: [0, 2, 4, 5]
+ * \endcode
+ *
+ * All the indices in the sub-mask are shifted by 3 towards zero,
+ * so that the first index in the output is zero.
+ */
IndexMask slice_and_offset(IndexRange slice, Vector<int64_t> &r_new_indices) const;
};
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 5e0ea4f2a99..2f41be369c1 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -104,25 +104,35 @@ enum {
#define BVH_RAYCAST_DEFAULT (BVH_RAYCAST_WATERTIGHT)
#define BVH_RAYCAST_DIST_MAX (FLT_MAX / 2.0f)
-/* callback must update nearest in case it finds a nearest result */
+/**
+ * Callback must update nearest in case it finds a nearest result.
+ */
typedef void (*BVHTree_NearestPointCallback)(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest);
-/* callback must update hit in case it finds a nearest successful hit */
+/**
+ * Callback must update hit in case it finds a nearest successful hit.
+ */
typedef void (*BVHTree_RayCastCallback)(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit);
-/* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */
+/**
+ * Callback to check if 2 nodes overlap (use thread if intersection results need to be stored).
+ */
typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread);
-/* callback to range search query */
+/**
+ * Callback to range search query.
+ */
typedef void (*BVHTree_RangeQuery)(void *userdata, int index, const float co[3], float dist_sq);
-/* callback to find nearest projected */
+/**
+ * Callback to find nearest projected.
+ */
typedef void (*BVHTree_NearestProjectedCallback)(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
@@ -131,42 +141,67 @@ typedef void (*BVHTree_NearestProjectedCallback)(void *userdata,
BVHTreeNearest *nearest);
/* callbacks to BLI_bvhtree_walk_dfs */
-/* return true to traverse into this nodes children, else skip. */
+
+/**
+ * Return true to traverse into this nodes children, else skip.
+ */
typedef bool (*BVHTree_WalkParentCallback)(const BVHTreeAxisRange *bounds, void *userdata);
-/* return true to keep walking, else early-exit the search. */
+/**
+ * Return true to keep walking, else early-exit the search.
+ */
typedef bool (*BVHTree_WalkLeafCallback)(const BVHTreeAxisRange *bounds,
int index,
void *userdata);
-/* return true to search (min, max) else (max, min). */
+/**
+ * Return true to search (min, max) else (max, min).
+ */
typedef bool (*BVHTree_WalkOrderCallback)(const BVHTreeAxisRange *bounds,
char axis,
void *userdata);
+/**
+ * \note many callers don't check for `NULL` return.
+ */
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis);
void BLI_bvhtree_free(BVHTree *tree);
-/* construct: first insert points, then call balance */
+/**
+ * Construct: first insert points, then call balance.
+ */
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints);
void BLI_bvhtree_balance(BVHTree *tree);
-/* update: first update points/nodes, then call update_tree to refit the bounding volumes */
+/**
+ * Update: first update points/nodes, then call update_tree to refit the bounding volumes.
+ * \note call before #BLI_bvhtree_update_tree().
+ */
bool BLI_bvhtree_update_node(
BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints);
+/**
+ * Call #BLI_bvhtree_update_node() first for every node/point/triangle.
+ */
void BLI_bvhtree_update_tree(BVHTree *tree);
+/**
+ * Use to check the total number of threads #BLI_bvhtree_overlap will use.
+ *
+ * \warning Must be the first tree passed to #BLI_bvhtree_overlap!
+ */
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree);
-/* collision/overlap: check two trees if they overlap,
- * alloc's *overlap with length of the int return value */
-BVHTreeOverlap *BLI_bvhtree_overlap_ex(
- const BVHTree *tree1,
- const BVHTree *tree2,
- uint *r_overlap_tot,
- /* optional callback to test the overlap before adding (must be thread-safe!) */
- BVHTree_OverlapCallback callback,
- void *userdata,
- const uint max_interactions,
- const int flag);
+/**
+ * Collision/overlap: check two trees if they overlap,
+ * alloc's *overlap with length of the int return value.
+ *
+ * \param callback: optional, to test the overlap before adding (must be thread-safe!).
+ */
+BVHTreeOverlap *BLI_bvhtree_overlap_ex(const BVHTree *tree1,
+ const BVHTree *tree2,
+ uint *r_overlap_tot,
+ BVHTree_OverlapCallback callback,
+ void *userdata,
+ const uint max_interactions,
+ const int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2,
unsigned int *r_overlap_tot,
@@ -175,14 +210,26 @@ BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersect_tot);
+/**
+ * Number of times #BLI_bvhtree_insert has been called.
+ * mainly useful for asserts functions to check we added the correct number.
+ */
int BLI_bvhtree_get_len(const BVHTree *tree);
+/**
+ * Maximum number of children that a node can have.
+ */
int BLI_bvhtree_get_tree_type(const BVHTree *tree);
float BLI_bvhtree_get_epsilon(const BVHTree *tree);
+/**
+ * This function returns the bounding box of the BVH tree.
+ */
void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]);
-/* find nearest node to the given coordinates
+/**
+ * Find nearest node to the given coordinates
* (if nearest is given it will only search nodes where
- * square distance is smaller than nearest->dist) */
+ * square distance is smaller than nearest->dist).
+ */
int BLI_bvhtree_find_nearest_ex(BVHTree *tree,
const float co[3],
BVHTreeNearest *nearest,
@@ -195,6 +242,10 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
BVHTree_NearestPointCallback callback,
void *userdata);
+/**
+ * Find the first node nearby.
+ * Favors speed over quality since it doesn't find the best target node.
+ */
int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3],
const float dist_sq,
@@ -217,6 +268,15 @@ int BLI_bvhtree_ray_cast(BVHTree *tree,
BVHTree_RayCastCallback callback,
void *userdata);
+/**
+ * Calls the callback for every ray intersection
+ *
+ * \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
+ * however using this function means existing generic callbacks can be used from custom callbacks
+ * without having to handle resetting the hit beforehand.
+ * It also avoid redundant argument and return value which aren't meaningful
+ * when collecting multiple hits.
+ */
void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree,
const float co[3],
const float dir[3],
@@ -238,7 +298,9 @@ float BLI_bvhtree_bb_raycast(const float bv[6],
const float light_end[3],
float pos[3]);
-/* range query */
+/**
+ * Range query.
+ */
int BLI_bvhtree_range_query(
BVHTree *tree, const float co[3], float radius, BVHTree_RangeQuery callback, void *userdata);
@@ -252,13 +314,27 @@ int BLI_bvhtree_find_nearest_projected(BVHTree *tree,
BVHTree_NearestProjectedCallback callback,
void *userdata);
+/**
+ * This is a generic function to perform a depth first search on the #BVHTree
+ * where the search order and nodes traversed depend on callbacks passed in.
+ *
+ * \param tree: Tree to walk.
+ * \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
+ * \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
+ * returning false exits early.
+ * \param walk_order_cb: Callback that indicates which direction to search,
+ * either from the node with the lower or higher K-DOP axis value.
+ * \param userdata: Argument passed to all callbacks.
+ */
void BLI_bvhtree_walk_dfs(BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb,
BVHTree_WalkLeafCallback walk_leaf_cb,
BVHTree_WalkOrderCallback walk_order_cb,
void *userdata);
-/* expose for bvh callbacks to use */
+/**
+ * Expose for BVH callbacks to use.
+ */
extern const float bvhtree_kdop_axes[13][3];
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_lasso_2d.h b/source/blender/blenlib/BLI_lasso_2d.h
index e920d1189a2..5f034bfdc1d 100644
--- a/source/blender/blenlib/BLI_lasso_2d.h
+++ b/source/blender/blenlib/BLI_lasso_2d.h
@@ -35,6 +35,9 @@ bool BLI_lasso_is_point_inside(const int mcoords[][2],
const int sx,
const int sy,
const int error_value);
+/**
+ * Edge version for lasso select. We assume bound-box check was done.
+ */
bool BLI_lasso_is_edge_inside(const int mcoords[][2],
const unsigned int mcoords_len,
int x0,
diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h
index 25d58a3050c..d872921defc 100644
--- a/source/blender/blenlib/BLI_linklist.h
+++ b/source/blender/blenlib/BLI_linklist.h
@@ -58,8 +58,15 @@ LinkNode *BLI_linklist_find_last(LinkNode *list) ATTR_WARN_UNUSED_RESULT;
void BLI_linklist_reverse(LinkNode **listp) ATTR_NONNULL(1);
+/**
+ * Move an item from its current position to a new one inside a single-linked list.
+ * \note `*listp` may be modified.
+ */
void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index) ATTR_NONNULL(1);
+/**
+ * A version of #BLI_linklist_prepend that takes the allocated link.
+ */
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) ATTR_NONNULL(1, 3);
void BLI_linklist_prepend(LinkNode **listp, void *ptr) ATTR_NONNULL(1);
void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma)
@@ -67,7 +74,11 @@ void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma
void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, struct BLI_mempool *mempool)
ATTR_NONNULL(1, 3);
-/* use LinkNodePair to avoid full search */
+/* Use #LinkNodePair to avoid full search. */
+
+/**
+ * A version of append that takes the allocated link.
+ */
void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
ATTR_NONNULL(1, 3);
void BLI_linklist_append(LinkNodePair *list_pair, void *ptr) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index cf525d1c2af..7d808d339e9 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -33,89 +33,233 @@
extern "C" {
#endif
+/**
+ * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
+ */
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Returns the 0-based index of the first element of listbase which contains the specified
+ * null-terminated string at the specified offset, or -1 if not found.
+ */
int BLI_findstringindex(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* find forwards */
+/* Find forwards. */
+
+/**
+ * Returns the nth element of \a listbase, numbering from 0.
+ */
void *BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Finds the first element of \a listbase which contains the null-terminated
+ * string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_findstring(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of \a listbase which contains a pointer to the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_findstring_ptr(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of listbase which contains the specified pointer value
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_findptr(const struct ListBase *listbase,
const void *ptr,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the first element of listbase which contains the specified bytes
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Find the first item in the list that matches the given string, or the given index as fallback.
+ *
+ * \note The string is only used is non-NULL and non-empty.
+ *
+ * \return The found item, or NULL.
+ */
void *BLI_listbase_string_or_index_find(const struct ListBase *listbase,
const char *string,
const size_t string_offset,
const int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* find backwards */
+/* Find backwards. */
+
+/**
+ * Returns the nth-last element of \a listbase, numbering from 0.
+ */
void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Finds the last element of \a listbase which contains the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindstring(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of \a listbase which contains a pointer to the
+ * null-terminated string \a id at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindstring_ptr(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of listbase which contains the specified pointer value
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_rfindptr(const struct ListBase *listbase,
const void *ptr,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Finds the last element of listbase which contains the specified bytes
+ * at the specified offset, returning NULL if not found.
+ */
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Removes and disposes of the entire contents of \a listbase using guardedalloc.
+ */
void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Appends \a vlink (assumed to begin with a Link) onto listbase.
+ */
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Removes \a vlink from \a listbase. Assumes it is linked into there!
+ */
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Checks that \a vlink is linked into listbase, removing it from there if so.
+ */
bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Removes the head from \a listbase and returns it.
+ */
void *BLI_pophead(ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Removes the tail from \a listbase and returns it.
+ */
void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Prepends \a vlink (assumed to begin with a Link) onto listbase.
+ */
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
+ * Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
+ */
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink)
ATTR_NONNULL(1);
+/**
+ * Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
+ * Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
+ */
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink)
ATTR_NONNULL(1);
+/**
+ * Insert a link in place of another, without changing its position in the list.
+ *
+ * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
+ * - `vreplacelink` *must* be in the list.
+ * - `vnewlink` *must not* be in the list.
+ */
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
ATTR_NONNULL(1, 2, 3);
+/**
+ * Sorts the elements of listbase into the order defined by cmp
+ * (which should return 1 if its first arg should come after its second arg).
+ * This uses insertion sort, so NOT ok for large list.
+ */
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *))
ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase,
int (*cmp)(void *, const void *, const void *),
void *thunk) ATTR_NONNULL(1, 2);
+/**
+ * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
+ * item if new position would exceed list (could optionally move to head/tail).
+ *
+ * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
+ * to move \a vlink before previous, or 1 to move behind next.
+ * \return If position of \a vlink has changed.
+ */
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
+/**
+ * Move the link at the index \a from to the position at index \a to.
+ *
+ * \return If the move was successful.
+ */
bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL();
+/**
+ * Removes and disposes of the entire contents of listbase using direct free(3).
+ */
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
+/**
+ * Returns the number of elements in \a listbase, up until (and including count_max)
+ *
+ * \note Use to avoid redundant looping.
+ */
int BLI_listbase_count_at_most(const struct ListBase *listbase,
const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Returns the number of elements in \a listbase.
+ */
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
+ */
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+/**
+ * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
+ */
void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb)
ATTR_NONNULL(1, 2);
+/**
+ * Swaps \a vlinka and \a vlinkb from their respective lists.
+ * Assumes they are both already in their \a listbasea!
+ */
void BLI_listbases_swaplinks(struct ListBase *listbasea,
struct ListBase *listbaseb,
void *vlinka,
void *vlinkb) ATTR_NONNULL(2, 3);
+/**
+ * Moves the entire contents of \a src onto the end of \a dst.
+ */
void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
+/**
+ * Moves the entire contents of \a src at the beginning of \a dst.
+ */
void BLI_movelisttolist_reverse(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
+/**
+ * Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
+ */
void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1);
+/**
+ * \param vlink: Link to make first.
+ */
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
+/**
+ * \param vlink: Link to make last.
+ */
void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
/**
@@ -134,7 +278,9 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
lb->first = lb->last = (void *)0;
}
-/* create a generic list node containing link to provided data */
+/**
+ * Create a generic list node containing link to provided data.
+ */
struct LinkData *BLI_genericNodeN(void *data);
/**
@@ -188,13 +334,17 @@ struct LinkData *BLI_genericNodeN(void *data);
#define LISTBASE_FOREACH_BACKWARD(type, var, list) \
for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev))
-/** A version of #LISTBASE_FOREACH that supports removing the item we're looping over. */
+/**
+ * A version of #LISTBASE_FOREACH that supports removing the item we're looping over.
+ */
#define LISTBASE_FOREACH_MUTABLE(type, var, list) \
for (type var = (type)((list)->first), *var##_iter_next; \
((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \
var = var##_iter_next)
-/** A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over. */
+/**
+ * A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over.
+ */
#define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \
for (type var = (type)((list)->last), *var##_iter_prev; \
((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 9b54f780296..83822481112 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -97,6 +97,7 @@ extern "C" {
/******************************* Float ******************************/
+/* powf is really slow for raising to integer powers. */
MINLINE float pow2f(float x);
MINLINE float pow3f(float x);
MINLINE float pow4f(float x);
@@ -120,11 +121,18 @@ MINLINE double interpd(double a, double b, double t);
MINLINE float ratiof(float min, float max, float pos);
MINLINE double ratiod(double min, double max, double pos);
+/**
+ * Map a normalized value, i.e. from interval [0, 1] to interval [a, b].
+ */
MINLINE float scalenorm(float a, float b, float x);
+/**
+ * Map a normalized value, i.e. from interval [0, 1] to interval [a, b].
+ */
MINLINE double scalenormd(double a, double b, double x);
/* NOTE: Compilers will upcast all types smaller than int to int when performing arithmetic
* operation. */
+
MINLINE int square_s(short a);
MINLINE int square_uchar(unsigned char a);
MINLINE int cube_s(short a);
@@ -170,7 +178,23 @@ MINLINE int clamp_i(int value, int min, int max);
MINLINE float clamp_f(float value, float min, float max);
MINLINE size_t clamp_z(size_t value, size_t min, size_t max);
+/**
+ * Almost-equal for IEEE floats, using absolute difference method.
+ *
+ * \param max_diff: the maximum absolute difference.
+ */
MINLINE int compare_ff(float a, float b, const float max_diff);
+/**
+ * Almost-equal for IEEE floats, using their integer representation
+ * (mixing ULP and absolute difference methods).
+ *
+ * \param max_diff: is the maximum absolute difference (allows to take care of the near-zero area,
+ * where relative difference methods cannot really work).
+ * \param max_ulps: is the 'maximum number of floats + 1'
+ * allowed between \a a and \a b to consider them equal.
+ *
+ * \see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+ */
MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps);
MINLINE bool compare_threshold_relative(const float value1,
const float value2,
@@ -180,13 +204,25 @@ MINLINE float signf(float f);
MINLINE int signum_i_ex(float a, float eps);
MINLINE int signum_i(float a);
+/**
+ * Used for zoom values.
+ */
MINLINE float power_of_2(float f);
+/**
+ * Returns number of (base ten) *significant* digits of integer part of given float
+ * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
+ */
MINLINE int integer_digits_f(const float f);
+/**
+ * Returns number of (base ten) *significant* digits of integer part of given double
+ * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
+ */
MINLINE int integer_digits_d(const double d);
MINLINE int integer_digits_i(const int i);
-/* these don't really fit anywhere but were being copied about a lot */
+/* These don't really fit anywhere but were being copied about a lot. */
+
MINLINE int is_power_of_2_i(int n);
MINLINE int power_of_2_max_i(int n);
MINLINE int power_of_2_min_i(int n);
@@ -196,9 +232,19 @@ MINLINE unsigned int power_of_2_min_u(unsigned int x);
MINLINE unsigned int log2_floor_u(unsigned int x);
MINLINE unsigned int log2_ceil_u(unsigned int x);
+/**
+ * Integer division that rounds 0.5 up, particularly useful for color blending
+ * with integers, to avoid gradual darkening when rounding down.
+ */
MINLINE int divide_round_i(int a, int b);
+/**
+ * modulo that handles negative numbers, works the same as Python's.
+ */
MINLINE int mod_i(int i, int n);
+/**
+ * Round to closest even number, halfway cases are rounded away from zero.
+ */
MINLINE float round_to_even(float f);
MINLINE signed char round_fl_to_char(float a);
@@ -230,18 +276,40 @@ MINLINE int round_db_to_int_clamp(double a);
MINLINE unsigned int round_db_to_uint_clamp(double a);
int pow_i(int base, int exp);
+
+/**
+ * \param ndigits: must be between 0 and 21.
+ */
double double_round(double x, int ndigits);
+/**
+ * Floor to the nearest power of 10, e.g.:
+ * - 15.0 -> 10.0
+ * - 0.015 -> 0.01
+ * - 1.0 -> 1.0
+ *
+ * \param f: Value to floor, must be over 0.0.
+ * \note If we wanted to support signed values we could if this becomes necessary.
+ */
float floor_power_of_10(float f);
+/**
+ * Ceiling to the nearest power of 10, e.g.:
+ * - 15.0 -> 100.0
+ * - 0.015 -> 0.1
+ * - 1.0 -> 1.0
+ *
+ * \param f: Value to ceiling, must be over 0.0.
+ * \note If we wanted to support signed values we could if this becomes necessary.
+ */
float ceil_power_of_10(float f);
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic pop
#endif
-/* asserts, some math functions expect normalized inputs
- * check the vector is unit length, or zero length (which can't be helped in some cases).
- */
+/* Asserts, some math functions expect normalized inputs
+ * check the vector is unit length, or zero length (which can't be helped in some cases). */
+
#ifndef NDEBUG
/** \note 0.0001 is too small because normals may be converted from short's: see T34322. */
# define BLI_ASSERT_UNIT_EPSILON 0.0002f
diff --git a/source/blender/blenlib/BLI_math_boolean.hh b/source/blender/blenlib/BLI_math_boolean.hh
index 79b1483bfb8..20fd00b2aa4 100644
--- a/source/blender/blenlib/BLI_math_boolean.hh
+++ b/source/blender/blenlib/BLI_math_boolean.hh
@@ -32,20 +32,24 @@
namespace blender {
-/* #orient2d gives the exact result, using multi-precision arithmetic when result
+/**
+ * #orient2d gives the exact result, using multi-precision arithmetic when result
* is close to zero. orient3d_fast just uses double arithmetic, so may be
* wrong if the answer is very close to zero.
- * Similarly, for #incircle and #incircle_fast. */
+ * Similarly, for #incircle and #incircle_fast.
+ */
int orient2d(const double2 &a, const double2 &b, const double2 &c);
int orient2d_fast(const double2 &a, const double2 &b, const double2 &c);
int incircle(const double2 &a, const double2 &b, const double2 &c, const double2 &d);
int incircle_fast(const double2 &a, const double2 &b, const double2 &c, const double2 &d);
-/* #orient3d gives the exact result, using multi-precision arithmetic when result
+/**
+ * #orient3d gives the exact result, using multi-precision arithmetic when result
* is close to zero. orient3d_fast just uses double arithmetic, so may be
* wrong if the answer is very close to zero.
- * Similarly, for #insphere and #insphere_fast. */
+ * Similarly, for #insphere and #insphere_fast.
+ */
int orient3d(const double3 &a, const double3 &b, const double3 &c, const double3 &d);
int orient3d_fast(const double3 &a, const double3 &b, const double3 &c, const double3 &d);
@@ -55,8 +59,23 @@ int insphere_fast(
const double3 &a, const double3 &b, const double3 &c, const double3 &d, const double3 &e);
#ifdef WITH_GMP
+/**
+ * Return +1 if a, b, c are in CCW order around a circle in the plane.
+ * Return -1 if they are in CW order, and 0 if they are in line.
+ */
int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c);
+/**
+ * Return +1 if d is in the oriented circle through a, b, and c.
+ * The oriented circle goes CCW through a, b, and c.
+ * Return -1 if d is outside, and 0 if it is on the circle.
+ */
int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d);
+/**
+ * Return +1 if d is below the plane containing a, b, c (which appear
+ * CCW when viewed from above the plane).
+ * Return -1 if d is above the plane.
+ * Return 0 if it is on the plane.
+ */
int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d);
#endif
} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 28257ba418a..32424f37676 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -31,6 +31,10 @@
extern "C" {
#endif
+/* -------------------------------------------------------------------- */
+/** \name Defines
+ * \{ */
+
/* YCbCr */
#define BLI_YCC_ITU_BT601 0
#define BLI_YCC_ITU_BT709 1
@@ -40,7 +44,11 @@ extern "C" {
#define BLI_YUV_ITU_BT601 0
#define BLI_YUV_ITU_BT709 1
-/******************* Conversion to RGB ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Conversion to RGB
+ * \{ */
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b);
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3]);
@@ -51,9 +59,18 @@ void yuv_to_rgb(float y, float u, float v, float *r_r, float *r_g, float *r_b, i
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace);
void cpack_to_rgb(unsigned int col, float *r_r, float *r_g, float *r_b);
-/***************** Conversion from RGB ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Conversion from RGB
+ * \{ */
void rgb_to_yuv(float r, float g, float b, float *r_y, float *r_u, float *r_v, int colorspace);
+/**
+ * The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f
+ *
+ * Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255.
+ */
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace);
void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v);
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3]);
@@ -64,9 +81,19 @@ void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3]);
void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float *r_v);
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3]);
unsigned int rgb_to_cpack(float r, float g, float b);
+/**
+ * We define a 'cpack' here as a (3 byte color code)
+ * number that can be expressed like 0xFFAA66 or so.
+ * For that reason it is sensitive for endianness... with this function it works correctly.
+ * \see #imm_cpack
+ */
unsigned int hsv_to_cpack(float h, float s, float v);
-/**************** Profile Transformations *****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Profile Transformations
+ * \{ */
float srgb_to_linearrgb(float c);
float linearrgb_to_srgb(float c);
@@ -90,7 +117,11 @@ MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[
void BLI_init_srgb_conversion(void);
-/**************** Alpha Transformations *****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Alpha Transformations
+ * \{ */
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4]);
MINLINE void premul_to_straight_v4(float color[4]);
@@ -99,13 +130,34 @@ MINLINE void straight_to_premul_v4(float color[4]);
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]);
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]);
-/************************** Other *************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
+
+/**
+ * If the requested RGB shade contains a negative weight for
+ * one of the primaries, it lies outside the color gamut
+ * accessible from the given triple of primaries. Desaturate
+ * it by adding white, equal quantities of R, G, and B, enough
+ * to make RGB all positive. The function returns 1 if the
+ * components were modified, zero otherwise.
+ */
int constrain_rgb(float *r, float *g, float *b);
void minmax_rgb(short c[3]);
+/**
+ * Clamp `hsv` to usable values.
+ */
void hsv_clamp_v(float hsv[3], float v_max);
+/**
+ * Applies an HUE offset to a float RGB color.
+ */
void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset);
+/**
+ * Applies an HUE offset to a byte RGB color.
+ */
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset);
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3]);
@@ -113,11 +165,28 @@ void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4]);
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3]);
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]);
+/**
+ * ITU-R BT.709 primaries
+ * https://en.wikipedia.org/wiki/Relative_luminance
+ *
+ * Real values are:
+ * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
+ * according to: "Derivation of Basic Television Color Equations", RP 177-1993
+ *
+ * As this sums slightly above 1.0, the document recommends to use:
+ * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
+ *
+ * The high precision values are used to calculate the rounded byte weights so they add up to 255:
+ * `54(R) + 182(G) + 19(B)`
+ */
MINLINE float rgb_to_grayscale(const float rgb[3]);
MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]);
MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit);
+/**
+ * Return triangle noise in [-0.5..1.5] range.
+ */
MINLINE float dither_random_value(float s, float t);
MINLINE void float_to_byte_dither_v3(
unsigned char b[3], const float f[3], float dither, float s, float t);
@@ -145,7 +214,11 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack);
void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max);
void wavelength_to_xyz_table(float *r_table, int width);
-/********* lift/gamma/gain / ASC-CDL conversion ***********/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name lift/gamma/gain / ASC-CDL conversion
+ * \{ */
void lift_gamma_gain_to_asc_cdl(const float *lift,
const float *gamma,
@@ -158,6 +231,8 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
# include "intern/math_color_inline.c"
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index be10b302144..55d118d17de 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -37,16 +37,24 @@
extern "C" {
#endif
-/********************************** Polygons *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Polygons
+ * \{ */
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]);
float normal_quad_v3(
float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+/**
+ * Computes the normal of a planar polygon See Graphics Gems for computing newell normal.
+ */
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr);
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
MINLINE float area_squared_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
MINLINE float area_tri_signed_v2(const float v1[2], const float v2[2], const float v3[2]);
+
+/* Triangles */
+
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3]);
float area_squared_tri_v3(const float v1[3], const float v2[3], const float v3[3]);
float area_tri_signed_v3(const float v1[3],
@@ -68,38 +76,88 @@ float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]);
MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2]);
void cross_poly_v3(float n[3], const float verts[][3], unsigned int nr);
+/**
+ * Scalar cross product of a 2d polygon.
+ *
+ * - equivalent to `area * 2`
+ * - useful for checking polygon winding (a positive value is clockwise).
+ */
float cross_poly_v2(const float verts[][2], unsigned int nr);
-/********************************* Planes **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Planes
+ * \{ */
+/**
+ * Calculate a plane from a point and a direction,
+ * \note \a point_no isn't required to be normalized.
+ */
void plane_from_point_normal_v3(float r_plane[4],
const float plane_co[3],
const float plane_no[3]);
+/**
+ * Get a point and a direction from a plane.
+ */
void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3]);
+/**
+ * Version of #plane_to_point_vector_v3 that gets a unit length vector.
+ */
void plane_to_point_vector_v3_normalized(const float plane[4],
float r_plane_co[3],
float r_plane_no[3]);
MINLINE float plane_point_side_v3(const float plane[4], const float co[3]);
-/********************************* Volume **********************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Volume
+ * \{ */
+
+/**
+ * The volume from a tetrahedron, points can be in any order
+ */
float volume_tetrahedron_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
+/**
+ * The volume from a tetrahedron, normal pointing inside gives negative volume
+ */
float volume_tetrahedron_signed_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
+/**
+ * The volume from a triangle that is made into a tetrahedron.
+ * This uses a simplified formula where the tip of the tetrahedron is in the world origin.
+ * Using this method, the total volume of a closed triangle mesh can be calculated.
+ * Note that you need to divide the result by 6 to get the actual volume.
+ */
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3]);
float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3]);
+/**
+ * Check if the edge is convex or concave
+ * (depends on face winding)
+ * Copied from BM_edge_is_convex().
+ */
bool is_edge_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+/**
+ * Evaluate if entire quad is a proper convex quad
+ */
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
bool is_poly_convex_v2(const float verts[][2], unsigned int nr);
+/**
+ * Check if either of the diagonals along this quad create flipped triangles
+ * (normals pointing away from eachother).
+ * - (1 << 0): (v1-v3) is flipped.
+ * - (1 << 1): (v2-v4) is flipped.
+ */
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v2[3],
@@ -111,36 +169,88 @@ bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
const float v4[3],
const float normal[3]);
-/********************************* Distance **********************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Distance
+ * \{ */
+
+/**
+ * Distance p to line v1-v2 using Hesse formula (NO LINE PIECE!)
+ */
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2]);
+/**
+ * Distance p to line-piece v1-v2.
+ */
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_signed_squared_to_plane_v3(const float p[3], const float plane[4]);
float dist_squared_to_plane_v3(const float p[3], const float plane[4]);
+/**
+ * Return the signed distance from the point to the plane.
+ */
float dist_signed_to_plane_v3(const float p[3], const float plane[4]);
float dist_to_plane_v3(const float p[3], const float plane[4]);
-/* plane3 versions */
+/* Plane3 versions. */
+
float dist_signed_squared_to_plane3_v3(const float p[3], const float plane[3]);
float dist_squared_to_plane3_v3(const float p[3], const float plane[3]);
float dist_signed_to_plane3_v3(const float p[3], const float plane[3]);
float dist_to_plane3_v3(const float p[3], const float plane[3]);
+/**
+ * Distance v1 to line-piece l1-l2 in 3D.
+ */
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
+/**
+ * Check if \a p is inside the 2x planes defined by `(v1, v2, v3)`
+ * where the 3x points define 2x planes.
+ *
+ * \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex.
+ *
+ * \note the distance from \a v1 & \a v3 to \a v2 doesn't matter
+ * (it just defines the planes).
+ *
+ * \return the lowest squared distance to either of the planes.
+ * where `(return < 0.0)` is outside.
+ *
+ * <pre>
+ * v1
+ * +
+ * /
+ * x - out / x - inside
+ * /
+ * +----+
+ * v2 v3
+ * x - also outside
+ * </pre>
+ */
float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3],
const float axis_ref[3]);
+/**
+ * Compute the squared distance of a point to a line (defined as ray).
+ * \param ray_origin: A point on the line.
+ * \param ray_direction: Normalized direction of the line.
+ * \param co: Point to which the distance is to be calculated.
+ */
float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
const float ray_direction[3],
const float co[3]);
+/**
+ * Find the closest point in a seg to a ray and return the distance squared.
+ * \param r_point: Is the point on segment closest to ray
+ * (or to ray_origin if the ray and the segment are parallel).
+ * \param r_depth: the distance of r_point projection on ray to the ray_origin.
+ */
float dist_squared_ray_to_seg_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -148,6 +258,9 @@ float dist_squared_ray_to_seg_v3(const float ray_origin[3],
float r_point[3],
float *r_depth);
+/**
+ * Returns the coordinates of the nearest vertex and the farthest vertex from a plane (or normal).
+ */
void aabb_get_near_far_from_plane(const float plane_no[3],
const float bbmin[3],
const float bbmax[3],
@@ -162,12 +275,17 @@ struct DistRayAABB_Precalc {
void dist_squared_ray_to_aabb_v3_precalc(struct DistRayAABB_Precalc *neasrest_precalc,
const float ray_origin[3],
const float ray_direction[3]);
+/**
+ * Returns the distance from a ray to a bound-box (projected on ray)
+ */
float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float r_point[3],
float *r_depth);
-/* when there is no advantage to precalc. */
+/**
+ * Use when there is no advantage to pre-calculation.
+ */
float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3],
const float ray_direction[3],
const float bb_min[3],
@@ -182,10 +300,17 @@ struct DistProjectedAABBPrecalc {
float pmat[4][4];
float mval[2];
};
+/**
+ * \param projmat: Projection Matrix (usually perspective
+ * matrix multiplied by object matrix).
+ */
void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *precalc,
const float projmat[4][4],
const float winsize[2],
const float mval[2]);
+/**
+ * Returns the distance from a 2D coordinate to a bound-box (projected).
+ */
float dist_squared_to_projected_aabb(struct DistProjectedAABBPrecalc *data,
const float bbmin[3],
const float bbmax[3],
@@ -205,21 +330,42 @@ double closest_to_line_v2_db(double r_close[2],
const double p[2],
const double l1[2],
const double l2[2]);
+/**
+ * Find closest point to p on line through (`l1`, `l2`) and return lambda,
+ * where (0 <= lambda <= 1) when `p` is in the line segment (`l1`, `l2`).
+ */
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
+/**
+ * Point closest to v1 on line v2-v3 in 2D.
+ */
void closest_to_line_segment_v2(float r_close[2],
const float p[2],
const float l1[2],
const float l2[2]);
+/**
+ * Point closest to v1 on line v2-v3 in 3D.
+ */
void closest_to_line_segment_v3(float r_close[3],
const float p[3],
const float l1[3],
const float l2[3]);
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3]);
+/**
+ * Find the closest point on a plane.
+ *
+ * \param r_close: Return coordinate
+ * \param plane: The plane to test against.
+ * \param pt: The point to find the nearest of
+ *
+ * \note non-unit-length planes are supported.
+ */
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3]);
void closest_to_plane3_normalized_v3(float r_close[3], const float plane[3], const float pt[3]);
void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt[3]);
-/* Set 'r' to the point in triangle (v1, v2, v3) closest to point 'p' */
+/**
+ * Set 'r' to the point in triangle (v1, v2, v3) closest to point 'p'.
+ */
void closest_on_tri_to_point_v3(
float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3]);
@@ -232,6 +378,13 @@ float ray_point_factor_v3(const float p[3],
const float ray_origin[3],
const float ray_direction[3]);
+/**
+ * A simplified version of #closest_to_line_v3
+ * we only need to return the `lambda`
+ *
+ * \param epsilon: avoid approaching divide-by-zero.
+ * Passing a zero will just check for nonzero division.
+ */
float line_point_factor_v3_ex(const float p[3],
const float l1[3],
const float l2[3],
@@ -246,14 +399,25 @@ float line_point_factor_v2_ex(const float p[2],
const float fallback);
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]);
+/**
+ * \note #isect_line_plane_v3() shares logic.
+ */
float line_plane_factor_v3(const float plane_co[3],
const float plane_no[3],
const float l1[3],
const float l2[3]);
+/**
+ * Ensure the distance between these points is no greater than 'dist'.
+ * If it is, scale them both into the center.
+ */
void limit_dist_v3(float v1[3], float v2[3], const float dist);
-/******************************* Intersection ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Intersection
+ * \{ */
/* TODO: int return value consistency. */
@@ -263,7 +427,13 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist);
#define ISECT_LINE_LINE_EXACT 1
#define ISECT_LINE_LINE_CROSS 2
+/**
+ * Intersect Line-Line, floats.
+ */
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
+/**
+ * Returns a point on each segment that is closest to the other.
+ */
void isect_seg_seg_v3(const float a0[3],
const float a1[3],
const float b0[3],
@@ -271,7 +441,21 @@ void isect_seg_seg_v3(const float a0[3],
float r_a[3],
float r_b[3]);
+/* intersect Line-Line, shorts */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]);
+/**
+ * Get intersection point of two 2D segments.
+ *
+ * \param endpoint_bias: Bias to use when testing for end-point overlap.
+ * A positive value considers intersections that extend past the endpoints,
+ * negative values contract the endpoints.
+ * Note the bias is applied to a 0-1 factor, not scaled to the length of segments.
+ *
+ * \returns intersection type:
+ * - -1: collinear.
+ * - 1: intersection.
+ * - 0: no intersection.
+ */
int isect_seg_seg_v2_point_ex(const float v0[2],
const float v1[2],
const float v2[2],
@@ -284,12 +468,37 @@ bool isect_seg_seg_v2_simple(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2]);
+/**
+ * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
+ * <pre>
+ * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
+ * </pre>
+ * \returns intersection type:
+ * - ISECT_LINE_LINE_COLINEAR: collinear.
+ * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
+ * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
+ * - ISECT_LINE_LINE_NONE: no intersection.
+ * Also returns lambda and mu in r_lambda and r_mu.
+ */
int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
const double v2[2],
const double v3[2],
const double v4[2],
double *r_lambda,
double *r_mu);
+/**
+ * \param l1, l2: Coordinates (point of line).
+ * \param sp, r: Coordinate and radius (sphere).
+ * \return r_p1, r_p2: Intersection coordinates.
+ *
+ * \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
+ * based on the direction defined by `l2 - l1`,
+ * this direction compared with the normal of each point on the sphere:
+ * \a r_p1 always has a >= 0.0 dot product.
+ * \a r_p2 always has a <= 0.0 dot product.
+ * For example, when \a l1 is inside the sphere and \a l2 is outside,
+ * \a r_p1 will always be between \a l1 and \a l2.
+ */
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
@@ -303,8 +512,17 @@ int isect_line_sphere_v2(const float l1[2],
float r_p1[2],
float r_p2[2]);
+/**
+ * Intersect Line-Line, floats - gives intersection point.
+ */
int isect_line_line_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2]);
+/**
+ * \return The number of point of interests
+ * 0 - lines are collinear
+ * 1 - lines are coplanar, i1 is set to intersection
+ * 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively
+ */
int isect_line_line_epsilon_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -318,12 +536,22 @@ int isect_line_line_v3(const float v1[3],
const float v4[3],
float r_i1[3],
float r_i2[3]);
+/**
+ * Intersection point strictly between the two lines
+ * \return false when no intersection is found.
+ */
bool isect_line_line_strict_v3(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
float vi[3],
float *r_lambda);
+/**
+ * Check if two rays are not parallel and returns a factor that indicates
+ * the distance from \a ray_origin_b to the closest point on ray-a to ray-b.
+ *
+ * \note Neither directions need to be normalized.
+ */
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
@@ -338,30 +566,85 @@ bool isect_ray_ray_v3(const float ray_origin_a[3],
float *r_lambda_a,
float *r_lambda_b);
+/**
+ * if clip is nonzero, will only return true if lambda is >= 0.0
+ * (i.e. intersection point is along positive \a ray_direction)
+ *
+ * \note #line_plane_factor_v3() shares logic.
+ */
bool isect_ray_plane_v3(const float ray_origin[3],
const float ray_direction[3],
const float plane[4],
float *r_lambda,
const bool clip);
+/**
+ * Check if a point is behind all planes.
+ */
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]);
+/**
+ * Check if a point is in front all planes.
+ * Same as isect_point_planes_v3 but with planes facing the opposite direction.
+ */
bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3]);
+/**
+ * Intersect line/plane.
+ *
+ * \param r_isect_co: The intersection point.
+ * \param l1: The first point of the line.
+ * \param l2: The second point of the line.
+ * \param plane_co: A point on the plane to intersect with.
+ * \param plane_no: The direction of the plane (does not need to be normalized).
+ *
+ * \note #line_plane_factor_v3() shares logic.
+ */
bool isect_line_plane_v3(float r_isect_co[3],
const float l1[3],
const float l2[3],
const float plane_co[3],
const float plane_no[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect three planes, return the point where all 3 meet.
+ * See Graphics Gems 1 pg 305
+ *
+ * \param plane_a, plane_b, plane_c: Planes.
+ * \param r_isect_co: The resulting intersection point.
+ */
bool isect_plane_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
const float plane_c[4],
float r_isect_co[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect two planes, return a point on the intersection and a vector
+ * that runs on the direction of the intersection.
+ * \note this is a slightly reduced version of #isect_plane_plane_plane_v3
+ *
+ * \param plane_a, plane_b: Planes.
+ * \param r_isect_co: The resulting intersection point.
+ * \param r_isect_no: The resulting vector of the intersection.
+ *
+ * \note \a r_isect_no isn't unit length.
+ */
bool isect_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
float r_isect_co[3],
float r_isect_no[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Intersect all planes, calling `callback_fn` for each point that intersects
+ * 3 of the planes that isn't outside any of the other planes.
+ *
+ * This can be thought of as calculating a convex-hull from an array of planes.
+ *
+ * \param eps_coplanar: Epsilon for testing if two planes are aligned (co-planar).
+ * \param eps_isect: Epsilon for testing of a point is behind any of the planes.
+ *
+ * \warning As complexity is a little under `O(N^3)`, this is only suitable for small arrays.
+ *
+ * \note This function could be optimized by some spatial structure.
+ */
bool isect_planes_v3_fn(
const float planes[][4],
const int planes_len,
@@ -371,6 +654,11 @@ bool isect_planes_v3_fn(
void *user_data);
/* line/ray triangle */
+
+/**
+ * Test if the line starting at p1 ending at p2 intersects the triangle v0..v2
+ * return non zero if it does.
+ */
bool isect_line_segment_tri_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -378,6 +666,9 @@ bool isect_line_segment_tri_v3(const float p1[3],
const float v2[3],
float *r_lambda,
float r_uv[2]);
+/**
+ * Like #isect_line_segment_tri_v3, but allows epsilon tolerance around triangle.
+ */
bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -394,6 +685,10 @@ bool isect_axial_line_segment_tri_v3(const int axis,
const float v2[3],
float *r_lambda);
+/**
+ * Test if the ray starting at p1 going in d direction intersects the triangle v0..v2
+ * return non zero if it does.
+ */
bool isect_ray_tri_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -417,6 +712,16 @@ bool isect_ray_tri_epsilon_v3(const float ray_origin[3],
float *r_lambda,
float r_uv[2],
const float epsilon);
+/**
+ * Intersect two triangles.
+ *
+ * \param r_i1, r_i2: Retrieve the overlapping edge between the 2 triangles.
+ * \param r_tri_a_edge_isect_count: Indicates how many edges in the first triangle are intersected.
+ * \return true when the triangles intersect.
+ *
+ * \note If it exists, \a r_i1 will be a point on the edge of the 1st triangle.
+ * \note intersections between coplanar triangles are currently undetected.
+ */
bool isect_tri_tri_v3_ex(const float tri_a[3][3],
const float tri_b[3][3],
float r_i1[3],
@@ -438,7 +743,9 @@ bool isect_tri_tri_v2(const float p1[2],
const float q2[2],
const float r2[2]);
-/* water-tight ray-cast (requires pre-calculation). */
+/**
+ * Water-tight ray-cast (requires pre-calculation).
+ */
struct IsectRayPrecalc {
/* Maximal dimension `kz`, and orthogonal dimensions. */
int kx, ky, kz;
@@ -456,7 +763,9 @@ bool isect_ray_tri_watertight_v3(const float ray_origin[3],
const float v2[3],
float *r_dist,
float r_uv[2]);
-/* slower version which calculates IsectRayPrecalc each time */
+/**
+ * Slower version which calculates #IsectRayPrecalc each time.
+ */
bool isect_ray_tri_watertight_v3_simple(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -478,7 +787,8 @@ bool isect_ray_line_v3(const float ray_origin[3],
const float v1[3],
float *r_lambda);
-/* point in polygon */
+/* Point in polygon. */
+
bool isect_point_poly_v2(const float pt[2],
const float verts[][2],
const unsigned int nr,
@@ -488,27 +798,50 @@ bool isect_point_poly_v2_int(const int pt[2],
const unsigned int nr,
const bool use_holes);
+/**
+ * Point in quad - only convex quads.
+ */
int isect_point_quad_v2(
const float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2]);
+/**
+ * Only single direction.
+ */
bool isect_point_tri_v2_cw(const float pt[2],
const float v1[2],
const float v2[2],
const float v3[2]);
+/**
+ * \code{.unparsed}
+ * x1,y2
+ * | \
+ * | \ .(a,b)
+ * | \
+ * x1,y1-- x2,y1
+ * \endcode
+ */
int isect_point_tri_v2_int(
const int x1, const int y1, const int x2, const int y2, const int a, const int b);
bool isect_point_tri_prism_v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3]);
+/**
+ * \param r_isect_co: The point \a p projected onto the triangle.
+ * \return True when \a p is inside the triangle.
+ * \note Its up to the caller to check the distance between \a p and \a r_vi
+ * against an error margin.
+ */
bool isect_point_tri_v3(const float p[3],
const float v1[3],
const float v2[3],
const float v3[3],
float r_isect_co[3]);
-/* axis-aligned bounding box */
+/**
+ * Axis-aligned bounding box.
+ */
bool isect_aabb_aabb_v3(const float min1[3],
const float max1[3],
const float min2[3],
@@ -527,6 +860,13 @@ bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float *tmin);
+/**
+ * Test a bounding box (AABB) for ray intersection.
+ * Assumes the ray is already local to the boundbox space.
+ *
+ * \note \a direction should be normalized
+ * if you intend to use the \a tmin or \a tmax distance results!
+ */
bool isect_ray_aabb_v3_simple(const float orig[3],
const float dir[3],
const float bb_min[3],
@@ -539,6 +879,14 @@ bool isect_ray_aabb_v3_simple(const float orig[3],
#define ISECT_AABB_PLANE_CROSS_ANY 1
#define ISECT_AABB_PLANE_IN_FRONT_ALL 2
+/**
+ * Checks status of an AABB in relation to a list of planes.
+ *
+ * \returns intersection type:
+ * - ISECT_AABB_PLANE_BEHIND_ONE (0): AABB is completely behind at least 1 plane;
+ * - ISECT_AABB_PLANE_CROSS_ANY (1): AABB intersects at least 1 plane;
+ * - ISECT_AABB_PLANE_IN_FRONT_ALL (2): AABB is completely in front of all planes;
+ */
int isect_aabb_planes_v3(const float (*planes)[4],
const int totplane,
const float bbmin[3],
@@ -564,7 +912,12 @@ bool clip_segment_v3_plane_n(const float p1[3],
bool point_in_slice_seg(float p[3], float l1[3], float l2[3]);
-/****************************** Interpolation ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interpolation
+ * \{ */
+
void interp_weights_tri_v3(
float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3]);
void interp_weights_quad_v3(float w[4],
@@ -576,6 +929,7 @@ void interp_weights_quad_v3(float w[4],
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
+/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
@@ -584,8 +938,17 @@ void interp_cubic_v3(float x[3],
const float v2[3],
const float t);
+/**
+ * Given an array with some invalid values this function interpolates valid values
+ * replacing the invalid ones.
+ */
int interp_sparse_array(float *array, const int list_size, const float skipval);
+/**
+ * Given 2 triangles in 3D space, and a point in relation to the first triangle.
+ * calculate the location of a point in relation to the second triangle.
+ * Useful for finding relative positions with geometry.
+ */
void transform_point_by_tri_v3(float pt_tar[3],
float const pt_src[3],
const float tri_tar_p1[3],
@@ -594,6 +957,10 @@ void transform_point_by_tri_v3(float pt_tar[3],
const float tri_src_p1[3],
const float tri_src_p2[3],
const float tri_src_p3[3]);
+/**
+ * Simply re-interpolates,
+ * assumes p_src is between \a l_src_p1-l_src_p2
+ */
void transform_point_by_seg_v3(float p_dst[3],
const float p_src[3],
const float l_dst_p1[3],
@@ -601,12 +968,32 @@ void transform_point_by_seg_v3(float p_dst[3],
const float l_src_p1[3],
const float l_src_p2[3]);
+/**
+ * \note Using #cross_tri_v2 means locations outside the triangle are correctly weighted.
+ *
+ * \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
+ * although it has double precision and is used for texture baking, so keep both.
+ */
void barycentric_weights_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * A version of #barycentric_weights_v2 that doesn't allow negative weights.
+ * Useful when negative values cause problems and points are only
+ * ever slightly outside of the triangle.
+ */
void barycentric_weights_v2_clamped(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * still use 2D X,Y space but this works for verts transformed by a perspective matrix,
+ * using their 4th component as a weight
+ */
void barycentric_weights_v2_persp(
const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3]);
+/**
+ * same as #barycentric_weights_v2 but works with a quad,
+ * NOTE: untested for values outside the quad's bounds
+ * this is #interp_weights_poly_v2 expanded for quads only
+ */
void barycentric_weights_v2_quad(const float v1[2],
const float v2[2],
const float v3[2],
@@ -614,20 +1001,47 @@ void barycentric_weights_v2_quad(const float v1[2],
const float co[2],
float w[4]);
+/**
+ * \return false for degenerated triangles.
+ */
bool barycentric_coords_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]);
+/**
+ * \return
+ * - 0 if the point is outside of triangle.
+ * - 1 if the point is inside triangle.
+ * - 2 if it's on the edge.
+ */
int barycentric_inside_triangle_v2(const float w[3]);
+/**
+ * Barycentric reverse
+ *
+ * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
+ *
+ * \note same basic result as #barycentric_weights_v2, see its comment for details.
+ */
void resolve_tri_uv_v2(
float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2]);
+/**
+ * Barycentric reverse 3d
+ *
+ * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
+ */
void resolve_tri_uv_v3(
float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3]);
+/**
+ * Bilinear reverse.
+ */
void resolve_quad_uv_v2(float r_uv[2],
const float st[2],
const float st0[2],
const float st1[2],
const float st2[2],
const float st3[2]);
+/**
+ * Bilinear reverse with derivatives.
+ */
void resolve_quad_uv_v2_deriv(float r_uv[2],
float r_deriv[2][2],
const float st[2],
@@ -635,22 +1049,35 @@ void resolve_quad_uv_v2_deriv(float r_uv[2],
const float st1[2],
const float st2[2],
const float st3[2]);
+/**
+ * A version of resolve_quad_uv_v2 that only calculates the 'u'.
+ */
float resolve_quad_u_v2(const float st[2],
const float st0[2],
const float st1[2],
const float st2[2],
const float st3[2]);
-/* use to find the point of a UV on a face */
+/**
+ * Use to find the point of a UV on a face.
+ * Reverse of `resolve_*` functions.
+ */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3]);
void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3]);
-/***************************** View & Projection *****************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View & Projection
+ * \{ */
void lookat_m4(
float mat[4][4], float vx, float vy, float vz, float px, float py, float pz, float twist);
void polarview_m4(float mat[4][4], float dist, float azimuth, float incidence, float twist);
+/**
+ * Matches `glFrustum` result.
+ */
void perspective_m4(float mat[4][4],
const float left,
const float right,
@@ -665,6 +1092,9 @@ void perspective_m4_fov(float mat[4][4],
const float angle_down,
const float nearClip,
const float farClip);
+/**
+ * Matches `glOrtho` result.
+ */
void orthographic_m4(float mat[4][4],
const float left,
const float right,
@@ -672,8 +1102,18 @@ void orthographic_m4(float mat[4][4],
const float top,
const float nearClip,
const float farClip);
+/**
+ * Translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
+ * (used to jitter the view).
+ */
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y);
+/**
+ * Frustum planes extraction from a projection matrix
+ * (homogeneous 4d vector representations of planes).
+ *
+ * plane parameters can be NULL if you do not need them.
+ */
void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
@@ -697,6 +1137,14 @@ void projmat_dimensions_db(const float winmat[4][4],
double *r_near,
double *r_far);
+/**
+ * Creates a projection matrix for a small region of the viewport.
+ *
+ * \param projmat: Projection Matrix.
+ * \param win_size: Viewport Size.
+ * \param x_min, x_max, y_min, y_max: Coordinates of the subregion.
+ * \return r_projmat: Resulting Projection Matrix.
+ */
void projmat_from_subregion(const float projmat[4][4],
const int win_size[2],
const int x_min,
@@ -708,7 +1156,11 @@ void projmat_from_subregion(const float projmat[4][4],
int box_clip_bounds_m4(float boundbox[2][3], const float bounds[4], float winmat[4][4]);
void box_minmax_bounds_m4(float min[3], float max[3], float boundbox[2][3], float mat[4][4]);
-/********************************** Mapping **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mapping
+ * \{ */
void map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z);
void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z);
@@ -718,7 +1170,11 @@ void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2],
const float axis[3],
const float angle);
-/********************************** Normals **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Normals
+ * \{ */
void accumulate_vertex_normals_tri_v3(float n1[3],
float n2[3],
@@ -738,13 +1194,21 @@ void accumulate_vertex_normals_v3(float n1[3],
const float co3[3],
const float co4[3]);
+/**
+ * Add weighted face normal component into normals of the face vertices.
+ * Caller must pass pre-allocated vdiffs of nverts length.
+ */
void accumulate_vertex_normals_poly_v3(float **vertnos,
const float polyno[3],
const float **vertcos,
float vdiffs[][3],
const int nverts);
-/********************************* Tangents **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tangents
+ * \{ */
void tangent_from_uv_v3(const float uv1[2],
const float uv2[2],
@@ -755,8 +1219,31 @@ void tangent_from_uv_v3(const float uv1[2],
const float n[3],
float r_tang[3]);
-/******************************** Vector Clouds ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vector Clouds
+ * \{ */
+/**
+ * Input:
+ *
+ * \param list_size: 4 lists as pointer to array[list_size]
+ * \param pos: current pos array of 'new' positions
+ * \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights)
+ * \param rpos: Reference rpos array of 'old' positions
+ * \param rweight: Reference rweight array of 'old'weights
+ * (may be NULL pointer if you have no weights).
+ *
+ * Output:
+ *
+ * \param lloc: Center of mass pos.
+ * \param rloc: Center of mass rpos.
+ * \param lrot: Rotation matrix.
+ * \param lscale: Scale matrix.
+ *
+ * pointers may be NULL if not needed
+ */
void vcloud_estimate_transform_v3(const int list_size,
const float (*pos)[3],
const float *weight,
@@ -767,12 +1254,16 @@ void vcloud_estimate_transform_v3(const int list_size,
float lrot[3][3],
float lscale[3][3]);
-/****************************** Spherical Harmonics *************************/
+/** \} */
-/* Uses 2nd order SH => 9 coefficients, stored in this order:
- * 0 = (0, 0),
- * 1 = (1, -1), 2 = (1, 0), 3 = (1, 1),
- * 4 = (2, -2), 5 = (2, -1), 6 = (2, 0), 7 = (2, 1), 8 = (2, 2) */
+/* -------------------------------------------------------------------- */
+/** \name Spherical Harmonics
+ *
+ * Uses 2nd order SH => 9 coefficients, stored in this order:
+ * - 0 = `(0, 0)`
+ * - 1 = `(1, -1), 2 = (1, 0), 3 = (1, 1)`
+ * - 4 = `(2, -2), 5 = (2, -1), 6 = (2, 0), 7 = (2, 1), 8 = (2, 2)`
+ * \{ */
MINLINE void zero_sh(float r[9]);
MINLINE void copy_sh_sh(float r[9], const float a[9]);
@@ -785,7 +1276,11 @@ MINLINE float diffuse_shv3(const float r[9], const float v[3]);
MINLINE void vec_fac_to_sh(float r[9], const float v[3], const float f);
MINLINE void madd_sh_shfl(float r[9], const float sh[9], const float f);
-/********************************* Form Factor *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Form Factor
+ * \{ */
float form_factor_quad(const float p[3],
const float n[3],
@@ -805,37 +1300,117 @@ bool form_factor_visible_quad(const float p[3],
float form_factor_hemi_poly(
float p[3], float n[3], float v1[3], float v2[3], float v3[3], float v4[3]);
+/**
+ * Same as axis_dominant_v3_to_m3, but flips the normal
+ */
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3]);
+/**
+ * \brief Normal to x,y matrix
+ *
+ * Creates a 3x3 matrix from a normal.
+ * This matrix can be applied to vectors so their 'z' axis runs along \a normal.
+ * In practice it means you can use x,y as 2d coords. \see
+ *
+ * \param r_mat: The matrix to return.
+ * \param normal: A unit length vector.
+ */
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]);
+/**
+ * Get the 2 dominant axis values, 0==X, 1==Y, 2==Z.
+ */
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3]);
+/**
+ * Same as #axis_dominant_v3 but return the max value.
+ */
MINLINE float axis_dominant_v3_max(int *r_axis_a,
int *r_axis_b,
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Get the single dominant axis value, 0==X, 1==Y, 2==Z.
+ */
MINLINE int axis_dominant_v3_single(const float vec[3]);
+/**
+ * The dominant axis of an orthogonal vector.
+ */
MINLINE int axis_dominant_v3_ortho_single(const float vec[3]);
MINLINE int max_axis_v3(const float vec[3]);
MINLINE int min_axis_v3(const float vec[3]);
+/**
+ * Simple function to either:
+ * - Calculate how many triangles needed from the total number of polygons + loops.
+ * - Calculate the first triangle index from the polygon index & that polygons loop-start.
+ *
+ * \param poly_count: The number of polygons or polygon-index
+ * (3+ sided faces, 1-2 sided give incorrect results).
+ * \param corner_count: The number of corners (also called loop-index).
+ */
MINLINE int poly_to_tri_count(const int poly_count, const int corner_count);
+/**
+ * Useful to calculate an even width shell, by taking the angle between 2 planes.
+ * The return value is a scale on the offset.
+ * no angle between planes is 1.0, as the angle between the 2 planes approaches 180d
+ * the distance gets very high, 180d would be inf, but this case isn't valid.
+ */
MINLINE float shell_angle_to_dist(const float angle);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`.
+ */
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b))`.
+ */
MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`.
+ */
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3]);
+/**
+ * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`.
+ */
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2]);
-/********************************* Cubic (Bezier) *******************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Cubic (Bezier)
+ * \{ */
+
+/**
+ * Return the value which the distance between points will need to be scaled by,
+ * to define a handle, given both points are on a perfect circle.
+ *
+ * Use when we want a bezier curve to match a circle as closely as possible.
+ *
+ * \note the return value will need to be divided by 0.75 for correct results.
+ */
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]);
-/********************************** Geodesics *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geodesics
+ * \{ */
+/**
+ * Utility for computing approximate geodesic distances on triangle meshes.
+ *
+ * Given triangle with vertex coordinates v0, v1, v2, and known geodesic distances
+ * dist1 and dist2 at v1 and v2, estimate a geodesic distance at vertex v0.
+ *
+ * From "Dart Throwing on Surfaces", EGSR 2009. Section 7, Geodesic Dart Throwing.
+ */
float geodesic_distance_propagate_across_triangle(
const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
#if BLI_MATH_DO_INLINE
# include "intern/math_geom_inline.c"
@@ -845,6 +1420,8 @@ float geodesic_distance_propagate_across_triangle(
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h
index cc025b469e3..7179de12066 100644
--- a/source/blender/blenlib/BLI_math_interp.h
+++ b/source/blender/blenlib/BLI_math_interp.h
@@ -77,7 +77,8 @@ typedef void (*ewa_filter_read_pixel_cb)(void *userdata, int x, int y, float res
void BLI_ewa_imp2radangle(
float A, float B, float C, float F, float *a, float *b, float *th, float *ecc);
-/* TODO(sergey): Consider making this function inlined, so the pixel read callback
+/**
+ * TODO(sergey): Consider making this function inlined, so the pixel read callback
* could also be inlined in order to avoid per-pixel function calls.
*/
void BLI_ewa_filter(const int width,
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 241acebffa3..3d8fe6f564a 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -32,7 +32,9 @@
extern "C" {
#endif
-/********************************* Init **************************************/
+/* -------------------------------------------------------------------- */
+/** \name Init
+ * \{ */
void zero_m2(float m[2][2]);
void zero_m3(float m[3][3]);
@@ -66,7 +68,11 @@ void swap_m4m4(float m1[4][4], float m2[4][4]);
/* Build index shuffle matrix */
void shuffle_m4(float R[4][4], const int index[4]);
-/******************************** Arithmetic *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Arithmetic
+ * \{ */
void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
@@ -81,14 +87,21 @@ void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4]);
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3]);
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
+/**
+ * `R = A * B`, ignore the elements on the 4th row/column of A.
+ */
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4]);
+/**
+ * `R = A * B`, ignore the elements on the 4th row/column of B.
+ */
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3]);
void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4]);
-/* special matrix multiplies
- * uniq: R <-- AB, R is neither A nor B
- * pre: R <-- AR
- * post: R <-- RB
+/**
+ * Special matrix multiplies
+ * - uniq: `R <-- AB`, R is neither A nor B
+ * - pre: `R <-- AR`
+ * - post: `R <-- RB`.
*/
void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m3_m3_pre(float R[3][3], const float A[3][3]);
@@ -192,6 +205,7 @@ void mul_v4_m4v3_db(double r[4], const double mat[4][4], const double vec[3]);
void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]);
void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]);
void mul_m2_v2(const float M[2][2], float v[2]);
+/** Same as #mul_m4_v3() but doesn't apply translation component. */
void mul_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]);
void mul_v3_mat3_m4v3_db(double r[3], const double M[4][4], const double v[3]);
@@ -211,7 +225,18 @@ void mul_transposed_m3_v3(const float M[3][3], float r[3]);
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_m3_v3_double(const float M[3][3], double r[3]);
+/**
+ * Combines transformations, handling scale separately in a manner equivalent
+ * to the Aligned Inherit Scale mode, in order to avoid creating shear.
+ * If A scale is uniform, the result is equivalent to ordinary multiplication.
+ *
+ * NOTE: this effectively takes output location from simple multiplication,
+ * and uses mul_m4_m4m4_split_channels for rotation and scale.
+ */
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]);
+/**
+ * Separately combines location, rotation and scale of the input matrices.
+ */
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4]);
void mul_m3_fl(float R[3][3], float f);
@@ -229,6 +254,16 @@ bool invert_m3(float R[3][3]);
bool invert_m3_m3(float R[3][3], const float A[3][3]);
bool invert_m4(float R[4][4]);
bool invert_m4_m4(float R[4][4], const float A[4][4]);
+/**
+ * Computes the inverse of mat and puts it in inverse.
+ * Uses Gaussian Elimination with partial (maximal column) pivoting.
+ * \return true on success (i.e. can always find a pivot) and false on failure.
+ * Mark Segal - 1992.
+ *
+ * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
+ * for non-invertible scale matrices, finding a partial solution can
+ * be useful to have a valid local transform center, see T57767.
+ */
bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
/* double arithmetic (mixed float/double) */
@@ -239,10 +274,15 @@ void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]);
void mul_m3_v3_db(const double M[3][3], double r[3]);
-/****************************** Linear Algebra *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Linear Algebra
+ * \{ */
void transpose_m3(float R[3][3]);
void transpose_m3_m3(float R[3][3], const float M[3][3]);
+/* seems obscure but in-fact a common operation */
void transpose_m3_m4(float R[3][3], const float M[4][4]);
void transpose_m4(float R[4][4]);
void transpose_m4_m4(float R[4][4], const float M[4][4]);
@@ -262,10 +302,36 @@ void normalize_m4(float R[4][4]) ATTR_NONNULL();
void normalize_m4_m4_ex(float R[4][4], const float M[4][4], float r_scale[3]) ATTR_NONNULL();
void normalize_m4_m4(float R[4][4], const float M[4][4]) ATTR_NONNULL();
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ */
void orthogonalize_m3(float R[3][3], int axis);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ */
void orthogonalize_m4(float R[4][4], int axis);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix,
+ * in a way that is symmetric and stable to variations in the input, and
+ * preserving the value of the determinant, i.e. the overall volume change.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ * \param normalize: Normalize the matrix instead of preserving volume.
+ */
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize);
bool orthogonalize_m3_zero_axes(float R[3][3], const float unit_length);
@@ -281,8 +347,8 @@ bool is_uniform_scaled_m4(const float m[4][4]);
/* NOTE: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix!
* Nowadays 'adjoint' usually refers to the conjugate transpose,
- * which for real-valued matrices is simply the transpose.
- */
+ * which for real-valued matrices is simply the transpose. */
+
void adjoint_m2_m2(float R[2][2], const float M[2][2]);
void adjoint_m3_m3(float R[3][3], const float M[3][3]);
void adjoint_m4_m4(float R[4][4], const float M[4][4]);
@@ -297,6 +363,13 @@ float determinant_m4(const float m[4][4]);
#define PSEUDOINVERSE_EPSILON 1e-8f
+/**
+ * Compute the Single Value Decomposition of an arbitrary matrix A
+ * That is compute the 3 matrices U,W,V with U column orthogonal (m,n)
+ * ,W a diagonal matrix and V an orthogonal square matrix `s.t.A = U.W.Vt`.
+ * From this decomposition it is trivial to compute the (pseudo-inverse)
+ * of `A` as `Ainv = V.Winv.transpose(U)`.
+ */
void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]);
void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon);
void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon);
@@ -306,18 +379,39 @@ bool has_zero_axis_m4(const float matrix[4][4]);
void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]);
void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]);
+/**
+ * A safe version of invert that uses valid axes, calculating the zero'd axis
+ * based on the non-zero ones.
+ *
+ * This works well for transformation matrices, when a single axis is zerod.
+ */
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]);
-/****************************** Transformations ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transformations
+ * \{ */
void scale_m3_fl(float R[3][3], float scale);
void scale_m4_fl(float R[4][4], float scale);
+/**
+ * This computes the overall volume scale factor of a transformation matrix.
+ * For an orthogonal matrix, it is the product of all three scale values.
+ * Returns a negative value if the transform is flipped by negative scale.
+ */
float mat3_to_volume_scale(const float M[3][3]);
float mat4_to_volume_scale(const float M[4][4]);
+/**
+ * This gets the average scale of a matrix, only use when your scaling
+ * data that has no idea of scale axis, examples are bone-envelope-radius
+ * and curve radius.
+ */
float mat3_to_scale(const float M[3][3]);
float mat4_to_scale(const float M[4][4]);
+/** Return 2D scale (in XY plane) of given mat4. */
float mat4_to_xy_scale(const float M[4][4]);
void size_to_mat3(float R[3][3], const float size[3]);
@@ -326,11 +420,31 @@ void size_to_mat4(float R[4][4], const float size[3]);
void mat3_to_size(float size[3], const float M[3][3]);
void mat4_to_size(float size[3], const float M[4][4]);
+/**
+ * Extract scale factors from the matrix, with correction to ensure
+ * exact volume in case of a sheared matrix.
+ */
void mat4_to_size_fix_shear(float size[3], const float M[4][4]);
void translate_m4(float mat[4][4], float tx, float ty, float tz);
+/**
+ * Rotate a matrix in-place.
+ *
+ * \note To create a new rotation matrix see:
+ * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
+ * (axis & angle args are compatible).
+ */
void rotate_m4(float mat[4][4], const char axis, const float angle);
+/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3]);
+/**
+ * Scale or rotate around a pivot point,
+ * a convenience function to avoid having to do inline.
+ *
+ * Since its common to make a scale/rotation matrix that pivots around an arbitrary point.
+ *
+ * Typical use case is to make 3x3 matrix, copy to 4x4, then pass to this function.
+ */
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat4_to_rot(float rot[3][3], const float wmat[4][4]);
@@ -341,16 +455,34 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat
void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_rot_size_to_mat4(float R[4][4],
const float loc[3],
const float rot[3][3],
const float size[3]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ *
+ * TODO: need to have a version that allows for rotation order.
+ */
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
const float size[3]);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_eulO_size_to_mat4(
float R[4][4], const float loc[3], const float eul[3], const float size[3], const short order);
+/**
+ * Make a 4x4 matrix out of 3 transform components.
+ * Matrices are made in the order: `scale * rot * loc`
+ */
void loc_quat_size_to_mat4(float R[4][4],
const float loc[3],
const float quat[4],
@@ -370,7 +502,32 @@ void blend_m4_m4m4(float out[4][4],
const float src[4][4],
const float srcweight);
+/**
+ * A polar-decomposition-based interpolation between matrix A and matrix B.
+ *
+ * \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
+ * (it typically remains below 2 usec on an average i74700,
+ * while #blend_m3_m3m3 remains below 0.4 usec).
+ * However, it gives expected results even with non-uniformly scaled matrices,
+ * see T46418 for an example.
+ *
+ * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
+ *
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \param B: Input matrix which is totally effective with `t = 1.0`.
+ * \param t: Interpolation factor.
+ */
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t);
+/**
+ * Complete transform matrix interpolation,
+ * based on polar-decomposition-based interpolation from #interp_m3_m3m3.
+ *
+ * \param R: Resulting interpolated matrix.
+ * \param A: Input matrix which is totally effective with `t = 0.0`.
+ * \param B: Input matrix which is totally effective with `t = 1.0`.
+ * \param t: Interpolation factor.
+ */
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t);
bool is_negative_m3(const float mat[3][3]);
@@ -382,16 +539,57 @@ bool is_zero_m4(const float mat[4][4]);
bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]);
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]);
-/* SpaceTransform helper */
+/**
+ * #SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces
+ * (where conversion can be represented by a matrix multiplication).
+ *
+ * A #SpaceTransform is initialized using:
+ * - #BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2)
+ *
+ * After that the following calls can be used:
+ * - Converts a coordinate in ob1 space to the corresponding ob2 space:
+ * #BLI_space_transform_apply(&data, co);
+ * - Converts a coordinate in ob2 space to the corresponding ob1 space:
+ * #BLI_space_transform_invert(&data, co);
+ *
+ * Same concept as #BLI_space_transform_apply and #BLI_space_transform_invert,
+ * but no is normalized after conversion (and not translated at all!):
+ * - #BLI_space_transform_apply_normal(&data, no);
+ * - #BLI_space_transform_invert_normal(&data, no);
+ */
typedef struct SpaceTransform {
float local2target[4][4];
float target2local[4][4];
} SpaceTransform;
+/**
+ * Global-invariant transform.
+ *
+ * This defines a matrix transforming a point in local space to a point in target space
+ * such that its global coordinates remain unchanged.
+ *
+ * In other words, if we have a global point P with local coordinates (x, y, z)
+ * and global coordinates (X, Y, Z),
+ * this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z)
+ * where (x', y', z') are the coordinates of P' in target space
+ * such that it keeps (X, Y, Z) coordinates in global space.
+ */
void BLI_space_transform_from_matrices(struct SpaceTransform *data,
const float local[4][4],
const float target[4][4]);
+/**
+ * Local-invariant transform.
+ *
+ * This defines a matrix transforming a point in global space
+ * such that its local coordinates (from local space to target space) remain unchanged.
+ *
+ * In other words, if we have a local point p with local coordinates (x, y, z)
+ * and global coordinates (X, Y, Z),
+ * this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z)
+ * where (X', Y', Z') are the coordinates of p' in global space
+ * such that it keeps (x, y, z) coordinates in target space.
+ */
void BLI_space_transform_global_from_matrices(struct SpaceTransform *data,
const float local[4][4],
const float target[4][4]);
@@ -403,7 +601,11 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
#define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \
BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat)
-/*********************************** Other ***********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
void print_m3(const char *str, const float M[3][3]);
void print_m4(const char *str, const float M[4][4]);
@@ -411,6 +613,8 @@ void print_m4(const char *str, const float M[4][4]);
#define print_m3_id(M) print_m3(STRINGIFY(M), M)
#define print_m4_id(M) print_m4(STRINGIFY(M), M)
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 461b5a60c9d..5e72d502262 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -32,31 +32,72 @@
extern "C" {
#endif
+/* -------------------------------------------------------------------- */
+/** \name Conversion Defines
+ * \{ */
+
#define RAD2DEG(_rad) ((_rad) * (180.0 / M_PI))
#define DEG2RAD(_deg) ((_deg) * (M_PI / 180.0))
#define RAD2DEGF(_rad) ((_rad) * (float)(180.0 / M_PI))
#define DEG2RADF(_deg) ((_deg) * (float)(M_PI / 180.0))
-/******************************** Quaternions ********************************/
-/* stored in (w, x, y, z) order */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quaternions
+ * Stored in (w, x, y, z) order.
+ * \{ */
+
+/* Initialize */
+
+/* Convenience, avoids setting Y axis everywhere. */
-/* init */
void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]);
/* arithmetic */
void mul_qt_qtqt(float q[4], const float a[4], const float b[4]);
+/**
+ * \note
+ * Assumes a unit quaternion?
+ *
+ * in fact not, but you may want to use a unit quaternion read on...
+ *
+ * Shortcut for 'q v q*' when \a v is actually a quaternion.
+ * This removes the need for converting a vector to a quaternion,
+ * calculating q's conjugate and converting back to a vector.
+ * It also happens to be faster (17+,24* vs * 24+,32*).
+ * If \a q is not a unit quaternion, then \a v will be both rotated by
+ * the same amount as if q was a unit quaternion, and scaled by the square of
+ * the length of q.
+ *
+ * For people used to python mathutils, its like:
+ * def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
+ *
+ * \note Multiplying by 3x3 matrix is ~25% faster.
+ */
void mul_qt_v3(const float q[4], float r[3]);
+/**
+ * Simple multiply.
+ */
void mul_qt_fl(float q[4], const float f);
+/**
+ * Raise a unit quaternion to the specified power.
+ */
void pow_qt_fl_normalized(float q[4], const float f);
void sub_qt_qtqt(float q[4], const float a[4], const float b[4]);
void invert_qt(float q[4]);
void invert_qt_qt(float q1[4], const float q2[4]);
+/**
+ * This is just conjugate_qt for cases we know \a q is unit-length.
+ * we could use #conjugate_qt directly, but use this function to show intent,
+ * and assert if its ever becomes non-unit-length.
+ */
void invert_qt_normalized(float q[4]);
void invert_qt_qt_normalized(float q1[4], const float q2[4]);
void conjugate_qt(float q[4]);
@@ -69,7 +110,15 @@ float normalize_qt_qt(float r[4], const float q[4]);
bool is_zero_qt(const float q[4]);
/* interpolation */
-void interp_dot_slerp(const float t, const float cosom, float w[2]);
+/**
+ * Generic function for implementing slerp
+ * (quaternions and spherical vector coords).
+ *
+ * \param t: factor in [0..1]
+ * \param cosom: dot product from normalized vectors/quats.
+ * \param r_w: calculated weights.
+ */
+void interp_dot_slerp(const float t, const float cosom, float r_w[2]);
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
@@ -77,24 +126,51 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]);
+/**
+ * Apply the rotation of \a a to \a q keeping the values compatible with \a old.
+ * Avoid axis flipping for animated f-curves for eg.
+ */
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4]);
void mat3_normalized_to_quat(float q[4], const float mat[3][3]);
void mat4_normalized_to_quat(float q[4], const float mat[4][4]);
void mat3_to_quat(float q[4], const float mat[3][3]);
void mat4_to_quat(float q[4], const float mat[4][4]);
+/**
+ * Same as tri_to_quat() but takes pre-computed normal from the triangle
+ * used for ngons when we know their normal.
+ */
void tri_to_quat_ex(float quat[4],
const float v1[3],
const float v2[3],
const float v3[3],
const float no_orig[3]);
+/**
+ * \return the length of the normal, use to test for degenerate triangles.
+ */
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3]);
void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag);
-/* NOTE: v1 and v2 must be normalized. */
+/**
+ * Calculate a rotation matrix from 2 normalized vectors.
+ * \note `v1` and `v2` must be normalized.
+ */
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3]);
+/**
+ * \note Expects vectors to be normalized.
+ */
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3]);
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4]);
+/**
+ * Decompose a quaternion into a swing rotation (quaternion with the selected
+ * axis component locked at zero), followed by a twist rotation around the axis.
+ *
+ * \param q: input quaternion.
+ * \param axis: twist axis in [0,1,2]
+ * \param r_swing: if not NULL, receives the swing quaternion.
+ * \param r_twist: if not NULL, receives the twist quaternion.
+ * \returns twist angle.
+ */
float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]);
float angle_normalized_qt(const float q[4]);
@@ -107,7 +183,9 @@ float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_signed_qt(const float q[4]);
float angle_signed_qtqt(const float q1[4], const float q2[4]);
-/* TODO: don't what this is, but it's not the same as mat3_to_quat */
+/**
+ * TODO: don't what this is, but it's not the same as #mat3_to_quat.
+ */
void mat3_to_quat_is_ok(float q[4], const float mat[3][3]);
/* other */
@@ -115,61 +193,120 @@ void print_qt(const char *str, const float q[4]);
#define print_qt_id(q) print_qt(STRINGIFY(q), q)
-/******************************** Axis Angle *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Axis Angle
+ * \{ */
/* conversion */
void axis_angle_normalized_to_quat(float r[4], const float axis[3], const float angle);
void axis_angle_to_quat(float r[4], const float axis[3], const float angle);
+/**
+ * Axis angle to 3x3 matrix - safer version (normalization of axis performed).
+ */
void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle);
+/**
+ * axis angle to 3x3 matrix
+ *
+ * This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
+ *
+ * \param axis: rotation axis (must be normalized).
+ * \param angle_sin: sin(angle)
+ * \param angle_cos: cos(angle)
+ */
void axis_angle_normalized_to_mat3_ex(float mat[3][3],
const float axis[3],
const float angle_sin,
const float angle_cos);
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const float angle);
+/**
+ * Axis angle to 4x4 matrix - safer version (normalization of axis performed).
+ */
void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle);
+/**
+ * 3x3 matrix to axis angle.
+ */
void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
+/**
+ * 4x4 matrix to axis angle.
+ */
void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
void mat3_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
+/**
+ * 4x4 matrix to axis angle.
+ */
void mat4_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
+/**
+ * Quaternions to Axis Angle.
+ */
void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
void angle_to_mat2(float R[2][2], const float angle);
+/**
+ * Create a 3x3 rotation matrix from a single axis.
+ */
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
+/**
+ * Create a 4x4 rotation matrix from a single axis.
+ */
void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle);
void axis_angle_to_quat_single(float q[4], const char axis, const float angle);
-/****************************** Exponential Map ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Exponential Map
+ * \{ */
+
void quat_to_expmap(float expmap[3], const float q[4]);
void quat_normalized_to_expmap(float expmap[3], const float q[4]);
void expmap_to_quat(float r[4], const float expmap[3]);
-/******************************** XYZ Eulers *********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XYZ Eulers
+ * \{ */
+/* XYZ order. */
void eul_to_quat(float quat[4], const float eul[3]);
+/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3]);
+/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3]);
+/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3]);
+/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float mat[4][4]);
void mat3_to_eul(float eul[3], const float mat[3][3]);
void mat4_to_eul(float eul[3], const float mat[4][4]);
+/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4]);
+/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
+/* order independent! */
void compatible_eul(float eul[3], const float old[3]);
+/* XYZ order */
void rotate_eul(float eul[3], const char axis, const float angle);
void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
-/************************** Arbitrary Order Eulers ***************************/
+/** \} */
-/* warning: must match the eRotationModes in DNA_action_types.h
+/* -------------------------------------------------------------------- */
+/** \name Arbitrary Order Eulers
+ * \{ */
+
+/* WARNING: must match the #eRotationModes in `DNA_action_types.h`
* order matters - types are saved to file. */
typedef enum eEulerRotationOrders {
@@ -183,19 +320,48 @@ typedef enum eEulerRotationOrders {
/* There are 6 more entries with duplicate entries included. */
} eEulerRotationOrders;
+/**
+ * Construct quaternion from Euler angles (in radians).
+ */
void eulO_to_quat(float quat[4], const float eul[3], const short order);
+/**
+ * Construct 3x3 matrix from Euler angles (in radians).
+ */
void eulO_to_mat3(float mat[3][3], const float eul[3], const short order);
+/**
+ * Construct 4x4 matrix from Euler angles (in radians).
+ */
void eulO_to_mat4(float mat[4][4], const float eul[3], const short order);
+/**
+ * Euler Rotation to Axis Angle.
+ */
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order);
+/**
+ * The matrix is written to as 3 axis vectors.
+ */
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order);
+/**
+ * Convert 3x3 matrix to Euler angles (in radians).
+ */
void mat3_normalized_to_eulO(float eul[3], const short order, const float mat[3][3]);
+/**
+ * Convert 4x4 matrix to Euler angles (in radians).
+ */
void mat4_normalized_to_eulO(float eul[3], const short order, const float mat[4][4]);
void mat3_to_eulO(float eul[3], const short order, const float mat[3][3]);
void mat4_to_eulO(float eul[3], const short order, const float mat[4][4]);
+/**
+ * Convert quaternion to Euler angles (in radians).
+ */
void quat_to_eulO(float eul[3], const short order, const float quat[4]);
+/**
+ * Axis Angle to Euler Rotation.
+ */
void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle);
+/* Uses 2 methods to retrieve eulers, and picks the closest. */
+
void mat3_normalized_to_compatible_eulO(float eul[3],
const float old[3],
const short order,
@@ -219,7 +385,11 @@ void quat_to_compatible_eulO(float eul[3],
void rotate_eulO(float eul[3], const short order, char axis, float angle);
-/******************************* Dual Quaternions ****************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dual Quaternions
+ * \{ */
void copy_dq_dq(DualQuat *r, const DualQuat *dq);
void normalize_dq(DualQuat *dq, float totw);
@@ -229,21 +399,39 @@ void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq);
void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4]);
void dquat_to_mat4(float R[4][4], const DualQuat *dq);
+/**
+ * Axis matches #eTrackToAxis_Modes.
+ */
void quat_apply_track(float quat[4], short axis, short upflag);
void vec_apply_track(float vec[3], short axis);
+/**
+ * Lens/angle conversion (radians).
+ */
float focallength_to_fov(float focal_length, float sensor);
float fov_to_focallength(float fov, float sensor);
float angle_wrap_rad(float angle);
float angle_wrap_deg(float angle);
+/**
+ * Returns an angle compatible with angle_compat.
+ */
float angle_compat_rad(float angle, float angle_compat);
+/**
+ * Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
+ * where the first 2 are a source and the second 2 are the target.
+ */
bool mat3_from_axis_conversion(
int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3]);
+/**
+ * Use when the second axis can be guessed.
+ */
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3]);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h
index 39a79efc7e2..32d4577899c 100644
--- a/source/blender/blenlib/BLI_math_solvers.h
+++ b/source/blender/blenlib/BLI_math_solvers.h
@@ -35,22 +35,61 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
-/********************************** Eigen Solvers *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Eigen Solvers
+ * \{ */
+/**
+ * \brief Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
+ *
+ * \param m3: the 3D symmetric matrix.
+ * \return r_eigen_values the computed eigen values (NULL if not needed).
+ * \return r_eigen_vectors the computed eigen vectors (NULL if not needed).
+ */
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
float r_eigen_values[3],
float r_eigen_vectors[3][3]);
+/**
+ * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
+ *
+ * \param m3: the matrix to decompose.
+ * \return r_U the computed left singular vector of \a m3 (NULL if not needed).
+ * \return r_S the computed singular values of \a m3 (NULL if not needed).
+ * \return r_V the computed right singular vector of \a m3 (NULL if not needed).
+ */
void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3]);
-/***************************** Simple Solvers ************************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simple Solvers
+ * \{ */
+
+/**
+ * \brief Solve a tridiagonal system of equations:
+ *
+ * a[i] * r_x[i-1] + b[i] * r_x[i] + c[i] * r_x[i+1] = d[i]
+ *
+ * Ignores a[0] and c[count-1]. Uses the Thomas algorithm, e.g. see wiki.
+ *
+ * \param r_x: output vector, may be shared with any of the input ones
+ * \return true if success
+ */
bool BLI_tridiagonal_solve(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
+/**
+ * \brief Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
+ *
+ * \param r_x: output vector, may be shared with any of the input ones
+ * \return true if success
+ */
bool BLI_tridiagonal_solve_cyclic(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
-/* Generic 3 variable Newton's method solver. */
+/**
+ * Generic 3 variable Newton's method solver.
+ */
typedef void (*Newton3D_DeltaFunc)(void *userdata, const float x[3], float r_delta[3]);
typedef void (*Newton3D_JacobianFunc)(void *userdata, const float x[3], float r_jacobian[3][3]);
typedef bool (*Newton3D_CorrectionFunc)(void *userdata,
@@ -58,6 +97,21 @@ typedef bool (*Newton3D_CorrectionFunc)(void *userdata,
float step[3],
float x_next[3]);
+/**
+ * \brief Solve a generic f(x) = 0 equation using Newton's method.
+ *
+ * \param func_delta: Callback computing the value of f(x).
+ * \param func_jacobian: Callback computing the Jacobian matrix of the function at x.
+ * \param func_correction: Callback for forcing the search into an arbitrary custom domain.
+ * May be NULL.
+ * \param userdata: Data for the callbacks.
+ * \param epsilon: Desired precision.
+ * \param max_iterations: Limit on the iterations.
+ * \param trace: Enables logging to console.
+ * \param x_init: Initial solution vector.
+ * \param result: Final result.
+ * \return true if success
+ */
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
Newton3D_JacobianFunc func_jacobian,
Newton3D_CorrectionFunc func_correction,
@@ -72,6 +126,8 @@ bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_statistics.h b/source/blender/blenlib/BLI_math_statistics.h
index 6e818f5c8df..e4524b49f3f 100644
--- a/source/blender/blenlib/BLI_math_statistics.h
+++ b/source/blender/blenlib/BLI_math_statistics.h
@@ -35,14 +35,36 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
-/********************************** Covariance Matrices *********************************/
+/* -------------------------------------------------------------------- */
+/** \name Covariance Matrices
+ * \{ */
+/**
+ * \brief Compute the covariance matrix of given set of nD coordinates.
+ *
+ * \param n: the dimension of the vectors (and hence, of the covariance matrix to compute).
+ * \param cos_vn: the nD points to compute covariance from.
+ * \param nbr_cos_vn: the number of nD coordinates in cos_vn.
+ * \param center: the center (or mean point) of cos_vn. If NULL,
+ * it is assumed cos_vn is already centered.
+ * \param use_sample_correction: whether to apply sample correction
+ * (i.e. get 'sample variance' instead of 'population variance').
+ * \return r_covmat the computed covariance matrix.
+ */
void BLI_covariance_m_vn_ex(const int n,
const float *cos_vn,
const int nbr_cos_vn,
const float *center,
const bool use_sample_correction,
float *r_covmat);
+/**
+ * \brief Compute the covariance matrix of given set of 3D coordinates.
+ *
+ * \param cos_v3: the 3D points to compute covariance from.
+ * \param nbr_cos_v3: the number of 3D coordinates in cos_v3.
+ * \return r_covmat the computed covariance matrix.
+ * \return r_center the computed center (mean) of 3D points (may be NULL).
+ */
void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
const int nbr_cos_v3,
const bool use_sample_correction,
@@ -53,6 +75,8 @@ void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_math_time.h b/source/blender/blenlib/BLI_math_time.h
index 671ec6f857f..52857773797 100644
--- a/source/blender/blenlib/BLI_math_time.h
+++ b/source/blender/blenlib/BLI_math_time.h
@@ -27,7 +27,10 @@
extern "C" {
#endif
-/************************ Time constants definitions***************************/
+/* -------------------------------------------------------------------- */
+/** \name Time Constants Definitions
+ * \{ */
+
#define SECONDS_IN_MILLISECONDS 0.001
#define SECONDS_IN_MINUTE 60.0
#define MINUTES_IN_HOUR 60.0
@@ -37,6 +40,20 @@ extern "C" {
#define SECONDS_IN_DAY (MINUTES_IN_DAY * SECONDS_IN_MINUTE)
#define SECONDS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Time API
+ * \{ */
+
+/**
+ * Explode given time value expressed in seconds, into a set of days, hours, minutes, seconds
+ * and/or milliseconds (depending on which return parameters are not NULL).
+ *
+ * \note The smallest given return parameter will get the potential fractional remaining time
+ * value. E.g. if you give `seconds=90.0` and do not pass `r_seconds` and `r_milliseconds`,
+ * `r_minutes` will be set to `1.5`.
+ */
void BLI_math_time_seconds_decompose(double seconds,
double *r_days,
double *r_hours,
@@ -44,7 +61,15 @@ void BLI_math_time_seconds_decompose(double seconds,
double *r_seconds,
double *r_milliseconds);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
+
+/* None. */
+
+/** \} */
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 62fd4a835ef..8f955076baf 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -33,7 +33,9 @@
extern "C" {
#endif
-/************************************* Init ***********************************/
+/* -------------------------------------------------------------------- */
+/** \name Init
+ * \{ */
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic push
@@ -57,6 +59,7 @@ MINLINE void swap_v3_v3(float a[3], float b[3]);
MINLINE void swap_v4_v4(float a[4], float b[4]);
/* unsigned char */
+
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]);
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]);
@@ -66,10 +69,13 @@ MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a);
MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a);
/* char */
+
MINLINE void copy_v2_v2_char(char r[2], const char a[2]);
MINLINE void copy_v3_v3_char(char r[3], const char a[3]);
MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
+
/* short */
+
MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
@@ -78,30 +84,49 @@ MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
MINLINE void copy_v4_v4_int(int r[4], const int a[4]);
+
/* double */
+
MINLINE void zero_v3_db(double r[3]);
MINLINE void copy_v2_v2_db(double r[2], const double a[2]);
MINLINE void copy_v3_v3_db(double r[3], const double a[3]);
MINLINE void copy_v4_v4_db(double r[4], const double a[4]);
+
/* short -> float */
+
MINLINE void copy_v3fl_v3s(float r[3], const short a[3]);
+
/* int <-> float */
+
MINLINE void copy_v2fl_v2i(float r[2], const int a[2]);
+
+/* int <-> float */
+
MINLINE void round_v2i_v2fl(int r[2], const float a[2]);
+
/* double -> float */
+
MINLINE void copy_v2fl_v2db(float r[2], const double a[2]);
MINLINE void copy_v3fl_v3db(float r[3], const double a[3]);
MINLINE void copy_v4fl_v4db(float r[4], const double a[4]);
+
/* float -> double */
+
MINLINE void copy_v2db_v2fl(double r[2], const float a[2]);
MINLINE void copy_v3db_v3fl(double r[3], const float a[3]);
MINLINE void copy_v4db_v4fl(double r[4], const float a[4]);
+
/* float args -> vec */
+
MINLINE void copy_v2_fl2(float v[2], float x, float y);
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z);
MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w);
-/********************************* Arithmetic ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Arithmetic
+ * \{ */
MINLINE void add_v2_fl(float r[2], float f);
MINLINE void add_v3_fl(float r[3], float f);
@@ -149,11 +174,30 @@ MINLINE void mul_v4_v4(float r[4], const float a[4]);
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f);
MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]);
MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]);
+/**
+ * Convenience function to get the projected depth of a position.
+ * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
+ *
+ * Matches logic for:
+ *
+ * \code{.c}
+ * float co_4d[4] = {co[0], co[1], co[2], 1.0};
+ * mul_m4_v4(mat, co_4d);
+ * return co_4d[3];
+ * \endcode
+ */
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4],
const float co[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Has the effect of #mul_m3_v3(), on a single axis.
+ */
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Has the effect of #mul_mat3_m4_v3(), on a single axis.
+ * (no adding translation)
+ */
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -180,12 +224,17 @@ MINLINE void negate_v3_v3(float r[3], const float a[3]);
MINLINE void negate_v4(float r[4]);
MINLINE void negate_v4_v4(float r[4], const float a[4]);
+/* could add more... */
+
MINLINE void negate_v3_short(short r[3]);
MINLINE void negate_v3_db(double r[3]);
MINLINE void invert_v2(float r[2]);
MINLINE void invert_v3(float r[3]);
-MINLINE void invert_v3_safe(float r[3]); /* Invert the vector, but leaves zero values as zero. */
+/**
+ * Invert the vector, but leaves zero values as zero.
+ */
+MINLINE void invert_v3_safe(float r[3]);
MINLINE void abs_v2(float r[2]);
MINLINE void abs_v2_v2(float r[2], const float a[2]);
@@ -209,14 +258,26 @@ MINLINE double dot_v3v3_db(const double a[3], const double b[3]) ATTR_WARN_UNUSE
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE double cross_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]);
+/**
+ * Cross product suffers from severe precision loss when vectors are
+ * nearly parallel or opposite; doing the computation in double helps a lot.
+ */
MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3]);
MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3]);
+/**
+ * Excuse this fairly specific function, its used for polygon normals all over the place
+ * (could use a better name).
+ */
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]);
MINLINE void star_m3_v3(float rmat[3][3], const float a[3]);
-/*********************************** Length **********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Length
+ * \{ */
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT;
@@ -241,8 +302,14 @@ MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESU
MINLINE double len_v3_db(const double a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE double len_squared_v3_db(const double v[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float normalize_v2_length(float r[2], const float unit_scale);
+/**
+ * \note any vectors containing `nan` will be zeroed out.
+ */
MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_scale);
MINLINE float normalize_v3_length(float r[3], const float unit_scale);
+/**
+ * \note any vectors containing `nan` will be zeroed out.
+ */
MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_scale);
MINLINE double normalize_v3_length_db(double n[3], const double unit_scale);
MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], const double unit_scale);
@@ -254,16 +321,32 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3]);
MINLINE double normalize_v3_v3_db(double r[3], const double a[3]);
MINLINE double normalize_v3_db(double n[3]);
-/******************************* Interpolation *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interpolation
+ * \{ */
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t);
void interp_v2_v2v2_db(double target[2], const double a[2], const double b[2], const double t);
+/**
+ * Weight 3 2D vectors,
+ * 'w' must be unit length but is not a vector, just 3 weights.
+ */
void interp_v2_v2v2v2(
float r[2], const float a[2], const float b[2], const float c[2], const float t[3]);
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t);
void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], const double t);
+/**
+ * Weight 3 vectors,
+ * 'w' must be unit length but is not a vector, just 3 weights.
+ */
void interp_v3_v3v3v3(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]);
+/**
+ * Weight 3 vectors,
+ * 'w' must be unit length but is not a vector, just 4 weights.
+ */
void interp_v3_v3v3v3v3(float p[3],
const float v1[3],
const float v2[3],
@@ -282,11 +365,20 @@ void interp_v4_v4v4v4v4(float p[4],
void interp_v3_v3v3v3_uv(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float uv[2]);
+/**
+ * slerp, treat vectors as spherical coordinates
+ * \see #interp_qt_qtqt
+ *
+ * \return success
+ */
bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t)
ATTR_WARN_UNUSED_RESULT;
bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], const float t)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors.
+ */
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t);
void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], const float t);
@@ -316,14 +408,34 @@ void mid_v3_v3v3v3v3(
float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr);
+/**
+ * Specialized function for calculating normals.
+ * Fast-path for:
+ *
+ * \code{.c}
+ * add_v3_v3v3(r, a, b);
+ * normalize_v3(r)
+ * mul_v3_fl(r, angle_normalized_v3v3(a, b) / M_PI_2);
+ * \endcode
+ *
+ * We can use the length of (a + b) to calculate the angle.
+ */
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3]);
+/**
+ * Same as mid_v3_v3v3_angle_weighted
+ * but \a r is assumed to be accumulated normals, divided by their total.
+ */
void mid_v3_angle_weighted(float r[3]);
void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]);
void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]);
void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]);
-/********************************* Comparison ********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Comparison
+ * \{ */
MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -378,24 +490,64 @@ MINLINE bool compare_size_v3v3(const float a[3],
const float b[3],
const float limit) ATTR_WARN_UNUSED_RESULT;
+/**
+ * <pre>
+ * + l1
+ * |
+ * neg <- | -> pos
+ * |
+ * + l2
+ * </pre>
+ *
+ * \return Positive value when 'pt' is left-of-line
+ * (looking from 'l1' -> 'l2').
+ */
MINLINE float line_point_side_v2(const float l1[2],
const float l2[2],
const float pt[2]) ATTR_WARN_UNUSED_RESULT;
-/********************************** Angles ***********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Angles
+ * \{ */
/* - angle with 2 arguments is angle between vector.
* - angle with 3 arguments is angle between 3 points at the middle point.
* - angle_normalized_* is faster equivalent if vectors are normalized.
*/
+
+/**
+ * Return the shortest angle in radians between the 2 vectors.
+ */
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT;
float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return the shortest angle in radians between the 2 vectors.
+ */
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return the angle in radians between vecs 1-2 and 2-3 in radians
+ * If v1 is a shoulder, v2 is the elbow and v3 is the hand,
+ * this would return the angle at the elbow.
+ *
+ * note that when v1/v2/v3 represent 3 points along a straight line
+ * that the angle returned will be pi (180deg), rather than 0.0.
+ */
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Quicker than full angle computation.
+ */
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Quicker than full angle computation.
+ */
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Angle between 2 vectors, about an axis (axis can be considered a plane).
+ */
float angle_on_axis_v3v3_v3(const float v1[3],
const float v2[3],
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
@@ -403,6 +555,9 @@ float angle_signed_on_axis_v3v3_v3(const float v1[3],
const float v2[3],
const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
+ */
float angle_on_axis_v3v3v3_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -416,32 +571,107 @@ void angle_quad_v3(
float angles[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
void angle_poly_v3(float *angles, const float *verts[3], int len);
-/********************************* Geometry **********************************/
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Geometry
+ * \{ */
+
+/**
+ * Project \a p onto \a v_proj
+ */
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]);
+/**
+ * Project \a p onto \a v_proj
+ */
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]);
void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]);
+/**
+ * Project \a p onto a unit length \a v_proj
+ */
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]);
+/**
+ * Project \a p onto a unit length \a v_proj
+ */
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]);
+/**
+ * In this case plane is a 3D vector only (no 4th component).
+ *
+ * Projecting will make \a out a copy of \a p orthogonal to \a v_plane.
+ *
+ * \note If \a p is exactly perpendicular to \a v_plane, \a out will just be a copy of \a p.
+ *
+ * \note This function is a convenience to call:
+ * \code{.c}
+ * project_v3_v3v3(out, p, v_plane);
+ * sub_v3_v3v3(out, p, out);
+ * \endcode
+ */
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
+/**
+ * Project a vector on a plane defined by normal and a plane point p.
+ */
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]);
+/**
+ * Returns a reflection vector from a vector and a normal vector
+ * reflect = vec - ((2 * dot(vec, mirror)) * mirror).
+ *
+ * <pre>
+ * v
+ * + ^
+ * \ |
+ * \|
+ * + normal: axis of reflection
+ * /
+ * /
+ * +
+ * out: result (negate for a 'bounce').
+ * </pre>
+ */
void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]);
void reflect_v3_v3v3_db(double out[3], const double vec[3], const double normal[3]);
+/**
+ * Takes a vector and computes 2 orthogonal directions.
+ *
+ * \note if \a n is n unit length, computed values will be too.
+ */
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
+/**
+ * Calculates \a p - a perpendicular vector to \a v
+ *
+ * \note return vector won't maintain same length.
+ */
void ortho_v3_v3(float out[3], const float v[3]);
+/**
+ * no brainer compared to v3, just have for consistency.
+ */
void ortho_v2_v2(float out[2], const float v[2]);
+/**
+ * Returns a vector bisecting the angle at b formed by a, b and c.
+ */
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
+/**
+ * Rotate a point \a p by \a angle around origin (0, 0)
+ */
void rotate_v2_v2fl(float r[2], const float p[2], const float angle);
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle);
+/**
+ * Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
+ * http://local.wasp.uwa.edu.au/~pbourke/geometry/
+ */
void rotate_normalized_v3_v3v3fl(float out[3],
const float p[3],
const float axis[3],
const float angle);
-/*********************************** Other ***********************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Other
+ * \{ */
void print_v2(const char *str, const float v[2]);
void print_v3(const char *str, const float v[3]);
@@ -464,6 +694,7 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr);
+/** ensure \a v1 is \a dist from \a v2 */
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
@@ -476,8 +707,16 @@ MINLINE void clamp_v2_v2v2(float vec[2], const float min[2], const float max[2])
MINLINE void clamp_v3_v3v3(float vec[3], const float min[3], const float max[3]);
MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4]);
-/***************************** Array Functions *******************************/
-/* follow fixed length vector function conventions. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Array Functions
+ * \{ */
+
+/**
+ * Follow fixed length vector function conventions.
+ */
+
double dot_vn_vn(const float *array_src_a,
const float *array_src_b,
const int size) ATTR_WARN_UNUSED_RESULT;
@@ -532,7 +771,11 @@ void add_vn_vnvn_d(double *array_tar,
const int size);
void mul_vn_db(double *array_tar, const int size, const double f);
-/**************************** Inline Definitions ******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Definitions
+ * \{ */
#if BLI_MATH_DO_INLINE
# include "intern/math_vector_inline.c"
@@ -542,6 +785,8 @@ void mul_vn_db(double *array_tar, const int size, const double f);
# pragma GCC diagnostic pop
#endif
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h
index b2e05b00735..4ac4712bc8c 100644
--- a/source/blender/blenlib/BLI_memarena.h
+++ b/source/blender/blenlib/BLI_memarena.h
@@ -29,8 +29,8 @@
extern "C" {
#endif
-/* A reasonable standard buffer size, big
- * enough to not cause much internal fragmentation,
+/**
+ * A reasonable standard buffer size, big enough to not cause much internal fragmentation,
* small enough not to waste resources
*/
#define BLI_MEMARENA_STD_BUFSIZE MEM_SIZE_OPTIMAL(1 << 14)
@@ -50,8 +50,22 @@ void *BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESU
void *BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2);
+/**
+ * Transfer ownership of allocated blocks from `ma_src` into `ma_dst`,
+ * cleaning the contents of `ma_src`.
+ *
+ * \note Useful for multi-threaded tasks that need a thread-local #MemArena
+ * that is kept after the multi-threaded operation is completed.
+ *
+ * \note Avoid accumulating memory pools where possible
+ * as any unused memory in `ma_src` is wasted every merge.
+ */
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src) ATTR_NONNULL(1, 2);
+/**
+ * Clear for reuse, avoids re-allocation when an arena may
+ * otherwise be free'd and recreated.
+ */
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h
index a9a3928394d..827ecc49739 100644
--- a/source/blender/blenlib/BLI_memblock.h
+++ b/source/blender/blenlib/BLI_memblock.h
@@ -38,6 +38,10 @@ typedef void (*MemblockValFreeFP)(void *val);
BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT;
void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Reset elem count to 0 but keep as much memory allocated needed
+ * for at least the previous elem count.
+ */
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
@@ -56,6 +60,11 @@ typedef struct BLI_memblock_iter {
void BLI_memblock_iternew(BLI_memblock *mblk, BLI_memblock_iter *iter) ATTR_NONNULL();
void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Direct access. elem is element index inside the chosen chunk.
+ * Double usage: You can set chunk to 0 and set the absolute elem index.
+ * The correct chunk will be retrieve.
+ */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_memiter.h b/source/blender/blenlib/BLI_memiter.h
index abb1bec809d..231aa31fad9 100644
--- a/source/blender/blenlib/BLI_memiter.h
+++ b/source/blender/blenlib/BLI_memiter.h
@@ -35,10 +35,19 @@ struct BLI_memiter;
typedef struct BLI_memiter BLI_memiter;
-/* warning, ATTR_MALLOC flag on BLI_memiter_alloc causes crash, see: D2756 */
-BLI_memiter *BLI_memiter_create(unsigned int chunk_size)
+/**
+ * \param chunk_size_min: Should be a power of two and
+ * significantly larger than the average element size used.
+ *
+ * While allocations of any size are supported, they won't be efficient
+ * (effectively becoming a single-linked list).
+ *
+ * Its intended that many elements can be stored per chunk.
+ */
+BLI_memiter *BLI_memiter_create(unsigned int chunk_size_min)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
void *BLI_memiter_alloc(BLI_memiter *mi, unsigned int size)
+ /* WARNING: `ATTR_MALLOC` attribute on #BLI_memiter_alloc causes crash, see: D2756. */
ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
ATTR_NONNULL(1, 3);
@@ -48,11 +57,15 @@ void BLI_memiter_destroy(BLI_memiter *mi) ATTR_NONNULL(1);
void BLI_memiter_clear(BLI_memiter *mi) ATTR_NONNULL(1);
unsigned int BLI_memiter_count(const BLI_memiter *mi) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* utils */
+/* Utilities. */
+
+/**
+ * Support direct lookup for the first item.
+ */
void *BLI_memiter_elem_first(BLI_memiter *mi);
void *BLI_memiter_elem_first_size(BLI_memiter *mi, unsigned int *r_size);
-/* private structure */
+/** Private structure. */
typedef struct BLI_memiter_handle {
struct BLI_memiter_elem *elem;
uint elem_left;
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index 61b572a4943..d6abae36e00 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -44,19 +44,52 @@ void *BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT A
ATTR_NONNULL(1);
void *BLI_mempool_calloc(BLI_mempool *pool)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
+/**
+ * Free an element from the mempool.
+ *
+ * \note doesn't protect against double frees, take care!
+ */
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1, 2);
+/**
+ * Empty the pool, as if it were just created.
+ *
+ * \param pool: The pool to clear.
+ * \param totelem_reserve: Optionally reserve how many items should be kept from clearing.
+ */
void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve) ATTR_NONNULL(1);
+/**
+ * Wrap #BLI_mempool_clear_ex with no reserve set.
+ */
void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1);
+/**
+ * Free the mempool its self (and all elements).
+ */
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1);
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1);
void *BLI_mempool_findelem(BLI_mempool *pool, unsigned int index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Fill in \a data with pointers to each element of the mempool,
+ * to create lookup table.
+ *
+ * \param pool: Pool to create a table from.
+ * \param data: array of pointers at least the size of 'pool->totused'
+ */
void BLI_mempool_as_table(BLI_mempool *pool, void **data) ATTR_NONNULL(1, 2);
+/**
+ * A version of #BLI_mempool_as_table that allocates and returns the data.
+ */
void **BLI_mempool_as_tableN(BLI_mempool *pool,
const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
+/**
+ * Fill in \a data with the contents of the mempool.
+ */
void BLI_mempool_as_array(BLI_mempool *pool, void *data) ATTR_NONNULL(1, 2);
+/**
+ * A version of #BLI_mempool_as_array that allocates and returns the data.
+ */
void *BLI_mempool_as_arrayN(BLI_mempool *pool,
const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
@@ -67,9 +100,10 @@ void BLI_mempool_set_memory_debug(void);
/**
* Iteration stuff.
- * NOTE: this may easy to produce bugs with.
+ * \note this may easy to produce bugs with.
*/
-/* private structure */
+
+/* Private structure. */
typedef struct BLI_mempool_iter {
BLI_mempool *pool;
struct BLI_mempool_chunk *curchunk;
@@ -89,7 +123,13 @@ enum {
BLI_MEMPOOL_ALLOW_ITER = (1 << 0),
};
+/**
+ * Initialize a new mempool iterator, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
+ */
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL();
+/**
+ * Step over the iterator, returning the mempool item or NULL.
+ */
void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_mesh_intersect.hh b/source/blender/blenlib/BLI_mesh_intersect.hh
index f28be9bf59b..4aaed814bba 100644
--- a/source/blender/blenlib/BLI_mesh_intersect.hh
+++ b/source/blender/blenlib/BLI_mesh_intersect.hh
@@ -93,13 +93,16 @@ struct Plane {
Plane(const mpq3 &norm_exact, const mpq_class &d_exact);
Plane(const double3 &norm, const double d);
- /* Test equality on the exact fields. */
+ /** Test equality on the exact fields. */
bool operator==(const Plane &other) const;
- /* Hash on the exact fields. */
+ /** Hash on the exact fields. */
uint64_t hash() const;
void make_canonical();
+ /**
+ * This is wrong for degenerate planes, but we don't expect to call it on those.
+ */
bool exact_populated() const;
void populate_exact();
};
@@ -395,10 +398,16 @@ struct BoundingBox {
}
};
-/** Assume bounding boxes have been expanded by a sufficient epsilon. */
+/**
+ * Assume bounding boxes have been expanded by a sufficient epsilon on all sides
+ * so that the comparisons against the bb bounds are sufficient to guarantee that
+ * if an overlap or even touching could happen, this will return true.
+ */
bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b);
/**
+ * This is the main routine for calculating the self_intersection of a triangle mesh.
+ *
* The output will have duplicate vertices merged and degenerate triangles ignored.
* If the input has overlapping co-planar triangles, then there will be
* as many duplicates as there are overlaps in each overlapping triangular region.
@@ -406,7 +415,7 @@ bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b);
* that the output triangle was a part of (input can have -1 for that field and then
* the index in `tri[]` will be used as the original index).
* The orig structure of the output #IMesh gives the originals for vertices and edges.
- * NOTE: if the input tm_in has a non-empty orig structure, then it is ignored.
+ * \note if the input tm_in has a non-empty orig structure, then it is ignored.
*/
IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena);
@@ -416,10 +425,17 @@ IMesh trimesh_nary_intersect(const IMesh &tm_in,
bool use_self,
IMeshArena *arena);
-/** Return an IMesh that is a triangulation of a mesh with general polygonal faces. */
+/**
+ * Return an #IMesh that is a triangulation of a mesh with general
+ * polygonal faces, #IMesh.
+ * Added diagonals will be distinguishable by having edge original
+ * indices of #NO_INDEX.
+ */
IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena);
-/** This has the side effect of populating verts in the #IMesh. */
+/**
+ * Writing the obj_mesh has the side effect of populating verts in the #IMesh.
+ */
void write_obj_mesh(IMesh &m, const std::string &objname);
} /* namespace blender::meshintersect */
diff --git a/source/blender/blenlib/BLI_noise.h b/source/blender/blenlib/BLI_noise.h
index 37afd8ee031..51aee9dc2ba 100644
--- a/source/blender/blenlib/BLI_noise.h
+++ b/source/blender/blenlib/BLI_noise.h
@@ -29,21 +29,65 @@ extern "C" {
float BLI_noise_hnoise(float noisesize, float x, float y, float z);
float BLI_noise_hnoisep(float noisesize, float x, float y, float z);
+/**
+ * Original turbulence functions.
+ */
float BLI_noise_turbulence(float noisesize, float x, float y, float z, int nr);
-/* newnoise: generic noise & turbulence functions
+/**
+ * newnoise: generic noise & turbulence functions
* to replace the above BLI_noise_hnoise/p & BLI_noise_turbulence/1.
- * This is done so different noise basis functions can be used */
+ * This is done so different noise basis functions can be used.
+ */
+/**
+ * newnoise: generic noise function for use with different `noisebasis`.
+ */
float BLI_noise_generic_noise(
float noisesize, float x, float y, float z, bool hard, int noisebasis);
+/**
+ * newnoise: generic turbulence function for use with different `noisebasis`.
+ */
float BLI_noise_generic_turbulence(
float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis);
+
/* newnoise: musgrave functions */
+
+/**
+ * Procedural `fBm` evaluated at "point"; returns value stored in "value".
+ *
+ * \param H: is the fractal increment parameter.
+ * \param lacunarity: is the gap between successive frequencies.
+ * \param octaves: is the number of frequencies in the `fBm`.
+ */
float BLI_noise_mg_fbm(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
+/**
+ * Procedural multi-fractal evaluated at "point";
+ * returns value stored in "value".
+ *
+ * \param H: determines the highest fractal dimension.
+ * \param lacunarity: is gap between successive frequencies.
+ * \param octaves: is the number of frequencies in the `fBm`.
+ *
+ * \note There used to be a parameter called `offset`, old docs read:
+ * is the zero offset, which determines multi-fractality.
+ */
float BLI_noise_mg_multi_fractal(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
+/**
+ * "Variable Lacunarity Noise"
+ * A distorted variety of Perlin noise.
+ */
float BLI_noise_mg_variable_lacunarity(
float x, float y, float z, float distortion, int nbas1, int nbas2);
+/**
+ * Heterogeneous procedural terrain function: stats by altitude method.
+ * Evaluated at "point"; returns value stored in "value".
+ *
+ * \param H: Determines the fractal dimension of the roughest areas.
+ * \param lacunarity: Is the gap between successive frequencies.
+ * \param octaves: Is the number of frequencies in the `fBm`.
+ * \param offset: Raises the terrain from `sea level`.
+ */
float BLI_noise_mg_hetero_terrain(float x,
float y,
float z,
@@ -52,6 +96,14 @@ float BLI_noise_mg_hetero_terrain(float x,
float octaves,
float offset,
int noisebasis);
+/**
+ * Hybrid additive/multiplicative multi-fractal terrain model.
+ *
+ * Some good parameter values to start with:
+ *
+ * \param H: 0.25
+ * \param offset: 0.7
+ */
float BLI_noise_mg_hybrid_multi_fractal(float x,
float y,
float z,
@@ -61,6 +113,15 @@ float BLI_noise_mg_hybrid_multi_fractal(float x,
float offset,
float gain,
int noisebasis);
+/**
+ * Ridged multi-fractal terrain model.
+ *
+ * Some good parameter values to start with:
+ *
+ * \param H: 1.0
+ * \param offset: 1.0
+ * \param gain: 2.0
+ */
float BLI_noise_mg_ridged_multi_fractal(float x,
float y,
float z,
@@ -71,9 +132,20 @@ float BLI_noise_mg_ridged_multi_fractal(float x,
float gain,
int noisebasis);
/* newnoise: voronoi */
+
+/**
+ * Not 'pure' Worley, but the results are virtually the same.
+ * Returns distances in da and point coords in `pa`.
+ */
void BLI_noise_voronoi(float x, float y, float z, float *da, float *pa, float me, int dtype);
-/* newnoise: BLI_noise_cell & BLI_noise_cell_v3 (for vector/point/color) */
+/**
+ * newnoise: BLI_noise_cell & BLI_noise_cell_v3 (for vector/point/color).
+ * idem, signed.
+ */
float BLI_noise_cell(float x, float y, float z);
+/**
+ * Returns a vector/point/color in `r_ca`, using point hash-array directly.
+ */
void BLI_noise_cell_v3(float x, float y, float z, float r_ca[3]);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_noise.hh b/source/blender/blenlib/BLI_noise.hh
index a7af69f42a9..44af2c44f00 100644
--- a/source/blender/blenlib/BLI_noise.hh
+++ b/source/blender/blenlib/BLI_noise.hh
@@ -30,24 +30,28 @@ namespace blender::noise {
* \{ */
/* Hash integers to `uint32_t`. */
+
uint32_t hash(uint32_t kx);
uint32_t hash(uint32_t kx, uint32_t ky);
uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz);
uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw);
/* Hash floats to `uint32_t`. */
+
uint32_t hash_float(float kx);
uint32_t hash_float(float2 k);
uint32_t hash_float(float3 k);
uint32_t hash_float(float4 k);
/* Hash integers to `float` between 0 and 1. */
+
float hash_to_float(uint32_t kx);
float hash_to_float(uint32_t kx, uint32_t ky);
float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz);
float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw);
/* Hash floats to `float` between 0 and 1. */
+
float hash_float_to_float(float k);
float hash_float_to_float(float2 k);
float hash_float_to_float(float3 k);
@@ -69,30 +73,35 @@ float4 hash_float_to_float4(float4 k);
* \{ */
/* Perlin noise in the range [-1, 1]. */
+
float perlin_signed(float position);
float perlin_signed(float2 position);
float perlin_signed(float3 position);
float perlin_signed(float4 position);
/* Perlin noise in the range [0, 1]. */
+
float perlin(float position);
float perlin(float2 position);
float perlin(float3 position);
float perlin(float4 position);
/* Fractal perlin noise in the range [0, 1]. */
+
float perlin_fractal(float position, float octaves, float roughness);
float perlin_fractal(float2 position, float octaves, float roughness);
float perlin_fractal(float3 position, float octaves, float roughness);
float perlin_fractal(float4 position, float octaves, float roughness);
/* Positive distorted fractal perlin noise. */
+
float perlin_fractal_distorted(float position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float2 position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float3 position, float octaves, float roughness, float distortion);
float perlin_fractal_distorted(float4 position, float octaves, float roughness, float distortion);
/* Positive distorted fractal perlin noise that outputs a float3. */
+
float3 perlin_float3_fractal_distorted(float position,
float octaves,
float roughness,
@@ -116,24 +125,56 @@ float3 perlin_float3_fractal_distorted(float4 position,
/** \name Musgrave Multi Fractal
* \{ */
+/**
+ * 1D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_ridged_multi_fractal(const float co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 2D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_ridged_multi_fractal(const float2 co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 3D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_ridged_multi_fractal(const float3 co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 4D Ridged Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_ridged_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -141,24 +182,56 @@ float musgrave_ridged_multi_fractal(const float4 co,
const float offset,
const float gain);
+/**
+ * 1D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hybrid_multi_fractal(const float co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 2D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hybrid_multi_fractal(const float2 co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 3D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hybrid_multi_fractal(const float3 co,
const float H,
const float lacunarity,
const float octaves,
const float offset,
const float gain);
+/**
+ * 4D Hybrid Additive/Multiplicative Multi-fractal Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hybrid_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -166,43 +239,132 @@ float musgrave_hybrid_multi_fractal(const float4 co,
const float offset,
const float gain);
+/**
+ * 1D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_fBm(const float co, const float H, const float lacunarity, const float octaves);
+
+/**
+ * 2D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_fBm(const float2 co, const float H, const float lacunarity, const float octaves);
+/**
+ * 3D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_fBm(const float3 co, const float H, const float lacunarity, const float octaves);
+/**
+ * 4D Musgrave fBm
+ *
+ * \param H: fractal increment parameter.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_fBm(const float4 co, const float H, const float lacunarity, const float octaves);
+/**
+ * 1D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_multi_fractal(const float co,
const float H,
const float lacunarity,
const float octaves);
+/**
+ * 2D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_multi_fractal(const float2 co,
const float H,
const float lacunarity,
const float octaves);
+/**
+ * 3D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_multi_fractal(const float3 co,
const float H,
const float lacunarity,
const float octaves);
+/**
+ * 4D Musgrave Multi-fractal
+ *
+ * \param H: highest fractal dimension.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ */
float musgrave_multi_fractal(const float4 co,
const float H,
const float lacunarity,
const float octaves);
+/**
+ * 1D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hetero_terrain(const float co,
const float H,
const float lacunarity,
const float octaves,
const float offset);
+/**
+ * 2D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hetero_terrain(const float2 co,
const float H,
const float lacunarity,
const float octaves,
const float offset);
+/**
+ * 3D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hetero_terrain(const float3 co,
const float H,
const float lacunarity,
const float octaves,
const float offset);
+/**
+ * 4D Musgrave Heterogeneous Terrain
+ *
+ * \param H: fractal dimension of the roughest area.
+ * \param lacunarity: gap between successive frequencies.
+ * \param octaves: number of frequencies in the fBm.
+ * \param offset: raises the terrain from `sea level'.
+ */
float musgrave_hetero_terrain(const float4 co,
const float H,
const float lacunarity,
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index e4774c58e84..8b54ee52322 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -29,27 +29,109 @@
extern "C" {
#endif
+/**
+ * Sets the specified environment variable to the specified value,
+ * and clears it if `val == NULL`.
+ */
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
+/**
+ * Only set an environment variable if already not there.
+ * Like Unix `setenv(env, val, 0);`
+ *
+ * (not used anywhere).
+ */
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
+/**
+ * Get an environment variable, result has to be used immediately.
+ *
+ * On windows #getenv gets its variables from a static copy of the environment variables taken at
+ * process start-up, causing it to not pick up on environment variables created during runtime.
+ * This function uses an alternative method to get environment variables that does pick up on
+ * runtime environment variables. The result will be UTF-8 encoded.
+ */
const char *BLI_getenv(const char *env) ATTR_NONNULL(1);
+/**
+ * Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
+ * front if specified and `dir` begins with "//"). Normalizes all occurrences of path
+ * separators, including ensuring there is exactly one between the copies of `dir` and `file`,
+ * and between the copies of `relabase` and `dir`.
+ *
+ * \param relabase: Optional prefix to substitute for "//" on front of `dir`.
+ * \param string: Area to return result.
+ */
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
+/**
+ * Ensures that the parent directory of `name` exists.
+ *
+ * \return true on success (i.e. given path now exists on file-system), false otherwise.
+ */
bool BLI_make_existing_file(const char *name);
+/**
+ * Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
+ *
+ * - Won't change \a string.
+ * - Won't create any directories.
+ * - Doesn't use CWD, or deal with relative paths.
+ * - Only fill's in \a dir and \a file when they are non NULL.
+ */
void BLI_split_dirfile(
const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
+/**
+ * Copies the parent directory part of string into `dir`, max length `dirlen`.
+ */
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
+/**
+ * Copies the leaf filename part of string into `file`, max length `filelen`.
+ */
void BLI_split_file_part(const char *string, char *file, const size_t filelen);
+/**
+ * Returns a pointer to the last extension (e.g. the position of the last period).
+ * Returns NULL if there is no extension.
+ */
const char *BLI_path_extension(const char *filepath) ATTR_NONNULL();
+/**
+ * Append a filename to a dir, ensuring slash separates.
+ */
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
ATTR_NONNULL();
+/**
+ * Simple appending of filename to dir, does not check for valid path!
+ * Puts result into `dst`, which may be same area as `dir`.
+ *
+ * \note Consider using #BLI_path_join for more general path joining
+ * that de-duplicates separators and can handle an arbitrary number of paths.
+ */
void BLI_join_dirfile(char *__restrict dst,
const size_t maxlen,
const char *__restrict dir,
const char *__restrict file) ATTR_NONNULL();
+/**
+ * Join multiple strings into a path, ensuring only a single path separator between each,
+ * and trailing slash is kept.
+ *
+ * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
+ * duplicate slashes will be cleaned up.
+ */
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first, ...)
ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
+/**
+ * Like Python's `os.path.basename()`
+ *
+ * \return The pointer into \a path string immediately after last slash,
+ * or start of \a path if none found.
+ */
const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Get an element of the path at an index, eg:
+ * "/some/path/file.txt" where an index of:
+ * - 0 or -3: "some"
+ * - 1 or -2: "path"
+ * - 2 or -1: "file.txt"
+ *
+ * Ignores multiple slashes at any point in the path (including start/end).
+ */
bool BLI_path_name_at_index(const char *__restrict path,
const int index,
int *__restrict r_offset,
@@ -59,59 +141,233 @@ bool BLI_path_name_at_index(const char *__restrict path,
bool BLI_path_contains(const char *container_path,
const char *containee_path) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns pointer to the rightmost path separator in string.
+ */
const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Appends a slash to string if there isn't one there already.
+ * Returns the new length of the string.
+ */
int BLI_path_slash_ensure(char *string) ATTR_NONNULL();
+/**
+ * Removes the last slash and everything after it to the end of string, if there is one.
+ */
void BLI_path_slash_rstrip(char *string) ATTR_NONNULL();
+/**
+ * Returns pointer to the leftmost path separator in string. Not actually used anywhere.
+ */
const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Changes to the path separators to the native ones for this OS.
+ */
void BLI_path_slash_native(char *path) ATTR_NONNULL();
#ifdef _WIN32
bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
#endif
+/**
+ * Search for a binary (executable)
+ */
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
+/**
+ * \return true when `str` end with `ext` (case insensitive).
+ */
bool BLI_path_extension_check(const char *str, const char *ext)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_path_extension_check_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0);
+/**
+ * \return true when `str` ends with any of the suffixes in `ext_array`.
+ */
bool BLI_path_extension_check_array(const char *str, const char **ext_array)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Semicolon separated wildcards, eg: `*.zip;*.py;*.exe`
+ * does `str` match any of the semicolon-separated glob patterns in #fnmatch.
+ */
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Does basic validation of the given glob string, to prevent common issues from string
+ * truncation.
+ *
+ * For now, only forbids last group to be a wildcard-only one, if there are more than one group
+ * (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`)
+ *
+ * \returns true if it had to modify given \a ext_fnmatch pattern.
+ */
bool BLI_path_extension_glob_validate(char *ext_fnmatch) ATTR_NONNULL();
+/**
+ * Removes any existing extension on the end of \a path and appends \a ext.
+ * \return false if there was no room.
+ */
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
+/**
+ * Strip's trailing '.'s and adds the extension only when needed
+ */
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
+/**
+ * Ensure `filepath` has a file component, adding `filename` when it's empty or ends with a slash.
+ * \return true if the `filename` was appended to `filepath`.
+ */
bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
+/**
+ * Looks for a sequence of decimal digits in string, preceding any filename extension,
+ * returning the integer value if found, or 0 if not.
+ *
+ * \param string: String to scan.
+ * \param head: Optional area to return copy of part of string prior to digits,
+ * or before dot if no digits.
+ * \param tail: Optional area to return copy of part of string following digits,
+ * or from dot if no digits.
+ * \param r_num_len: Optional to return number of digits found.
+ */
int BLI_path_sequence_decode(const char *string,
char *head,
char *tail,
unsigned short *r_num_len);
+/**
+ * Returns in area pointed to by string a string of the form `<head><pic><tail>`,
+ * where pic is formatted as `numlen` digits with leading zeroes.
+ */
void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic);
+/**
+ * Remove redundant characters from \a path and optionally make absolute.
+ *
+ * \param relabase: The path this is relative to, or ignored when NULL.
+ * \param path: Can be any input, and this function converts it to a regular full path.
+ * Also removes garbage from directory paths, like `/../` or double slashes etc.
+ *
+ * \note \a path isn't protected for max string names.
+ */
void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2);
-/* Same as above but adds a trailing slash. */
+/**
+ * Cleanup file-path ensuring a trailing slash.
+ *
+ * \note Same as #BLI_path_normalize but adds a trailing slash.
+ */
void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
+/**
+ * Make given name safe to be used in paths.
+ *
+ * \return true if \a fname was changed, false otherwise.
+ *
+ * For now, simply replaces reserved chars (as listed in
+ * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
+ * by underscores ('_').
+ *
+ * \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
+ * but again can be an issue in some cases, so we simply replace it by an underscore too
+ * (good practice anyway).
+ * REMOVED based on popular demand (see T45900).
+ * Percent '%' char is a bit same case - not recommended to use it,
+ * but supported by all decent file-systems/operating-systems around.
+ *
+ * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
+ * this can lead to issues.
+ *
+ * \note On Windows, it also checks for forbidden names
+ * (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
+ */
bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1);
+/**
+ * Make given path OS-safe.
+ *
+ * \return true if \a path was changed, false otherwise.
+ */
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
-/* Go back one directory. */
+/**
+ * Go back one directory.
+ *
+ * Replaces path with the path of its parent directory, returning true if
+ * it was able to find a parent directory within the path.
+ */
bool BLI_path_parent_dir(char *path) ATTR_NONNULL();
-/* Go back until the directory is found. */
+/**
+ * Go back until the directory is found.
+ *
+ * Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
+ * leaving the path of the lowest-level directory that does exist and we can read.
+ */
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL();
+/**
+ * If path begins with "//", strips that and replaces it with `basepath` directory.
+ *
+ * \note Also converts drive-letter prefix to something more sensible
+ * if this is a non-drive-letter-based system.
+ *
+ * \param path: The path to convert.
+ * \param basepath: The directory to base relative paths with.
+ * \return true if the path was relative (started with "//").
+ */
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL();
+/**
+ * Replaces "#" character sequence in last slash-separated component of `path`
+ * with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
+ */
bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL();
+/**
+ * Replaces "#" character sequence in last slash-separated component of `path`
+ * with sta and end as decimal integers, with leading zeroes as necessary, to make digits
+ * digits each, with a hyphen in-between.
+ */
bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL();
+/**
+ * Get the frame from a filename formatted by blender's frame scheme
+ */
bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL();
-void BLI_path_frame_strip(char *path, char *ext) ATTR_NONNULL();
+/**
+ * Given a `path` with digits representing frame numbers, replace the digits with the '#'
+ * character and extract the extension.
+ * So: `/some/path_123.jpeg`
+ * Becomes: `/some/path_###` with `r_ext` set to `.jpeg`.
+ */
+void BLI_path_frame_strip(char *path, char *r_ext) ATTR_NONNULL();
+/**
+ * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
+ */
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
+/**
+ * Checks for a relative path (ignoring Blender's "//") prefix
+ * (unlike `!BLI_path_is_rel(path)`).
+ * When false, #BLI_path_abs_from_cwd would expand the absolute path.
+ */
+bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL();
+/**
+ * Checks for relative path, expanding them relative to the current working directory.
+ * \returns true if the expansion was performed.
+ *
+ * \note Should only be called with command line paths.
+ * This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
+ * In most cases #BLI_path_abs should be used instead.
+ */
bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) ATTR_NONNULL();
+/**
+ * Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
+ * the same `relfile`, will convert it back to its original value.
+ */
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
+/**
+ * Does path begin with the special "//" prefix that Blender uses to indicate
+ * a path relative to the .blend file.
+ */
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * Return true if the path is a UNC share.
+ */
bool BLI_path_is_unc(const char *path);
+/**
+ * Creates a display string from path to be used menus and the user interface.
+ * Like `bpy.path.display_name()`.
+ */
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) ATTR_NONNULL();
#if defined(WIN32)
@@ -119,10 +375,22 @@ void BLI_path_normalize_unc_16(wchar_t *path_16);
void BLI_path_normalize_unc(char *path_16, int maxlen);
#endif
+/**
+ * Appends a suffix to the string, fitting it before the extension
+ *
+ * string = Foo.png, suffix = 123, separator = _
+ * Foo.png -> Foo_123.png
+ *
+ * \param string: original (and final) string
+ * \param maxlen: Maximum length of string
+ * \param suffix: String to append to the original string
+ * \param sep: Optional separator character
+ * \return true if succeeded
+ */
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
ATTR_NONNULL();
-/* path string comparisons: case-insensitive for Windows, case-sensitive otherwise */
+/* Path string comparisons: case-insensitive for Windows, case-sensitive otherwise. */
#if defined(WIN32)
# define BLI_path_cmp BLI_strcasecmp
# define BLI_path_ncmp BLI_strncasecmp
@@ -131,8 +399,8 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
# define BLI_path_ncmp strncmp
#endif
-/* these values need to be hardcoded in structs, dna does not recognize defines */
-/* also defined in DNA_space_types.h */
+/* These values need to be hard-coded in structs, dna does not recognize defines */
+/* also defined in `DNA_space_types.h`. */
#ifndef FILE_MAXDIR
# define FILE_MAXDIR 768
# define FILE_MAXFILE 256
@@ -155,7 +423,7 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
#define FILENAME_PARENT ".."
#define FILENAME_CURRENT "."
-/* Avoid calling strcmp on one or two chars! */
+/* Avoid calling `strcmp` on one or two chars! */
#define FILENAME_IS_PARENT(_n) (((_n)[0] == '.') && ((_n)[1] == '.') && ((_n)[2] == '\0'))
#define FILENAME_IS_CURRENT(_n) (((_n)[0] == '.') && ((_n)[1] == '\0'))
#define FILENAME_IS_CURRPAR(_n) \
diff --git a/source/blender/blenlib/BLI_polyfill_2d.h b/source/blender/blenlib/BLI_polyfill_2d.h
index ca63ea5af87..d16c102ec86 100644
--- a/source/blender/blenlib/BLI_polyfill_2d.h
+++ b/source/blender/blenlib/BLI_polyfill_2d.h
@@ -26,6 +26,9 @@ extern "C" {
struct MemArena;
+/**
+ * A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations.
+ */
void BLI_polyfill_calc_arena(const float (*coords)[2],
const unsigned int coords_tot,
const int coords_sign,
@@ -33,6 +36,19 @@ void BLI_polyfill_calc_arena(const float (*coords)[2],
struct MemArena *arena);
+/**
+ * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
+ *
+ * \param coords: 2D coordinates describing vertices of the polygon,
+ * in either clockwise or counterclockwise order.
+ * \param coords_tot: Total points in the array.
+ * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
+ *
+ * \param r_tris: This array is filled in with triangle indices in clockwise order.
+ * The length of the array must be `coords_tot - 2`.
+ * Indices are guaranteed to be assigned to unique triangles, with valid indices,
+ * even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
+ */
void BLI_polyfill_calc(const float (*coords)[2],
const unsigned int coords_tot,
const int coords_sign,
diff --git a/source/blender/blenlib/BLI_polyfill_2d_beautify.h b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
index 2c5296269ae..b0b97336a3b 100644
--- a/source/blender/blenlib/BLI_polyfill_2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
@@ -27,6 +27,12 @@ extern "C" {
struct Heap;
struct MemArena;
+/**
+ * The intention is that this calculates the output of #BLI_polyfill_calc
+ * \note assumes the \a coords form a boundary,
+ * so any edges running along contiguous (wrapped) indices,
+ * are ignored since the edges won't share 2 faces.
+ */
void BLI_polyfill_beautify(const float (*coords)[2],
const unsigned int coords_tot,
unsigned int (*tris)[3],
@@ -35,6 +41,21 @@ void BLI_polyfill_beautify(const float (*coords)[2],
struct MemArena *arena,
struct Heap *eheap);
+/**
+ * Assuming we have 2 triangles sharing an edge (2 - 4),
+ * check if the edge running from (1 - 3) gives better results.
+ *
+ * \param lock_degenerate: Use to avoid rotating out of a degenerate state:
+ * - When true, an existing zero area face on either side of the (2 - 4
+ * split will return a positive value.
+ * - When false, the check must be non-biased towards either split direction.
+ * \param r_area: Return the area of the quad,
+ * This can be useful when comparing the return value with near zero epsilons.
+ * In this case the epsilon can be scaled by the area to avoid the return value
+ * of very large faces not having a reliable way to detect near-zero output.
+ *
+ * \return (negative number means the edge can be rotated, lager == better).
+ */
float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index f8627952628..a1df6e1263e 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -31,7 +31,8 @@
extern "C" {
#endif
-/* RNG is an abstract random number generator type that avoids using globals.
+/**
+ * RNG is an abstract random number generator type that avoids using globals.
* Always use this instead of the global RNG unless you have a good reason,
* the global RNG is not thread safe and will not give repeatable results.
*/
@@ -42,19 +43,34 @@ struct RNG_THREAD_ARRAY;
typedef struct RNG_THREAD_ARRAY RNG_THREAD_ARRAY;
struct RNG *BLI_rng_new(unsigned int seed);
+/**
+ * A version of #BLI_rng_new that hashes the seed.
+ */
struct RNG *BLI_rng_new_srandom(unsigned int seed);
struct RNG *BLI_rng_copy(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
+/**
+ * Use a hash table to create better seed.
+ */
void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1, 2);
int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]) ATTR_NONNULL(1, 2);
void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]) ATTR_NONNULL(1, 2);
+/**
+ * Generate a random point inside given tri.
+ */
void BLI_rng_get_tri_sample_float_v2(struct RNG *rng,
const float v1[2],
const float v2[2],
@@ -75,9 +91,16 @@ void BLI_rng_shuffle_bitmap(struct RNG *rng, unsigned int *bitmap, unsigned int
ATTR_NONNULL(1, 2);
/** Note that skipping is as slow as generating n numbers! */
+/**
+ * Simulate getting \a n random values.
+ *
+ * \note Useful when threaded code needs consistent values, independent of task division.
+ */
void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1);
-/* fill an array with random numbers */
+/**
+ * Fill an array with random numbers.
+ */
void BLI_array_frand(float *ar, int count, unsigned int seed);
/** Return a pseudo-random (hash) float from an integer value */
diff --git a/source/blender/blenlib/BLI_rand.hh b/source/blender/blenlib/BLI_rand.hh
index 0c0dd464d4d..cc9e9b374d7 100644
--- a/source/blender/blenlib/BLI_rand.hh
+++ b/source/blender/blenlib/BLI_rand.hh
@@ -47,6 +47,9 @@ class RandomNumberGenerator {
x_ = (static_cast<uint64_t>(seed) << 16) | lowseed;
}
+ /**
+ * Set a randomized hash of the value as seed.
+ */
void seed_random(uint32_t seed);
uint32_t get_uint32()
@@ -117,6 +120,9 @@ class RandomNumberGenerator {
float2 get_unit_float2();
float3 get_unit_float3();
+ /**
+ * Generate a random point inside the given triangle.
+ */
float2 get_triangle_sample(float2 v1, float2 v2, float2 v3);
float3 get_triangle_sample_3d(float3 v1, float3 v2, float3 v3);
void get_bytes(MutableSpan<char> r_bytes);
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index fb52436587f..f4b1d051d16 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -34,12 +34,28 @@ struct rcti;
extern "C" {
#endif
+/**
+ * Determine if a `rect` is empty.
+ * An empty `rect` is one with a zero (or negative) width or height.
+ *
+ * \return True if \a rect is empty.
+ */
bool BLI_rcti_is_empty(const struct rcti *rect);
bool BLI_rctf_is_empty(const struct rctf *rect);
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
+/**
+ * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ * If this returns false, #BLI_rctf_sanitize() can be called to address this.
+ *
+ * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
+ * have max < min. Usually this is what you'd want though.
+ */
bool BLI_rctf_is_valid(const struct rctf *rect);
bool BLI_rcti_is_valid(const struct rcti *rect);
+/**
+ * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
+ */
void BLI_rctf_sanitize(struct rctf *rect);
void BLI_rcti_sanitize(struct rcti *rect);
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size);
@@ -48,11 +64,21 @@ void BLI_rcti_init_minmax(struct rcti *rect);
void BLI_rctf_init_minmax(struct rctf *rect);
void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]);
void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2]);
+void BLI_rcti_do_minmax_rcti(struct rcti *rect, const struct rcti *other);
+/**
+ * Given 2 rectangles, transform a point from one to another.
+ */
void BLI_rctf_transform_pt_v(const rctf *dst,
const rctf *src,
float xy_dst[2],
const float xy_src[2]);
+/**
+ * Calculate a 4x4 matrix representing the transformation between two rectangles.
+ *
+ * \note Multiplying a vector by this matrix does *not*
+ * give the same value as #BLI_rctf_transform_pt_v.
+ */
void BLI_rctf_transform_calc_m4_pivot_min_ex(
const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y);
void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]);
@@ -62,7 +88,13 @@ void BLI_rcti_translate(struct rcti *rect, int x, int y);
void BLI_rcti_recenter(struct rcti *rect, int x, int y);
void BLI_rctf_recenter(struct rctf *rect, float x, float y);
void BLI_rcti_resize(struct rcti *rect, int x, int y);
+/**
+ * Change width & height around the central X location.
+ */
void BLI_rcti_resize_x(struct rcti *rect, int x);
+/**
+ * Change width & height around the central Y location.
+ */
void BLI_rcti_resize_y(struct rcti *rect, int y);
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y);
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y);
@@ -82,6 +114,14 @@ void BLI_rctf_interp(struct rctf *rect,
// void BLI_rcti_interp(struct rctf *rect, struct rctf *rect_a, struct rctf *rect_b, float fac);
bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]);
bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]);
+/**
+ * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
+ *
+ * Keeps the top left corner within the bounds, which for user interface
+ * elements is typically where the most important information is.
+ *
+ * \return true if a change is made.
+ */
bool BLI_rctf_clamp(struct rctf *rect, const struct rctf *rect_bounds, float r_xy[2]);
bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2]);
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit);
@@ -100,7 +140,13 @@ bool BLI_rctf_isect_x(const rctf *rect, const float x);
bool BLI_rctf_isect_y(const rctf *rect, const float y);
bool BLI_rctf_isect_pt(const struct rctf *rect, const float x, const float y);
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2]);
+/**
+ * \returns shortest distance from \a rect to x (0 if inside)
+ */
int BLI_rcti_length_x(const rcti *rect, const int x);
+/**
+ * \returns shortest distance from \a rect to y (0 if inside)
+ */
int BLI_rcti_length_y(const rcti *rect, const int y);
float BLI_rctf_length_x(const rctf *rect, const float x);
float BLI_rctf_length_y(const rctf *rect, const float y);
@@ -109,14 +155,20 @@ bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const fl
bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], const float radius);
bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], const float radius);
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b);
+/**
+ * is \a rct_b inside \a rct_a
+ */
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b);
-void BLI_rcti_union(struct rcti *rct1, const struct rcti *rct2);
-void BLI_rctf_union(struct rctf *rct1, const struct rctf *rct2);
+void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b);
+void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b);
void BLI_rcti_rctf_copy(struct rcti *dst, const struct rctf *src);
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src);
void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src);
void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src);
+/**
+ * Expand the rectangle to fit a rotated \a src.
+ */
void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle);
void print_rctf(const char *str, const struct rctf *rect);
diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h
index 8f281023177..744d30397d4 100644
--- a/source/blender/blenlib/BLI_scanfill.h
+++ b/source/blender/blenlib/BLI_scanfill.h
@@ -123,6 +123,12 @@ void BLI_scanfill_begin_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
void BLI_scanfill_end_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
/* scanfill_utils.c */
+
+/**
+ * Call before scan-fill to remove self intersections.
+ *
+ * \return false if no changes were made.
+ */
bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx,
ListBase *fillvertbase,
ListBase *filledgebase);
diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h
index f7aec716e9e..9492a252fed 100644
--- a/source/blender/blenlib/BLI_smallhash.h
+++ b/source/blender/blenlib/BLI_smallhash.h
@@ -34,8 +34,10 @@ typedef struct {
void *val;
} SmallHashEntry;
-/* How much stack space to use before dynamically allocating memory.
- * set to match one of the values in 'hashsizes' to avoid too many mallocs. */
+/**
+ * How much stack space to use before dynamically allocating memory.
+ * set to match one of the values in 'hashsizes' to avoid too many mallocs.
+ */
#define SMSTACKSIZE 131
typedef struct SmallHash {
unsigned int nbuckets;
@@ -53,8 +55,18 @@ typedef struct {
void BLI_smallhash_init_ex(SmallHash *sh, const unsigned int nentries_reserve) ATTR_NONNULL(1);
void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1);
+/**
+ * \note does *not* free *sh itself! only the direct data!
+ */
void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1);
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
+/**
+ * Inserts a new value to a key that may already be in ghash.
+ *
+ * Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups)
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
@@ -74,6 +86,12 @@ void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr
/* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */
#ifdef DEBUG
+/**
+ * Measure how well the hash function performs
+ * (1.0 is perfect - no stepping needed).
+ *
+ * Smaller is better!
+ */
double BLI_smallhash_calc_quality(SmallHash *sh);
#endif
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index b00bc0a2e57..653f5f61c9e 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -31,24 +31,73 @@ typedef struct BLI_Stack BLI_Stack;
BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
const char *description,
const size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Create a new homogeneous stack with elements of 'elem_size' bytes.
+ */
BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Free the stack's data and the stack itself
+ */
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL();
+/**
+ * Push a new item onto the stack.
+ *
+ * \return a pointer #BLI_Stack.elem_size
+ * bytes of uninitialized memory (caller must fill in).
+ */
void *BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Copies the source value onto the stack
+ *
+ * \note This copies #BLI_Stack.elem_size bytes from \a src,
+ * (the pointer itself is not stored).
+ *
+ * \param src: source data to be copied to the stack.
+ */
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL();
+/**
+ * A version of #BLI_stack_pop which fills in an array.
+ *
+ * \param dst: The destination array,
+ * must be at least (#BLI_Stack.elem_size * \a n) bytes long.
+ * \param n: The number of items to pop.
+ *
+ * \note The first item in the array will be last item added to the stack.
+ */
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
+/**
+ * A version of #BLI_stack_pop_n which fills in an array (in the reverse order).
+ *
+ * \note The first item in the array will be first item added to the stack.
+ */
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
+/**
+ * Retrieves and removes the top element from the stack.
+ * The value is copies to \a dst, which must be at least \a elem_size bytes.
+ *
+ * Does not reduce amount of allocated memory.
+ */
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL();
void *BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Removes the top element from the stack.
+ */
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL();
+/**
+ * Discards all elements without freeing.
+ */
void BLI_stack_clear(BLI_Stack *stack) ATTR_NONNULL();
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the stack is empty, false otherwise
+ */
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index d3dc05edd9e..91cc7b23a5f 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -33,23 +33,78 @@
extern "C" {
#endif
+/**
+ * Duplicates the first \a len bytes of cstring \a str
+ * into a newly mallocN'd string and returns it. \a str
+ * is assumed to be at least len bytes long.
+ *
+ * \param str: The string to be duplicated
+ * \param len: The number of bytes to duplicate
+ * \retval Returns the duplicated string
+ */
char *BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Duplicates the cstring \a str into a newly mallocN'd
+ * string and returns it.
+ *
+ * \param str: The string to be duplicated
+ * \retval Returns the duplicated string
+ */
char *BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC;
+/**
+ * Appends the two strings, and returns new mallocN'ed string
+ * \param str1: first string for copy
+ * \param str2: second string for append
+ * \retval Returns dst
+ */
char *BLI_strdupcat(const char *__restrict str1,
const char *__restrict str2) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
+/**
+ * Like strncpy but ensures dst is always
+ * '\0' terminated.
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param maxncpy: Maximum number of characters to copy (generally
+ * the size of dst)
+ * \retval Returns dst
+ */
char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
ATTR_NONNULL();
+/**
+ * Like BLI_strncpy but ensures dst is always padded by given char,
+ * on both sides (unless src is empty).
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param pad: the char to use for padding
+ * \param maxncpy: Maximum number of characters to copy (generally the size of dst)
+ * \retval Returns dst
+ */
char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src,
const char pad,
size_t maxncpy) ATTR_NONNULL();
+/**
+ * Like strncpy but ensures dst is always
+ * '\0' terminated.
+ *
+ * \note This is a duplicate of #BLI_strncpy that returns bytes copied.
+ * And is a drop in replacement for 'snprintf(str, sizeof(str), "%s", arg);'
+ *
+ * \param dst: Destination for copy
+ * \param src: Source string to copy
+ * \param maxncpy: Maximum number of characters to copy (generally
+ * the size of dst)
+ * \retval The number of bytes copied (The only difference from BLI_strncpy).
+ */
size_t BLI_strncpy_rlen(char *__restrict dst,
const char *__restrict src,
const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -57,6 +112,18 @@ size_t BLI_strncpy_rlen(char *__restrict dst,
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return the range of the quoted string (excluding quotes) `str` after `prefix`.
+ *
+ * A version of #BLI_str_quoted_substrN that calculates the range
+ * instead of un-escaping and allocating the result.
+ *
+ * \param str: String potentially including `prefix`.
+ * \param prefix: Quoted string prefix.
+ * \param r_start: The start of the quoted string (after the first quote).
+ * \param r_end: The end of the quoted string (before the last quote).
+ * \return True when a quoted string range could be found after `prefix`.
+ */
bool BLI_str_quoted_substr_range(const char *__restrict str,
const char *__restrict prefix,
int *__restrict r_start,
@@ -67,91 +134,328 @@ char *BLI_str_quoted_substrN(const char *__restrict str,
const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
#endif
+/**
+ * Fills \a result with text within "" that appear after some the contents of \a prefix.
+ * i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
+ *
+ * \param str: is the entire string to chop.
+ * \param prefix: is the part of the string to step over.
+ * \param result: The buffer to fill.
+ * \param result_maxlen: The maximum size of the buffer (including nil terminator).
+ * \return True if the prefix was found and the entire quoted string was copied into result.
+ *
+ * Assume that the strings returned must be freed afterwards,
+ * and that the inputs will contain data we want.
+ */
bool BLI_str_quoted_substr(const char *__restrict str,
const char *__restrict prefix,
char *result,
size_t result_maxlen);
+/**
+ * string with all instances of substr_old replaced with substr_new,
+ * Returns a copy of the c-string \a str into a newly #MEM_mallocN'd
+ * and returns it.
+ *
+ * \note A rather wasteful string-replacement utility, though this shall do for now.
+ * Feel free to replace this with an even safe + nicer alternative
+ *
+ * \param str: The string to replace occurrences of substr_old in
+ * \param substr_old: The text in the string to find and replace
+ * \param substr_new: The text in the string to find and replace
+ * \retval Returns the duplicated string
+ */
char *BLI_str_replaceN(const char *__restrict str,
const char *__restrict substr_old,
const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC;
-void BLI_str_replace_char(char *string, char src, char dst) ATTR_NONNULL();
+/**
+ * In-place replace every \a src to \a dst in \a str.
+ *
+ * \param str: The string to operate on.
+ * \param src: The character to replace.
+ * \param dst: The character to replace with.
+ */
+void BLI_str_replace_char(char *str, char src, char dst) ATTR_NONNULL();
+/**
+ * Simple exact-match string replacement.
+ *
+ * \param replace_table: Array of source, destination pairs.
+ *
+ * \note Larger tables should use a hash table.
+ */
bool BLI_str_replace_table_exact(char *string,
const size_t string_len,
const char *replace_table[][2],
int replace_table_len);
+/**
+ * Portable replacement for #snprintf
+ */
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
+/**
+ * A version of #BLI_snprintf that returns `strlen(dst)`
+ */
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
+/**
+ * Portable replacement for `vsnprintf`.
+ */
size_t BLI_vsnprintf(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0);
+/**
+ * A version of #BLI_vsnprintf that returns `strlen(buffer)`
+ */
size_t BLI_vsnprintf_rlen(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0);
+/**
+ * Print formatted string into a newly #MEM_mallocN'd string
+ * and return it.
+ */
char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
+/**
+ * This roughly matches C and Python's string escaping with double quotes - `"`.
+ *
+ * Since every character may need escaping,
+ * it's common to create a buffer twice as large as the input.
+ *
+ * \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`.
+ * \param src: The un-escaped source string.
+ * \param dst_maxncpy: The maximum number of bytes allowable to copy.
+ *
+ * \note This is used for creating animation paths in blend files.
+ */
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
ATTR_NONNULL();
+/**
+ * This roughly matches C and Python's string escaping with double quotes - `"`.
+ *
+ * The destination will never be larger than the source, it will either be the same
+ * or up to half when all characters are escaped.
+ *
+ * \param dst: The destination string, at least the size of `strlen(src) + 1`.
+ * \param src: The escaped source string.
+ * \param src_maxncpy: The maximum number of bytes allowable to copy from `src`.
+ * \param dst_maxncpy: The maximum number of bytes allowable to copy into `dst`.
+ * \param r_is_complete: Set to true when
+ */
size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src,
const size_t src_maxncpy,
/* Additional arguments. */
const size_t dst_maxncpy,
bool *r_is_complete) ATTR_NONNULL();
+/**
+ * See #BLI_str_unescape_ex doc-string.
+ *
+ * This function makes the assumption that `dst` always has
+ * at least `src_maxncpy` bytes available.
+ *
+ * Use #BLI_str_unescape_ex if `dst` has a smaller fixed size.
+ *
+ * \note This is used for parsing animation paths in blend files (runs often).
+ */
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
ATTR_NONNULL();
+/**
+ * Find the first un-escaped quote in the string (to find the end of the string).
+ *
+ * \param str: Typically this is the first character in a quoted string.
+ * Where the character before `*str` would be `"`.
+
+ * \return The pointer to the first un-escaped quote.
+ */
const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL();
+/**
+ * Format ints with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst: The resulting string
+ * \param num: Number to format
+ * \return The length of \a dst
+ */
size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
+/**
+ * Format uint64_t with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst: The resulting string
+ * \param num: Number to format
+ * \return The length of \a dst
+ */
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();
+/**
+ * Format a size in bytes using binary units.
+ * 1000 -> 1 KB
+ * Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
+ *
+ * \param dst: The resulting string.
+ * Dimension of 14 to support largest possible value for \a bytes (#LLONG_MAX).
+ * \param bytes: Number to format.
+ * \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
+ */
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
ATTR_NONNULL();
+/**
+ * Format a count to up to 6 places (plus '\0' terminator) string using long number
+ * names abbreviations. Used to produce a compact representation of large numbers.
+ *
+ * 1 -> 1
+ * 15 -> 15
+ * 155 -> 155
+ * 1555 -> 1.6K
+ * 15555 -> 15.6K
+ * 155555 -> 156K
+ * 1555555 -> 1.6M
+ * 15555555 -> 15.6M
+ * 155555555 -> 156M
+ * 1000000000 -> 1B
+ * ...
+ *
+ * Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
+ */
void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) ATTR_NONNULL();
+/**
+ * Compare two strings without regard to case.
+ *
+ * \retval True if the strings are equal, false otherwise.
+ */
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Portable replacement for `strcasestr` (not available in MSVC)
+ */
char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Variation of #BLI_strcasestr with string length limited to \a len
+ */
char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Case insensitive, *natural* string comparison,
+ * keeping numbers in order.
+ */
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Like strcmp, but will ignore any heading/trailing pad char for comparison.
+ * So e.g. if pad is '*', '*world' and 'world*' will compare equal.
+ */
int BLI_strcmp_ignore_pad(const char *str1,
const char *str2,
const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Determine the length of a fixed-size string.
+ */
size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BLI_str_tolower_ascii(char *str, const size_t len) ATTR_NONNULL();
void BLI_str_toupper_ascii(char *str, const size_t len) ATTR_NONNULL();
+/**
+ * Strip white-space from end of the string.
+ */
void BLI_str_rstrip(char *str) ATTR_NONNULL();
+/**
+ * Strip trailing zeros from a float, eg:
+ * 0.0000 -> 0.0
+ * 2.0010 -> 2.001
+ *
+ * \param str:
+ * \param pad:
+ * \return The number of zeros stripped.
+ */
int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL();
+/**
+ * Return index of a string in a string array.
+ *
+ * \param str: The string to find.
+ * \param str_array: Array of strings.
+ * \param str_array_len: The length of the array, or -1 for a NULL-terminated array.
+ * \return The index of str in str_array or -1.
+ */
int BLI_str_index_in_array_n(const char *__restrict str,
const char **__restrict str_array,
const int str_array_len) ATTR_NONNULL();
+/**
+ * Return index of a string in a string array.
+ *
+ * \param str: The string to find.
+ * \param str_array: Array of strings, (must be NULL-terminated).
+ * \return The index of str in str_array or -1.
+ */
int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
ATTR_NONNULL();
+/**
+ * Find if a string starts with another string.
+ *
+ * \param str: The string to search within.
+ * \param start: The string we look for at the start.
+ * \return If str starts with start.
+ */
bool BLI_str_startswith(const char *__restrict str, const char *__restrict start) ATTR_NONNULL();
+/**
+ * Find if a string ends with another string.
+ *
+ * \param str: The string to search within.
+ * \param end: The string we look for at the end.
+ * \return If str ends with end.
+ */
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL();
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, from left.
+ *
+ * \param str: The string to search within.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, from right.
+ *
+ * \param str: The string to search within.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL();
+/**
+ * Find the first char matching one of the chars in \a delim, either from left or right.
+ *
+ * \param str: The string to search within.
+ * \param end: If non-NULL, the right delimiter of the string.
+ * \param delim: The set of delimiters to search for, as unicode values.
+ * \param sep: Return value, set to the first delimiter found (or NULL if none found).
+ * \param suf: Return value, set to next char after the first delimiter found
+ * (or NULL if none found).
+ * \param from_right: If %true, search from the right of \a str, else, search from its left.
+ * \return The length of the prefix (i.e. *sep - str).
+ */
size_t BLI_str_partition_ex(const char *str,
const char *end,
const char delim[],
@@ -166,6 +470,16 @@ bool BLI_string_all_words_matched(const char *name,
int (*words)[2],
const int words_len);
+/**
+ * Find the ranges needed to split \a str into its individual words.
+ *
+ * \param str: The string to search for words.
+ * \param len: Size of the string to search.
+ * \param delim: Character to use as a delimiter.
+ * \param r_words: Info about the words found. Set to [index, len] pairs.
+ * \param words_max: Max number of words to find
+ * \return The number of words found in \a str
+ */
int BLI_string_find_split_words(const char *str,
const size_t len,
const char delim,
@@ -177,6 +491,7 @@ int BLI_string_find_split_words(const char *str,
* Avoid repeating destination with `sizeof(..)`.
* \note `ARRAY_SIZE` allows pointers on some platforms.
* \{ */
+
#define STRNCPY(dst, src) BLI_strncpy(dst, src, ARRAY_SIZE(dst))
#define STRNCPY_RLEN(dst, src) BLI_strncpy_rlen(dst, src, ARRAY_SIZE(dst))
#define SNPRINTF(dst, format, ...) BLI_snprintf(dst, ARRAY_SIZE(dst), format, __VA_ARGS__)
@@ -186,6 +501,7 @@ int BLI_string_find_split_words(const char *str,
len += BLI_strncpy_rlen(dst + len, suffix, ARRAY_SIZE(dst) - len)
#define STR_CONCATF(dst, len, format, ...) \
len += BLI_snprintf_rlen(dst + len, ARRAY_SIZE(dst) - len, format, __VA_ARGS__)
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/BLI_string_search.h b/source/blender/blenlib/BLI_string_search.h
index 8057e5b75cb..f0bf259d213 100644
--- a/source/blender/blenlib/BLI_string_search.h
+++ b/source/blender/blenlib/BLI_string_search.h
@@ -23,7 +23,19 @@ extern "C" {
typedef struct StringSearch StringSearch;
StringSearch *BLI_string_search_new(void);
-void BLI_string_search_add(StringSearch *search, const char *str, void *user_data);
+/**
+ * Add a new possible result to the search.
+ * The caller keeps ownership of all parameters.
+ *
+ * \param weight: Can be used to customize the order when multiple items have the same match score.
+ */
+void BLI_string_search_add(StringSearch *search, const char *str, void *user_data, int weight);
+
+/**
+ * Filter and sort all previously added search items.
+ * Returns an array containing the filtered user data.
+ * The caller has to free the returned array.
+ */
int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data);
void BLI_string_search_free(StringSearch *search);
@@ -40,8 +52,24 @@ void BLI_string_search_free(StringSearch *search);
namespace blender::string_search {
+/**
+ * Computes the cost of transforming string a into b. The cost/distance is the minimal number of
+ * operations that need to be executed. Valid operations are deletion, insertion, substitution and
+ * transposition.
+ *
+ * This function is utf8 aware in the sense that it works at the level of individual code points
+ * (1-4 bytes long) instead of on individual bytes.
+ */
int damerau_levenshtein_distance(StringRef a, StringRef b);
+/**
+ * Returns -1 when this is no reasonably good match.
+ * Otherwise returns the number of errors in the match.
+ */
int get_fuzzy_match_errors(StringRef query, StringRef full);
+/**
+ * Splits a string into words and normalizes them (currently that just means converting to lower
+ * case). The returned strings are allocated in the given allocator.
+ */
void extract_normalized_words(StringRef str,
LinearAllocator<> &allocator,
Vector<StringRef, 64> &r_words);
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index bf7547cc90b..72bddb322db 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -32,23 +32,84 @@ char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t
size_t BLI_strncpy_utf8_rlen(char *__restrict dst,
const char *__restrict src,
size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Find first UTF-8 invalid byte in given \a str, of \a length bytes.
+ *
+ * \return the offset of the first invalid byte.
+ */
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(1);
+/**
+ * Remove any invalid UTF-8 byte (taking into account multi-bytes sequence of course).
+ *
+ * \return number of stripped bytes.
+ */
int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1);
-/* warning, can return -1 on bad chars */
+/**
+ * \return The size (in bytes) of a single UTF-8 char.
+ * \warning Can return -1 on bad chars.
+ */
int BLI_str_utf8_size(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Use when we want to skip errors.
+ */
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* copied from glib */
+/**
+ * \param p: a pointer to Unicode character encoded as UTF-8
+ *
+ * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
+ * If \a p does not point to a valid UTF-8 encoded character, results are
+ * undefined. If you are not sure that the bytes are complete
+ * valid Unicode characters, you should use g_utf8_get_char_validated()
+ * instead.
+ *
+ * Return value: the resulting character
+ */
unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * UTF8 decoding that steps over the index (unless an error is encountered).
+ *
+ * \param p: The text to step over.
+ * \param p_len: The length of `p`.
+ * \param index: Index of `p` to step over.
+ * \return the code-point `(p + *index)` if there is a decoding error.
+ *
+ * \note Falls back to `LATIN1` for text drawing.
+ */
unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p,
size_t p_len,
size_t *__restrict index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 3);
+/**
+ * UTF8 decoding that steps over the index (unless an error is encountered).
+ *
+ * \param p: The text to step over.
+ * \param p_len: The length of `p`.
+ * \param index: Index of `p` to step over.
+ * \return the code-point or #BLI_UTF8_ERR if there is a decoding error.
+ *
+ * \note The behavior for clipped text (where `p_len` limits decoding trailing bytes)
+ * must have the same behavior is encountering a nil byte,
+ * so functions that only use the first part of a string has matching behavior to functions
+ * that null terminate the text.
+ */
unsigned int BLI_str_utf8_as_unicode_step_or_error(
const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 3);
size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT;
+/**
+ * BLI_str_utf8_from_unicode:
+ *
+ * \param c: a Unicode character code
+ * \param outbuf: output buffer, must have at least `outbuf_len` bytes of space.
+ * If the length required by `c` exceeds `outbuf_len`,
+ * the bytes available bytes will be zeroed and `outbuf_len` returned.
+ *
+ * Converts a single character to UTF-8.
+ *
+ * \return number of bytes written.
+ */
size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf, const size_t outbuf_len)
ATTR_NONNULL(2);
size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w,
@@ -57,19 +118,57 @@ size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w,
size_t BLI_str_utf32_as_utf8(char *__restrict dst,
const char32_t *__restrict src,
const size_t maxncpy) ATTR_NONNULL(1, 2);
+/**
+ * \return The UTF-32 len in UTF-8.
+ */
size_t BLI_str_utf32_as_utf8_len(const char32_t *src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * BLI_str_find_prev_char_utf8:
+ * \param p: pointer to some position within \a str
+ * \param str_start: pointer to the beginning of a UTF-8 encoded string
+ *
+ * Given a position \a p with a UTF-8 encoded string \a str, find the start
+ * of the previous UTF-8 character starting before. \a p Returns \a str_start if no
+ * UTF-8 characters are present in \a str_start before \a p.
+ *
+ * \a p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte.
+ *
+ * \return A pointer to the found character.
+ */
const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2);
+/**
+ * \param p: a pointer to a position within a UTF-8 encoded string
+ * \param str_end: a pointer to the byte following the end of the string.
+ *
+ * Finds the start of the next UTF-8 character in the string after \a p
+ *
+ * \a p does not have to be at the beginning of a UTF-8 character. No check
+ * is made to see if the character found is actually valid other than
+ * it starts with an appropriate byte.
+ *
+ * \return a pointer to the found character or a pointer to the null terminating character '\0'.
+ */
const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2);
+/**
+ * \return the `wchar_t` length in UTF-8.
+ */
size_t BLI_wstrlen_utf8(const wchar_t *src) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_bytes)
ATTR_NONNULL(1, 3);
+/**
+ * \param strc: the string to measure the length.
+ * \param maxlen: the string length (in bytes)
+ * \return the unicode length (not in bytes!)
+ */
size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
@@ -79,10 +178,14 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst,
const char *__restrict src,
const size_t maxncpy) ATTR_NONNULL(1, 2);
-/* count columns that character/string occupies, based on wcwidth.c */
+/**
+ * Count columns that character/string occupies (based on `wcwidth.co`).
+ */
int BLI_wcwidth(char32_t ucs) ATTR_WARN_UNUSED_RESULT;
int BLI_wcswidth(const char32_t *pwcs, size_t n) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-/* warning, can return -1 on bad chars */
+/**
+ * \warning can return -1 on bad chars.
+ */
int BLI_str_utf8_char_width(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
@@ -111,7 +214,8 @@ int BLI_str_utf8_offset_to_column(const char *str, int offset) ATTR_WARN_UNUSED_
int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
-#define BLI_UTF8_MAX 6 /* mem */
+/** Size in bytes. */
+#define BLI_UTF8_MAX 6
#define BLI_UTF8_WIDTH_MAX 2 /* columns */
#define BLI_UTF8_ERR ((unsigned int)-1)
@@ -120,8 +224,10 @@ int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSE
* Avoid repeating destination with `sizeof(..)`.
* \note `ARRAY_SIZE` allows pointers on some platforms.
* \{ */
+
#define STRNCPY_UTF8(dst, src) BLI_strncpy_utf8(dst, src, ARRAY_SIZE(dst))
#define STRNCPY_UTF8_RLEN(dst, src) BLI_strncpy_utf8_rlen(dst, src, ARRAY_SIZE(dst))
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
index 277bb6fac05..ce4d0afb933 100644
--- a/source/blender/blenlib/BLI_string_utils.h
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -36,33 +36,71 @@ struct ListBase;
typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
+/**
+ * Looks for a numeric suffix preceded by `delim` character on the end of
+ * name, puts preceding part into *left and value of suffix into *nr.
+ * Returns the length of *left.
+ *
+ * Foo.001 -> "Foo", 1
+ * Returning the length of "Foo"
+ *
+ * \param left: Where to return copy of part preceding `delim`.
+ * \param nr: Where to return value of numeric suffix`.
+ * \param name: String to split`.
+ * \param delim: Delimiter character`.
+ * \return Length of \a left.
+ */
size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
bool BLI_string_is_decimal(const char *string) ATTR_NONNULL();
+/**
+ * Based on `BLI_split_dirfile()` / `os.path.splitext()`,
+ * `"a.b.c"` -> (`"a.b"`, `".c"`).
+ */
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
+/**
+ * `"a.b.c"` -> (`"a."`, `"b.c"`).
+ */
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
-/* Join strings, return newly allocated string. */
+/**
+ * Join strings, return newly allocated string.
+ */
char *BLI_string_join_array(char *result,
size_t result_len,
const char *strings[],
uint strings_len) ATTR_NONNULL();
+/**
+ * A version of #BLI_string_join that takes a separator which can be any character including '\0'.
+ */
char *BLI_string_join_array_by_sep_char(char *result,
size_t result_len,
char sep,
const char *strings[],
uint strings_len) ATTR_NONNULL();
+/**
+ * Join an array of strings into a newly allocated, null terminated string.
+ */
char *BLI_string_join_arrayN(const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
+ */
char *BLI_string_join_array_by_sep_charN(char sep,
const char *strings[],
uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
+ * The new location of each string is written into this array.
+ */
char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
char *table[],
const char *strings[],
uint strings_len) ATTR_NONNULL();
-/* Take multiple arguments, pass as (array, length). */
+/**
+ * Take multiple arguments, pass as (array, length).
+ */
#define BLI_string_join(result, result_len, ...) \
BLI_string_join_array( \
result, result_len, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
@@ -75,23 +113,57 @@ char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
BLI_string_join_array_by_sep_char_with_tableN( \
sep, table, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
+/**
+ * Finds the best possible flipped (left/right) name.
+ * For renaming; check for unique names afterwards.
+ *
+ * \param r_name: flipped name,
+ * assumed to be a pointer to a string of at least \a name_len size.
+ * \param from_name: original name,
+ * assumed to be a pointer to a string of at least \a name_len size.
+ * \param strip_number: If set, remove number extensions.
+ * \return The number of bytes written into \a r_name.
+ */
size_t BLI_string_flip_side_name(char *r_name,
const char *from_name,
const bool strip_number,
const size_t name_len);
+/**
+ * Ensures name is unique (according to criteria specified by caller in unique_check callback),
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param unique_check: Return true if name is not unique
+ * \param arg: Additional arg to unique_check--meaning is up to caller
+ * \param defname: To initialize name if latter is empty
+ * \param delim: Delimits numeric suffix in name
+ * \param name: Name to be ensured unique
+ * \param name_len: Maximum length of name area
+ * \return true if there if the name was changed
+ */
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
void *arg,
const char *defname,
char delim,
char *name,
size_t name_len);
+/**
+ * Ensures that the specified block has a unique name within the containing list,
+ * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
+ *
+ * \param list: List containing the block
+ * \param vlink: The block to check the name for
+ * \param defname: To initialize block name if latter is empty
+ * \param delim: Delimits numeric suffix in name
+ * \param name_offset: Offset of name within block structure
+ * \param name_len: Maximum length of name area
+ */
bool BLI_uniquename(struct ListBase *list,
void *vlink,
const char *defname,
char delim,
int name_offset,
- size_t len);
+ size_t name_len);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 53ac5f7047b..a67de2e2910 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -35,20 +35,24 @@ extern "C" {
struct BLI_mempool;
-/* Task Scheduler
+/* -------------------------------------------------------------------- */
+/** \name Task Scheduler
*
- * Central scheduler that holds running threads ready to execute tasks. A single
- * queue holds the task from all pools.
+ * Central scheduler that holds running threads ready to execute tasks.
+ * A single queue holds the task from all pools.
*
- * Init/exit must be called before/after any task pools are created/freed, and
- * must be called from the main threads. All other scheduler and pool functions
- * are thread-safe. */
+ * Initialize/exit must be called before/after any task pools are created/freed, and must
+ * be called from the main threads. All other scheduler and pool functions are thread-safe.
+ * \{ */
void BLI_task_scheduler_init(void);
void BLI_task_scheduler_exit(void);
int BLI_task_scheduler_num_threads(void);
-/* Task Pool
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Pool
*
* Pool of tasks that will be executed by the central task scheduler. For each
* pool, we can wait for all tasks to be done, or cancel them before they are
@@ -60,7 +64,7 @@ int BLI_task_scheduler_num_threads(void);
* pool with smaller tasks. When other threads are busy they will continue
* working on their own tasks, if not they will join in, no new threads will
* be launched.
- */
+ * \{ */
typedef enum eTaskPriority {
TASK_PRIORITY_LOW,
@@ -71,25 +75,34 @@ typedef struct TaskPool TaskPool;
typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata);
typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata);
-/* Regular task pool that immediately starts executing tasks as soon as they
- * are pushed, either on the current or another thread. */
+/**
+ * Regular task pool that immediately starts executing tasks as soon as they
+ * are pushed, either on the current or another thread.
+ */
TaskPool *BLI_task_pool_create(void *userdata, eTaskPriority priority);
-/* Background: always run tasks in a background thread, never immediately
- * execute them. For running background jobs. */
+/**
+ * Background: always run tasks in a background thread, never immediately
+ * execute them. For running background jobs.
+ */
TaskPool *BLI_task_pool_create_background(void *userdata, eTaskPriority priority);
-/* Background Serial: run tasks one after the other in the background,
- * without parallelization between the tasks. */
+/**
+ * Background Serial: run tasks one after the other in the background,
+ * without parallelization between the tasks.
+ */
TaskPool *BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority);
-/* Suspended: don't execute tasks until work_and_wait is called. This is slower
+/**
+ * Suspended: don't execute tasks until work_and_wait is called. This is slower
* as threads can't immediately start working. But it can be used if the data
- * structures the threads operate on are not fully initialized until all tasks
- * are created. */
+ * structures the threads operate on are not fully initialized until all tasks are created.
+ */
TaskPool *BLI_task_pool_create_suspended(void *userdata, eTaskPriority priority);
-/* No threads: immediately executes tasks on the same thread. For debugging. */
+/**
+ * No threads: immediately executes tasks on the same thread. For debugging.
+ */
TaskPool *BLI_task_pool_create_no_threads(void *userdata);
void BLI_task_pool_free(TaskPool *pool);
@@ -100,28 +113,45 @@ void BLI_task_pool_push(TaskPool *pool,
bool free_taskdata,
TaskFreeFunction freedata);
-/* work and wait until all tasks are done */
+/**
+ * Work and wait until all tasks are done.
+ */
void BLI_task_pool_work_and_wait(TaskPool *pool);
-/* cancel all tasks, keep worker threads running */
+/**
+ * Cancel all tasks, keep worker threads running.
+ */
void BLI_task_pool_cancel(TaskPool *pool);
-/* for worker threads, test if current task pool canceled. this function may
+/**
+ * For worker threads, test if current task pool canceled. this function may
* only be called from worker threads and pool must be the task pool that the
- * thread is currently executing a task from. */
+ * thread is currently executing a task from.
+ */
bool BLI_task_pool_current_canceled(TaskPool *pool);
-/* optional userdata pointer to pass along to run function */
+/**
+ * Optional `userdata` pointer to pass along to run function.
+ */
void *BLI_task_pool_user_data(TaskPool *pool);
-/* optional mutex to use from run function */
+/**
+ * Optional mutex to use from run function.
+ */
ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
-/* Parallel for routines */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Parallel for Routines
+ * \{ */
-/* Per-thread specific data passed to the callback. */
+/**
+ * Per-thread specific data passed to the callback.
+ */
typedef struct TaskParallelTLS {
- /* Copy of user-specifier chunk, which is copied from original chunk to all
- * worker threads. This is similar to OpenMP's firstprivate.
+ /**
+ * Copy of user-specifier chunk, which is copied from original chunk to all worker threads.
+ * This is similar to OpenMP's `firstprivate`.
*/
void *userdata_chunk;
} TaskParallelTLS;
@@ -186,7 +216,8 @@ void BLI_task_parallel_range(const int start,
TaskParallelRangeFunc func,
const TaskParallelSettings *settings);
-/* This data is shared between all tasks, its access needs thread lock or similar protection.
+/**
+ * This data is shared between all tasks, its access needs thread lock or similar protection.
*/
typedef struct TaskParallelIteratorStateShared {
/* Maximum amount of items to acquire at once. */
@@ -214,6 +245,20 @@ typedef void (*TaskParallelIteratorFunc)(void *__restrict userdata,
int index,
const TaskParallelTLS *__restrict tls);
+/**
+ * This function allows to parallelize for loops using a generic iterator.
+ *
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param iter_func: Callback function used to generate chunks of items.
+ * \param init_item: The initial item, if necessary (may be NULL if unused).
+ * \param init_index: The initial index.
+ * \param tot_items: The total amount of items to iterate over
+ * (if unknown, set it to a negative number).
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note Static scheduling is only available when \a tot_items is >= 0.
+ */
void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorIterFunc iter_func,
void *init_item,
@@ -222,6 +267,17 @@ void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorFunc func,
const TaskParallelSettings *settings);
+/**
+ * This function allows to parallelize for loops over ListBase items.
+ *
+ * \param listbase: The double linked list to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
+ *
+ * \note There is no static scheduling here,
+ * since it would need another full loop over items to count them.
+ */
void BLI_task_parallel_listbase(struct ListBase *listbase,
void *userdata,
TaskParallelIteratorFunc func,
@@ -232,6 +288,16 @@ typedef struct MempoolIterData MempoolIterData;
typedef void (*TaskParallelMempoolFunc)(void *userdata,
MempoolIterData *iter,
const TaskParallelTLS *__restrict tls);
+/**
+ * This function allows to parallelize for loops over Mempool items.
+ *
+ * \param mempool: The iterable BLI_mempool to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note There is no static scheduling here.
+ */
void BLI_task_parallel_mempool(struct BLI_mempool *mempool,
void *userdata,
TaskParallelMempoolFunc func,
@@ -252,14 +318,21 @@ BLI_INLINE void BLI_parallel_mempool_settings_defaults(TaskParallelSettings *set
settings->use_threading = true;
}
-/* Don't use this, store any thread specific data in tls->userdata_chunk instead.
- * Only here for code to be removed. */
+/**
+ * Don't use this, store any thread specific data in `tls->userdata_chunk` instead.
+ * Only here for code to be removed.
+ */
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
-/* Task Graph Scheduling */
-/* Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Graph Scheduling
+ *
+ * Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
* The nodes in the graph can be run in separate threads.
*
+ * \code{.unparsed}
* +---- [root] ----+
* | |
* v v
@@ -267,55 +340,61 @@ int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
* | |
* v v
* [node_3] [node_4]
+ * \endcode
*
- * TaskGraph *task_graph = BLI_task_graph_create();
- * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL);
- * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
- * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * \code{.c}
+ * TaskGraph *task_graph = BLI_task_graph_create();
+ * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL);
+ * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
*
- * BLI_task_graph_edge_create(root, node_1);
- * BLI_task_graph_edge_create(root, node_2);
- * BLI_task_graph_edge_create(node_2, node_3);
- * BLI_task_graph_edge_create(node_2, node_4);
+ * BLI_task_graph_edge_create(root, node_1);
+ * BLI_task_graph_edge_create(root, node_2);
+ * BLI_task_graph_edge_create(node_2, node_3);
+ * BLI_task_graph_edge_create(node_2, node_4);
+ * \endcode
*
* Any node can be triggered to start a chain of tasks. Normally you would trigger a root node but
* it is supported to start the chain of tasks anywhere in the forest or tree. When a node
* completes, the execution flow is forwarded via the created edges.
* When a child node has multiple parents the child node will be triggered once for each parent.
*
- * BLI_task_graph_node_push_work(root);
+ * `BLI_task_graph_node_push_work(root);`
*
* In this example After `root` is finished, `node_1` and `node_2` will be started.
* Only after `node_2` is finished `node_3` and `node_4` will be started.
*
* After scheduling work we need to wait until all the tasks have been finished.
*
- * BLI_task_graph_work_and_wait();
+ * `BLI_task_graph_work_and_wait();`
*
* When finished you can clean up all the resources by freeing the task_graph. Nodes are owned by
* the graph and are freed task_data will only be freed if a free_func was given.
*
- * BLI_task_graph_free(task_graph);
+ * `BLI_task_graph_free(task_graph);`
*
* Work can enter a tree on any node. Normally this would be the root_node.
* A `task_graph` can be reused, but the caller needs to make sure the task_data is reset.
*
- * ** Task-Data **
+ * Task-Data
+ * ---------
*
* Typically you want give a task data to work on.
* Task data can be shared with other nodes, but be careful not to free the data multiple times.
- * Task data is freed when calling `BLI_task_graph_free`.
- *
- * MyData *task_data = MEM_callocN(sizeof(MyData), __func__);
- * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN);
- * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
- * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * Task data is freed when calling #BLI_task_graph_free.
*
- */
+ * \code{.c}
+ * MyData *task_data = MEM_callocN(sizeof(MyData), __func__);
+ * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN);
+ * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * \endcode
+ * \{ */
+
struct TaskGraph;
struct TaskNode;
@@ -332,7 +411,10 @@ struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph,
bool BLI_task_graph_node_push_work(struct TaskNode *task_node);
void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node);
-/* Task Isolation
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Task Isolation
*
* Task isolation helps avoid unexpected task scheduling decisions that can lead to bugs if wrong
* assumptions were made. Typically that happens when doing "nested threading", i.e. one thread
@@ -359,9 +441,12 @@ void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_
* multiple threads, another thread will typically run the task and avoid the deadlock. However, if
* this situation happens on all threads at the same time, all threads will deadlock. This happened
* in T88598.
- */
+ * \{ */
+
void BLI_task_isolate(void (*func)(void *userdata), void *userdata);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_task.hh b/source/blender/blenlib/BLI_task.hh
index da7309837c8..84d5cd39bb4 100644
--- a/source/blender/blenlib/BLI_task.hh
+++ b/source/blender/blenlib/BLI_task.hh
@@ -67,14 +67,19 @@ void parallel_for(IndexRange range, int64_t grain_size, const Function &function
return;
}
#ifdef WITH_TBB
- tbb::parallel_for(tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
- [&](const tbb::blocked_range<int64_t> &subrange) {
- function(IndexRange(subrange.begin(), subrange.size()));
- });
+ /* Invoking tbb for small workloads has a large overhead. */
+ if (range.size() >= grain_size) {
+ tbb::parallel_for(
+ tbb::blocked_range<int64_t>(range.first(), range.one_after_last(), grain_size),
+ [&](const tbb::blocked_range<int64_t> &subrange) {
+ function(IndexRange(subrange.begin(), subrange.size()));
+ });
+ return;
+ }
#else
UNUSED_VARS(grain_size);
- function(range);
#endif
+ function(range);
}
template<typename Value, typename Function, typename Reduction>
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 4f71e3aa6e4..6e60430ea38 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -38,12 +38,24 @@ struct ListBase;
/* Threading API */
-/* This is run once at startup. */
+/**
+ * This is run once at startup.
+ */
void BLI_threadapi_init(void);
void BLI_threadapi_exit(void);
+/**
+ * \param tot: When 0 only initializes malloc mutex in a safe way (see sequence.c)
+ * problem otherwise: scene render will kill of the mutex!
+ */
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot);
+/**
+ * Amount of available threads.
+ */
int BLI_available_threads(struct ListBase *threadbase);
+/**
+ * Returns thread number, for sample patterns or threadsafe tables.
+ */
int BLI_threadpool_available_thread_index(struct ListBase *threadbase);
void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata);
void BLI_threadpool_remove(struct ListBase *threadbase, void *callerdata);
@@ -54,7 +66,10 @@ int BLI_thread_is_main(void);
/* System Information */
-int BLI_system_thread_count(void); /* gets the number of threads the system can make use of */
+/**
+ * \return the number of threads the system can make use of.
+ */
+int BLI_system_thread_count(void);
void BLI_system_num_threads_override_set(int num);
int BLI_system_num_threads_override_get(void);
@@ -198,6 +213,7 @@ void BLI_thread_queue_nowait(ThreadQueue *queue);
/* **** Special functions to help performance on crazy NUMA setups. **** */
/* Make sure process/thread is using NUMA node with fast memory access. */
+
void BLI_thread_put_process_on_fast_node(void);
void BLI_thread_put_thread_on_fast_node(void);
diff --git a/source/blender/blenlib/BLI_timecode.h b/source/blender/blenlib/BLI_timecode.h
index 5dfd9089598..4eec8aef245 100644
--- a/source/blender/blenlib/BLI_timecode.h
+++ b/source/blender/blenlib/BLI_timecode.h
@@ -29,17 +29,49 @@
extern "C" {
#endif
+/**
+ * Generate time-code/frame number string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param brevity_level: special setting for #View2D grid drawing,
+ * used to specify how detailed we need to be
+ * \param time_seconds: time total time in seconds
+ * \param fps: frames per second, typically from the #FPS macro
+ * \param timecode_style: enum from #eTimecodeStyles
+ * \return length of \a str
+ */
size_t BLI_timecode_string_from_time(char *str,
const size_t maxncpy,
const int brevity_level,
const float time_seconds,
- const double scene_fps,
+ const double fps,
const short timecode_style) ATTR_NONNULL();
+/**
+ * Generate time string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param time_seconds: time total time in seconds
+ * \return length of \a str
+ */
size_t BLI_timecode_string_from_time_simple(char *str,
const size_t maxncpy,
const double time_seconds) ATTR_NONNULL();
+/**
+ * Generate time string and store in \a str
+ *
+ * \param str: destination string
+ * \param maxncpy: maximum number of characters to copy `sizeof(str)`
+ * \param brevity_level: special setting for #View2D grid drawing,
+ * used to specify how detailed we need to be
+ * \param time_seconds: time total time in seconds
+ * \return length of \a str
+ *
+ * \note in some cases this is used to print non-seconds values.
+ */
size_t BLI_timecode_string_from_time_seconds(char *str,
const size_t maxncpy,
const int brevity_level,
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index dec8acd7549..1b9457496ef 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -635,6 +635,9 @@ extern "C" {
/* defined
* in memory_utils.c for now. I do not know where we should put it actually... */
#ifndef __BLI_MEMORY_UTILS_H__
+/**
+ * Check if memory is zeroed, as with `memset(arr, 0, arr_size)`.
+ */
extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
#endif
diff --git a/source/blender/blenlib/BLI_uvproject.h b/source/blender/blenlib/BLI_uvproject.h
index 6028d95bda0..c1cc1cdbb51 100644
--- a/source/blender/blenlib/BLI_uvproject.h
+++ b/source/blender/blenlib/BLI_uvproject.h
@@ -26,16 +26,26 @@ extern "C" {
struct Object;
struct ProjCameraInfo;
-/* create uv info from the camera, needs to be freed */
+/**
+ * Create UV info from the camera, needs to be freed.
+ *
+ * \param rotmat: can be `obedit->obmat` when uv project is used.
+ * \param winx, winy: can be from `scene->r.xsch / ysch`.
+ */
struct ProjCameraInfo *BLI_uvproject_camera_info(struct Object *ob,
float rotmat[4][4],
float winx,
float winy);
-/* apply uv from uvinfo (camera) */
+/**
+ * Apply UV from uvinfo (camera).
+ */
void BLI_uvproject_from_camera(float target[2], float source[3], struct ProjCameraInfo *uci);
-/* apply uv from perspective matrix */
+/**
+ * Apply uv from perspective matrix.
+ * \param persmat: Can be `rv3d->persmat`.
+ */
void BLI_uvproject_from_view(float target[2],
float source[3],
float persmat[4][4],
@@ -43,10 +53,14 @@ void BLI_uvproject_from_view(float target[2],
float winx,
float winy);
-/* apply ortho uv's */
+/**
+ * Apply orthographic UV's.
+ */
void BLI_uvproject_from_view_ortho(float target[2], float source[3], const float rotmat[4][4]);
-/* so we can adjust scale with keeping the struct private */
+/**
+ * So we can adjust scale with keeping the struct private.
+ */
void BLI_uvproject_camera_info_scale(struct ProjCameraInfo *uci, float scale_x, float scale_y);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index d9f83d3e1cb..5103ac4b668 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -183,6 +183,15 @@ template<typename T> class VArrayImpl {
* own anything can overwrite this with false. */
return true;
}
+
+ /**
+ * Return true when the other virtual array should be considered to be the same, e.g. because it
+ * shares the same underlying memory.
+ */
+ virtual bool is_same(const VArrayImpl<T> &UNUSED(other)) const
+ {
+ return false;
+ }
};
/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
@@ -223,69 +232,21 @@ template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
};
/**
- * A virtual array implementation for a span. Methods in this class are final so that it can be
- * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used).
- */
-template<typename T> class VArrayImpl_For_Span : public VArrayImpl<T> {
- protected:
- const T *data_ = nullptr;
-
- public:
- VArrayImpl_For_Span(const Span<T> data) : VArrayImpl<T>(data.size()), data_(data.data())
- {
- }
-
- protected:
- VArrayImpl_For_Span(const int64_t size) : VArrayImpl<T>(size)
- {
- }
-
- T get(const int64_t index) const final
- {
- return data_[index];
- }
-
- bool is_span() const final
- {
- return true;
- }
-
- Span<T> get_internal_span() const final
- {
- return Span<T>(data_, this->size_);
- }
-};
-
-/**
- * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the
- * #may_have_ownership method.
- */
-template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> {
- public:
- using VArrayImpl_For_Span<T>::VArrayImpl_For_Span;
-
- private:
- bool may_have_ownership() const override
- {
- return false;
- }
-};
-
-/**
- * Like #VArrayImpl_For_Span but for mutable data.
+ * A virtual array implementation that references that wraps a span. This implementation is used by
+ * mutable and immutable spans to avoid code duplication.
*/
-template<typename T> class VMutableArrayImpl_For_MutableSpan : public VMutableArrayImpl<T> {
+template<typename T> class VArrayImpl_For_Span : public VMutableArrayImpl<T> {
protected:
T *data_ = nullptr;
public:
- VMutableArrayImpl_For_MutableSpan(const MutableSpan<T> data)
+ VArrayImpl_For_Span(const MutableSpan<T> data)
: VMutableArrayImpl<T>(data.size()), data_(data.data())
{
}
protected:
- VMutableArrayImpl_For_MutableSpan(const int64_t size) : VMutableArrayImpl<T>(size)
+ VArrayImpl_For_Span(const int64_t size) : VMutableArrayImpl<T>(size)
{
}
@@ -308,15 +269,27 @@ template<typename T> class VMutableArrayImpl_For_MutableSpan : public VMutableAr
{
return Span<T>(data_, this->size_);
}
+
+ bool is_same(const VArrayImpl<T> &other) const final
+ {
+ if (other.size() != this->size_) {
+ return false;
+ }
+ if (!other.is_span()) {
+ return false;
+ }
+ const Span<T> other_span = other.get_internal_span();
+ return data_ == other_span.data();
+ }
};
/**
- * Like #VArrayImpl_For_Span_final but for mutable data.
+ * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the
+ * #may_have_ownership method.
*/
-template<typename T>
-class VMutableArrayImpl_For_MutableSpan_final final : public VMutableArrayImpl_For_MutableSpan<T> {
+template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> {
public:
- using VMutableArrayImpl_For_MutableSpan<T>::VMutableArrayImpl_For_MutableSpan;
+ using VArrayImpl_For_Span<T>::VArrayImpl_For_Span;
private:
bool may_have_ownership() const override
@@ -340,7 +313,7 @@ class VArrayImpl_For_ArrayContainer : public VArrayImpl_For_Span<T> {
VArrayImpl_For_ArrayContainer(Container container)
: VArrayImpl_For_Span<T>((int64_t)container.size()), container_(std::move(container))
{
- this->data_ = container_.data();
+ this->data_ = const_cast<T *>(container_.data());
}
};
@@ -422,58 +395,26 @@ template<typename T, typename GetFunc> class VArrayImpl_For_Func final : public
/**
* \note: This is `final` so that #may_have_ownership can be implemented reliably.
*/
-template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-class VArrayImpl_For_DerivedSpan final : public VArrayImpl<ElemT> {
- private:
- const StructT *data_;
-
- public:
- VArrayImpl_For_DerivedSpan(const Span<StructT> data)
- : VArrayImpl<ElemT>(data.size()), data_(data.data())
- {
- }
-
- private:
- ElemT get(const int64_t index) const override
- {
- return GetFunc(data_[index]);
- }
-
- void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override
- {
- ElemT *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); });
- }
-
- void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override
- {
- ElemT *dst = r_span.data();
- mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); });
- }
-
- bool may_have_ownership() const override
- {
- return false;
- }
-};
-
-/**
- * \note: This is `final` so that #may_have_ownership can be implemented reliably.
- */
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, ElemT)>
-class VMutableArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> {
+ void (*SetFunc)(StructT &, ElemT) = nullptr>
+class VArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> {
private:
StructT *data_;
public:
- VMutableArrayImpl_For_DerivedSpan(const MutableSpan<StructT> data)
+ VArrayImpl_For_DerivedSpan(const MutableSpan<StructT> data)
: VMutableArrayImpl<ElemT>(data.size()), data_(data.data())
{
}
+ template<typename OtherStructT,
+ typename OtherElemT,
+ OtherElemT (*OtherGetFunc)(const OtherStructT &),
+ void (*OtherSetFunc)(OtherStructT &, OtherElemT)>
+ friend class VArrayImpl_For_DerivedSpan;
+
private:
ElemT get(const int64_t index) const override
{
@@ -501,6 +442,23 @@ class VMutableArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT>
{
return false;
}
+
+ bool is_same(const VArrayImpl<ElemT> &other) const override
+ {
+ if (other.size() != this->size_) {
+ return false;
+ }
+ if (const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc> *other_typed =
+ dynamic_cast<const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc> *>(&other)) {
+ return other_typed->data_ == data_;
+ }
+ if (const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc> *other_typed =
+ dynamic_cast<const VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc> *>(
+ &other)) {
+ return other_typed->data_ == data_;
+ }
+ return false;
+ }
};
namespace detail {
@@ -620,7 +578,7 @@ template<typename T> class VArrayCommon {
/* Make sure we are actually constructing a #VArrayImpl. */
static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>);
if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) {
- /* Only inline the implementatiton when it is copyable and when it fits into the inline
+ /* Only inline the implementation when it is copyable and when it fits into the inline
* buffer of the storage. */
impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...);
}
@@ -719,9 +677,6 @@ template<typename T> class VArrayCommon {
bool is_span() const
{
BLI_assert(*this);
- if (this->is_empty()) {
- return true;
- }
return impl_->is_span();
}
@@ -742,9 +697,6 @@ template<typename T> class VArrayCommon {
bool is_single() const
{
BLI_assert(*this);
- if (impl_->size() == 1) {
- return true;
- }
return impl_->is_single();
}
@@ -761,6 +713,25 @@ template<typename T> class VArrayCommon {
return impl_->get_internal_single();
}
+ /**
+ * Return true when the other virtual references the same underlying memory.
+ */
+ bool is_same(const VArrayCommon<T> &other) const
+ {
+ if (!*this || !other) {
+ return false;
+ }
+ /* Check in both directions in case one does not know how to compare to the other
+ * implementation. */
+ if (impl_->is_same(*other.impl_)) {
+ return true;
+ }
+ if (other.impl_->is_same(*impl_)) {
+ return true;
+ }
+ return false;
+ }
+
/** Copy the entire virtual array into a span. */
void materialize(MutableSpan<T> r_span) const
{
@@ -846,7 +817,10 @@ template<typename T> class VArray : public VArrayCommon<T> {
*/
static VArray ForSpan(Span<T> values)
{
- return VArray::For<VArrayImpl_For_Span_final<T>>(values);
+ /* Cast const away, because the virtual array implementation for const and non const spans is
+ * shared. */
+ MutableSpan<T> span{const_cast<T *>(values.data()), values.size()};
+ return VArray::For<VArrayImpl_For_Span_final<T>>(span);
}
/**
@@ -865,7 +839,10 @@ template<typename T> class VArray : public VArrayCommon<T> {
template<typename StructT, T (*GetFunc)(const StructT &)>
static VArray ForDerivedSpan(Span<StructT> values)
{
- return VArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc>>(values);
+ /* Cast const away, because the virtual array implementation for const and non const derived
+ * spans is shared. */
+ MutableSpan<StructT> span{const_cast<StructT *>(values.data()), values.size()};
+ return VArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc>>(span);
}
/**
@@ -925,7 +902,7 @@ template<typename T> class VMutableArray : public VArrayCommon<T> {
*/
static VMutableArray ForSpan(MutableSpan<T> values)
{
- return VMutableArray::For<VMutableArrayImpl_For_MutableSpan_final<T>>(values);
+ return VMutableArray::For<VArrayImpl_For_Span_final<T>>(values);
}
/**
@@ -935,8 +912,7 @@ template<typename T> class VMutableArray : public VArrayCommon<T> {
template<typename StructT, T (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, T)>
static VMutableArray ForDerivedSpan(MutableSpan<StructT> values)
{
- return VMutableArray::For<VMutableArrayImpl_For_DerivedSpan<StructT, T, GetFunc, SetFunc>>(
- values);
+ return VMutableArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc, SetFunc>>(values);
}
/** Convert to a #VArray by copying. */
@@ -1107,6 +1083,30 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
}
};
+template<typename T> class SingleAsSpan {
+ private:
+ T value_;
+ int64_t size_;
+
+ public:
+ SingleAsSpan(T value, int64_t size) : value_(std::move(value)), size_(size)
+ {
+ BLI_assert(size_ >= 0);
+ }
+
+ SingleAsSpan(const VArray<T> &varray) : SingleAsSpan(varray.get_internal_single(), varray.size())
+ {
+ }
+
+ const T &operator[](const int64_t index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ UNUSED_VARS_NDEBUG(index);
+ return value_;
+ }
+};
+
/**
* Generate multiple versions of the given function optimized for different virtual arrays.
* One has to be careful with nesting multiple devirtualizations, because that results in an
@@ -1121,14 +1121,11 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool
/* Support disabling the devirtualization to simplify benchmarking. */
if (enable) {
if (varray.is_single()) {
- /* `VArrayImpl_For_Single` can be used for devirtualization, because it is declared `final`.
- */
- func(VArray<T>::ForSingle(varray.get_internal_single(), varray.size()));
+ func(SingleAsSpan<T>(varray));
return;
}
if (varray.is_span()) {
- /* `VArrayImpl_For_Span` can be used for devirtualization, because it is declared `final`. */
- func(VArray<T>::ForSpan(varray.get_internal_span()));
+ func(varray.get_internal_span());
return;
}
}
@@ -1153,23 +1150,19 @@ inline void devirtualize_varray2(const VArray<T1> &varray1,
const bool is_single1 = varray1.is_single();
const bool is_single2 = varray2.is_single();
if (is_span1 && is_span2) {
- func(VArray<T1>::ForSpan(varray1.get_internal_span()),
- VArray<T2>::ForSpan(varray2.get_internal_span()));
+ func(varray1.get_internal_span(), varray2.get_internal_span());
return;
}
if (is_span1 && is_single2) {
- func(VArray<T1>::ForSpan(varray1.get_internal_span()),
- VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size()));
+ func(varray1.get_internal_span(), SingleAsSpan(varray2));
return;
}
if (is_single1 && is_span2) {
- func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()),
- VArray<T2>::ForSpan(varray2.get_internal_span()));
+ func(SingleAsSpan(varray1), varray2.get_internal_span());
return;
}
if (is_single1 && is_single2) {
- func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()),
- VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size()));
+ func(SingleAsSpan(varray1), SingleAsSpan(varray2));
return;
}
}
diff --git a/source/blender/blenlib/BLI_voxel.h b/source/blender/blenlib/BLI_voxel.h
index eb84f0a27ee..83e4bdbdc10 100644
--- a/source/blender/blenlib/BLI_voxel.h
+++ b/source/blender/blenlib/BLI_voxel.h
@@ -27,13 +27,13 @@
extern "C" {
#endif
-/** Find the index number of a voxel, given x/y/z integer coords and resolution vector. */
-
+/** Calculate the index number of a voxel, given x/y/z integer coords and resolution vector. */
#define BLI_VOXEL_INDEX(x, y, z, res) \
((int64_t)(x) + (int64_t)(y) * (int64_t)(res)[0] + \
(int64_t)(z) * (int64_t)(res)[0] * (int64_t)(res)[1])
-/* all input coordinates must be in bounding box 0.0 - 1.0 */
+/* All input coordinates must be in bounding box 0.0 - 1.0. */
+
float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3]);
float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3]);
float BLI_voxel_sample_triquadratic(const float *data, const int res[3], const float co[3]);
diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c
index 7a9cf416d91..f4d60a9e047 100644
--- a/source/blender/blenlib/intern/BLI_array.c
+++ b/source/blender/blenlib/intern/BLI_array.c
@@ -54,11 +54,6 @@
#include "MEM_guardedalloc.h"
-/**
- * This function is only to be called via macros.
- *
- * \note The caller must adjust \a arr_len
- */
void _bli_array_grow_func(void **arr_p,
const void *arr_static,
const int sizeof_arr_p,
diff --git a/source/blender/blenlib/intern/BLI_assert.c b/source/blender/blenlib/intern/BLI_assert.c
index cebc6f8957f..e089ef149a0 100644
--- a/source/blender/blenlib/intern/BLI_assert.c
+++ b/source/blender/blenlib/intern/BLI_assert.c
@@ -49,14 +49,13 @@ void _BLI_assert_print_backtrace(void)
#endif
}
-/**
- * Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
- * allowing changes to debug builds to accidentally to break release builds.
- *
- * For example `BLI_assert(0);` at the end of a function that returns a value,
- * will hide that it's missing a return.
- */
void _BLI_assert_abort(void)
{
+ /* Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
+ * allowing changes to debug builds to accidentally to break release builds.
+ *
+ * For example `BLI_assert(0);` at the end of a function that returns a value,
+ * will hide that it's missing a return. */
+
abort();
}
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index 8f7f722c71b..262d112d914 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -63,11 +63,6 @@ struct DynStr {
/***/
-/**
- * Create a new DynStr.
- *
- * \return Pointer to a new DynStr.
- */
DynStr *BLI_dynstr_new(void)
{
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -78,11 +73,6 @@ DynStr *BLI_dynstr_new(void)
return ds;
}
-/**
- * Create a new DynStr.
- *
- * \return Pointer to a new DynStr.
- */
DynStr *BLI_dynstr_new_memarena(void)
{
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -98,12 +88,6 @@ BLI_INLINE void *dynstr_alloc(DynStr *__restrict ds, size_t size)
return ds->memarena ? BLI_memarena_alloc(ds->memarena, size) : malloc(size);
}
-/**
- * Append a c-string to a DynStr.
- *
- * \param ds: The DynStr to append to.
- * \param cstr: The c-string to append.
- */
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
{
DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
@@ -123,13 +107,6 @@ void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
ds->curlen += cstrlen;
}
-/**
- * Append a length clamped c-string to a DynStr.
- *
- * \param ds: The DynStr to append to.
- * \param cstr: The c-string to append.
- * \param len: The maximum length of the c-string to copy.
- */
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
{
DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
@@ -209,12 +186,6 @@ void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, v
}
}
-/**
- * Append a c-string to a DynStr, but with formatting like printf.
- *
- * \param ds: The DynStr to append to.
- * \param format: The printf format string to use.
- */
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
{
va_list args;
@@ -277,25 +248,11 @@ void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ..
}
}
-/**
- * Find the length of a DynStr.
- *
- * \param ds: The DynStr of interest.
- * \return The length of \a ds.
- */
int BLI_dynstr_get_len(const DynStr *ds)
{
return ds->curlen;
}
-/**
- * Get a DynStr's contents as a c-string.
- * The \a rets argument must be allocated to be at
- * least the size of `BLI_dynstr_get_len(ds) + 1`.
- *
- * \param ds: The DynStr of interest.
- * \param rets: The string to fill.
- */
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets)
{
char *s;
@@ -312,14 +269,6 @@ void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict ret
rets[ds->curlen] = '\0';
}
-/**
- * Get a DynStr's contents as a c-string.
- * <i> The returned c-string should be freed
- * using MEM_freeN. </i>
- *
- * \param ds: The DynStr of interest.
- * \return The contents of \a ds as a c-string.
- */
char *BLI_dynstr_get_cstring(const DynStr *ds)
{
char *rets = MEM_mallocN(ds->curlen + 1, "dynstr_cstring");
@@ -327,11 +276,6 @@ char *BLI_dynstr_get_cstring(const DynStr *ds)
return rets;
}
-/**
- * Clear the DynStr
- *
- * \param ds: The DynStr to clear.
- */
void BLI_dynstr_clear(DynStr *ds)
{
if (ds->memarena) {
@@ -350,11 +294,6 @@ void BLI_dynstr_clear(DynStr *ds)
ds->curlen = 0;
}
-/**
- * Free the DynStr
- *
- * \param ds: The DynStr to free.
- */
void BLI_dynstr_free(DynStr *ds)
{
if (ds->memarena) {
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index f05dea46dc8..169f34f52c3 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -229,12 +229,6 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
}
}
-/**
- * Scans the contents of the directory named *dirname, and allocates and fills in an
- * array of entries describing them in *filelist.
- *
- * \return The length of filelist array.
- */
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
{
struct BuildDirCtx dir_ctx;
@@ -256,9 +250,6 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
return dir_ctx.nrfiles;
}
-/**
- * Convert given entry's size into human-readable strings.
- */
void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz,
/* Used to change MB -> M, etc. - is that really useful? */
@@ -278,9 +269,6 @@ void BLI_filelist_entry_size_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's modes into human-readable strings.
- */
void BLI_filelist_entry_mode_to_string(const struct stat *st,
const bool UNUSED(compact),
char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
@@ -328,9 +316,6 @@ void BLI_filelist_entry_mode_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's owner into human-readable strings.
- */
void BLI_filelist_entry_owner_to_string(const struct stat *st,
const bool UNUSED(compact),
char r_owner[FILELIST_DIRENTRY_OWNER_LEN])
@@ -349,12 +334,6 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st,
#endif
}
-/**
- * Convert given entry's time into human-readable strings.
- *
- * \param r_is_today: optional, returns true if the date matches today's.
- * \param r_is_yesterday: optional, returns true if the date matches yesterday's.
- */
void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts,
const bool compact,
@@ -417,9 +396,6 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
}
}
-/**
- * Deep-duplicate of a single direntry.
- */
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
{
*dst = *src;
@@ -431,9 +407,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
}
}
-/**
- * Deep-duplicate of a #direntry array including the array itself.
- */
void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist,
const unsigned int nrentries)
@@ -448,9 +421,6 @@ void BLI_filelist_duplicate(struct direntry **dest_filelist,
}
}
-/**
- * frees storage for a single direntry, not the direntry itself.
- */
void BLI_filelist_entry_free(struct direntry *entry)
{
if (entry->relname) {
@@ -461,9 +431,6 @@ void BLI_filelist_entry_free(struct direntry *entry)
}
}
-/**
- * Frees storage for an array of #direntry, including the array itself.
- */
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
{
unsigned int i;
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 2c9285e418a..8e2a8ab7639 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -694,16 +694,6 @@ static GHash *ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopy
/** \name GHash Public API
* \{ */
-/**
- * Creates a new, empty GHash.
- *
- * \param hashfp: Hash callback.
- * \param cmpfp: Comparison callback.
- * \param info: Identifier string for the GHash.
- * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
- * Use this to avoid resizing buckets if the size is known or can be closely approximated.
- * \return An empty GHash.
- */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info,
@@ -712,72 +702,38 @@ GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0);
}
-/**
- * Wraps #BLI_ghash_new_ex with zero entries reserved.
- */
GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info)
{
return BLI_ghash_new_ex(hashfp, cmpfp, info, 0);
}
-/**
- * Copy given GHash. Keys and values are also copied if relevant callback is provided,
- * else pointers remain the same.
- */
GHash *BLI_ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
{
return ghash_copy(gh, keycopyfp, valcopyfp);
}
-/**
- * Reserve given amount of entries (resize \a gh accordingly if needed).
- */
void BLI_ghash_reserve(GHash *gh, const uint nentries_reserve)
{
ghash_buckets_expand(gh, nentries_reserve, true);
ghash_buckets_contract(gh, nentries_reserve, true, false);
}
-/**
- * \return size of the GHash.
- */
uint BLI_ghash_len(const GHash *gh)
{
return gh->nentries;
}
-/**
- * Insert a key/value pair into the \a gh.
- *
- * \note Duplicates are not checked,
- * the caller is expected to ensure elements are unique unless
- * GHASH_FLAG_ALLOW_DUPES flag is set.
- */
void BLI_ghash_insert(GHash *gh, void *key, void *val)
{
ghash_insert(gh, key, val);
}
-/**
- * Inserts a new value to a key that may already be in ghash.
- *
- * Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
- *
- * \returns true if a new key has been added.
- */
bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
return ghash_insert_safe(gh, key, val, true, keyfreefp, valfreefp);
}
-/**
- * Replaces the key of an item in the \a gh.
- *
- * Use when a key is re-allocated or its memory location is changed.
- *
- * \returns The previous key or NULL if not found, the caller may free if it's needed.
- */
void *BLI_ghash_replace_key(GHash *gh, void *key)
{
const uint hash = ghash_keyhash(gh, key);
@@ -791,15 +747,6 @@ void *BLI_ghash_replace_key(GHash *gh, void *key)
return NULL;
}
-/**
- * Lookup the value of \a key in \a gh.
- *
- * \param key: The key to lookup.
- * \returns the value for \a key or NULL.
- *
- * \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
- * from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
- */
void *BLI_ghash_lookup(const GHash *gh, const void *key)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -807,9 +754,6 @@ void *BLI_ghash_lookup(const GHash *gh, const void *key)
return e ? e->val : NULL;
}
-/**
- * A version of #BLI_ghash_lookup which accepts a fallback argument.
- */
void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_default)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -817,16 +761,6 @@ void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_defau
return e ? e->val : val_default;
}
-/**
- * Lookup a pointer to the value of \a key in \a gh.
- *
- * \param key: The key to lookup.
- * \returns the pointer to value for \a key or NULL.
- *
- * \note This has 2 main benefits over #BLI_ghash_lookup.
- * - A NULL return always means that \a key isn't in \a gh.
- * - The value can be modified in-place without further function calls (faster).
- */
void **BLI_ghash_lookup_p(GHash *gh, const void *key)
{
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -834,20 +768,6 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key)
return e ? &e->val : NULL;
}
-/**
- * Ensure \a key is exists in \a gh.
- *
- * This handles the common situation where the caller needs ensure a key is added to \a gh,
- * constructing a new value in the case the key isn't found.
- * Otherwise use the existing value.
- *
- * Such situations typically incur multiple lookups, however this function
- * avoids them by ensuring the key is added,
- * returning a pointer to the value so it can be used or initialized by the caller.
- *
- * \returns true when the value didn't need to be added.
- * (when false, the caller _must_ initialize the value).
- */
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
{
const uint hash = ghash_keyhash(gh, key);
@@ -864,12 +784,6 @@ bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
return haskey;
}
-/**
- * A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
- * Typically used when the key is to be duplicated.
- *
- * \warning Caller _must_ write to \a r_key when returning false.
- */
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
{
const uint hash = ghash_keyhash(gh, key);
@@ -889,14 +803,6 @@ bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_
return haskey;
}
-/**
- * Remove \a key from \a gh, or return false if the key wasn't found.
- *
- * \param key: The key to remove.
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- * \return true if \a key was removed from \a gh.
- */
bool BLI_ghash_remove(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp,
@@ -912,17 +818,11 @@ bool BLI_ghash_remove(GHash *gh,
return false;
}
-/* same as above but return the value,
- * no free value argument since it will be returned */
-/**
- * Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
- *
- * \param key: The key to remove.
- * \param keyfreefp: Optional callback to free the key.
- * \return the value of \a key int \a gh or NULL.
- */
void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
{
+ /* Same as above but return the value,
+ * no free value argument since it will be returned. */
+
const uint hash = ghash_keyhash(gh, key);
const uint bucket_index = ghash_bucket_index(gh, hash);
GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, bucket_index);
@@ -935,23 +835,11 @@ void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
return NULL;
}
-/**
- * \return true if the \a key is in \a gh.
- */
bool BLI_ghash_haskey(const GHash *gh, const void *key)
{
return (ghash_lookup_entry(gh, key) != NULL);
}
-/**
- * Remove a random entry from \a gh, returning true
- * if a key/value pair could be removed, false otherwise.
- *
- * \param r_key: The removed key.
- * \param r_val: The removed value.
- * \param state: Used for efficient removal.
- * \return true if there was something to pop, false if ghash was already empty.
- */
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
{
GHashEntry *e = (GHashEntry *)ghash_pop(gh, state);
@@ -970,13 +858,6 @@ bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
return false;
}
-/**
- * Reset \a gh clearing all entries.
- *
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
- */
void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp,
@@ -990,21 +871,11 @@ void BLI_ghash_clear_ex(GHash *gh,
BLI_mempool_clear_ex(gh->entrypool, nentries_reserve ? (int)nentries_reserve : -1);
}
-/**
- * Wraps #BLI_ghash_clear_ex with zero entries reserved.
- */
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
BLI_ghash_clear_ex(gh, keyfreefp, valfreefp, 0);
}
-/**
- * Frees the GHash and its members.
- *
- * \param gh: The GHash to free.
- * \param keyfreefp: Optional callback to free the key.
- * \param valfreefp: Optional callback to free the value.
- */
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
BLI_assert((int)gh->nentries == BLI_mempool_len(gh->entrypool));
@@ -1017,17 +888,11 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreef
MEM_freeN(gh);
}
-/**
- * Sets a GHash flag.
- */
void BLI_ghash_flag_set(GHash *gh, uint flag)
{
gh->flag |= flag;
}
-/**
- * Clear a GHash flag.
- */
void BLI_ghash_flag_clear(GHash *gh, uint flag)
{
gh->flag &= ~flag;
@@ -1039,14 +904,6 @@ void BLI_ghash_flag_clear(GHash *gh, uint flag)
/** \name GHash Iterator API
* \{ */
-/**
- * Create a new GHashIterator. The hash table must not be mutated
- * while the iterator is in use, and the iterator will step exactly
- * #BLI_ghash_len(gh) times before becoming done.
- *
- * \param gh: The GHash to iterate over.
- * \return Pointer to a new iterator.
- */
GHashIterator *BLI_ghashIterator_new(GHash *gh)
{
GHashIterator *ghi = MEM_mallocN(sizeof(*ghi), "ghash iterator");
@@ -1054,14 +911,6 @@ GHashIterator *BLI_ghashIterator_new(GHash *gh)
return ghi;
}
-/**
- * Init an already allocated GHashIterator. The hash table must not
- * be mutated while the iterator is in use, and the iterator will
- * step exactly #BLI_ghash_len(gh) times before becoming done.
- *
- * \param ghi: The GHashIterator to initialize.
- * \param gh: The GHash to iterate over.
- */
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
{
ghi->gh = gh;
@@ -1078,11 +927,6 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
}
}
-/**
- * Steps the iterator to the next index.
- *
- * \param ghi: The iterator.
- */
void BLI_ghashIterator_step(GHashIterator *ghi)
{
if (ghi->curEntry) {
@@ -1097,11 +941,6 @@ void BLI_ghashIterator_step(GHashIterator *ghi)
}
}
-/**
- * Free a GHashIterator.
- *
- * \param ghi: The iterator to free.
- */
void BLI_ghashIterator_free(GHashIterator *ghi)
{
MEM_freeN(ghi);
@@ -1111,9 +950,8 @@ void BLI_ghashIterator_free(GHashIterator *ghi)
/* -------------------------------------------------------------------- */
/** \name GSet Public API
- *
- * Use ghash API to give 'set' functionality
* \{ */
+
GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info,
@@ -1127,9 +965,6 @@ GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
return BLI_gset_new_ex(hashfp, cmpfp, info, 0);
}
-/**
- * Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
- */
GSet *BLI_gset_copy(const GSet *gs, GHashKeyCopyFP keycopyfp)
{
return (GSet *)ghash_copy((const GHash *)gs, keycopyfp, NULL);
@@ -1140,10 +975,6 @@ uint BLI_gset_len(const GSet *gs)
return ((GHash *)gs)->nentries;
}
-/**
- * Adds the key to the set (no checks for unique keys!).
- * Matching #BLI_ghash_insert
- */
void BLI_gset_insert(GSet *gs, void *key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1151,23 +982,11 @@ void BLI_gset_insert(GSet *gs, void *key)
ghash_insert_ex_keyonly((GHash *)gs, key, bucket_index);
}
-/**
- * A version of BLI_gset_insert which checks first if the key is in the set.
- * \returns true if a new key has been added.
- *
- * \note GHash has no equivalent to this because typically the value would be different.
- */
bool BLI_gset_add(GSet *gs, void *key)
{
return ghash_insert_safe_keyonly((GHash *)gs, key, false, NULL);
}
-/**
- * Set counterpart to #BLI_ghash_ensure_p_ex.
- * similar to BLI_gset_add, except it returns the key pointer.
- *
- * \warning Caller _must_ write to \a r_key when returning false.
- */
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1186,23 +1005,11 @@ bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
return haskey;
}
-/**
- * Adds the key to the set (duplicates are managed).
- * Matching #BLI_ghash_reinsert
- *
- * \returns true if a new key has been added.
- */
bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
{
return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp);
}
-/**
- * Replaces the key to the set if it's found.
- * Matching #BLI_ghash_replace_key
- *
- * \returns The old key or NULL if not found.
- */
void *BLI_gset_replace_key(GSet *gs, void *key)
{
return BLI_ghash_replace_key((GHash *)gs, key);
@@ -1218,13 +1025,6 @@ bool BLI_gset_haskey(const GSet *gs, const void *key)
return (ghash_lookup_entry((const GHash *)gs, key) != NULL);
}
-/**
- * Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
- *
- * \param r_key: The removed key.
- * \param state: Used for efficient removal.
- * \return true if there was something to pop, false if gset was already empty.
- */
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key)
{
GSetEntry *e = (GSetEntry *)ghash_pop((GHash *)gs, (GHashIterState *)state);
@@ -1274,19 +1074,12 @@ void BLI_gset_flag_clear(GSet *gs, uint flag)
* This can be useful when the key references data stored outside the GSet.
* \{ */
-/**
- * Returns the pointer to the key if it's found.
- */
void *BLI_gset_lookup(const GSet *gs, const void *key)
{
Entry *e = ghash_lookup_entry((const GHash *)gs, key);
return e ? e->key : NULL;
}
-/**
- * Returns the pointer to the key if it's found, removing it from the GSet.
- * \note Caller must handle freeing.
- */
void *BLI_gset_pop_key(GSet *gs, const void *key)
{
const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1308,9 +1101,6 @@ void *BLI_gset_pop_key(GSet *gs, const void *key)
#include "BLI_math.h"
-/**
- * \return number of buckets in the GHash.
- */
int BLI_ghash_buckets_len(const GHash *gh)
{
return (int)gh->nbuckets;
@@ -1320,13 +1110,6 @@ int BLI_gset_buckets_len(const GSet *gs)
return BLI_ghash_buckets_len((const GHash *)gs);
}
-/**
- * Measure how well the hash function performs (1.0 is approx as good as random distribution),
- * and return a few other stats like load,
- * variance of the distribution of the entries in the buckets, etc.
- *
- * Smaller is better!
- */
double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load,
double *r_variance,
diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c
index b9144009304..f8e621e406c 100644
--- a/source/blender/blenlib/intern/BLI_ghash_utils.c
+++ b/source/blender/blenlib/intern/BLI_ghash_utils.c
@@ -46,9 +46,10 @@ uint BLI_ghashutil_ptrhash(const void *key)
return (uint)(intptr_t)key;
}
#else
-/* Based Python3.7's pointer hashing function. */
uint BLI_ghashutil_ptrhash(const void *key)
{
+ /* Based Python3.7's pointer hashing function. */
+
size_t y = (size_t)key;
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
* excessive hash collisions for dicts and sets */
@@ -134,15 +135,6 @@ size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
}
-/**
- * This function implements the widely used "djb" hash apparently posted
- * by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
- * unsigned hash value starts at 5381 and for each byte 'c' in the
- * string, is updated: `hash = hash * 33 + c`.
- * This function uses the signed value of each byte.
- *
- * NOTE: this is the same hash method that glib 2.34.0 uses.
- */
uint BLI_ghashutil_strhash_n(const char *key, size_t n)
{
const signed char *p;
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index a221820d4c4..efa0110ed53 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -193,11 +193,6 @@ static void heap_node_free(Heap *heap, HeapNode *node)
/** \name Public Heap API
* \{ */
-/**
- * Creates a new heap. Removed nodes are recycled, so memory usage will not shrink.
- *
- * \note Use when the size of the heap is known in advance.
- */
Heap *BLI_heap_new_ex(uint tot_reserve)
{
Heap *heap = MEM_mallocN(sizeof(Heap), __func__);
@@ -261,10 +256,6 @@ void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
heap->nodes.free = NULL;
}
-/**
- * Insert heap node with a value (often a 'cost') and pointer into the heap,
- * duplicate values are allowed.
- */
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
{
HeapNode *node;
@@ -289,9 +280,6 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
return node;
}
-/**
- * Convenience function since this is a common pattern.
- */
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
{
if (*node_p == NULL) {
@@ -312,19 +300,11 @@ uint BLI_heap_len(const Heap *heap)
return heap->size;
}
-/**
- * Return the top node of the heap.
- * This is the node with the lowest value.
- */
HeapNode *BLI_heap_top(const Heap *heap)
{
return heap->tree[0];
}
-/**
- * Return the value of top node of the heap.
- * This is the node with the lowest value.
- */
float BLI_heap_top_value(const Heap *heap)
{
BLI_assert(heap->size != 0);
@@ -332,9 +312,6 @@ float BLI_heap_top_value(const Heap *heap)
return heap->tree[0]->value;
}
-/**
- * Pop the top node off the heap and return its pointer.
- */
void *BLI_heap_pop_min(Heap *heap)
{
BLI_assert(heap->size != 0);
@@ -366,11 +343,6 @@ void BLI_heap_remove(Heap *heap, HeapNode *node)
BLI_heap_pop_min(heap);
}
-/**
- * Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls,
- * balancing the tree still has a performance cost,
- * but is often much less than remove/insert, difference is most noticeable with large heaps.
- */
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value)
{
if (value < node->value) {
@@ -427,9 +399,6 @@ static bool heap_is_minheap(const Heap *heap, uint root)
}
return true;
}
-/**
- * Only for checking internal errors (gtest).
- */
bool BLI_heap_is_valid(const Heap *heap)
{
return heap_is_minheap(heap, 0);
diff --git a/source/blender/blenlib/intern/BLI_heap_simple.c b/source/blender/blenlib/intern/BLI_heap_simple.c
index c075a2f8643..f285dd074c3 100644
--- a/source/blender/blenlib/intern/BLI_heap_simple.c
+++ b/source/blender/blenlib/intern/BLI_heap_simple.c
@@ -147,11 +147,6 @@ static void heapsimple_up(HeapSimple *heap, uint i, float active_val, void *acti
/** \name Public HeapSimple API
* \{ */
-/**
- * Creates a new simple heap, which only supports insertion and removal from top.
- *
- * \note Use when the size of the heap is known in advance.
- */
HeapSimple *BLI_heapsimple_new_ex(uint tot_reserve)
{
HeapSimple *heap = MEM_mallocN(sizeof(HeapSimple), __func__);
@@ -190,10 +185,6 @@ void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
heap->size = 0;
}
-/**
- * Insert heap node with a value (often a 'cost') and pointer into the heap,
- * duplicate values are allowed.
- */
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr)
{
if (UNLIKELY(heap->size >= heap->bufsize)) {
@@ -214,9 +205,6 @@ uint BLI_heapsimple_len(const HeapSimple *heap)
return heap->size;
}
-/**
- * Return the lowest value of the heap.
- */
float BLI_heapsimple_top_value(const HeapSimple *heap)
{
BLI_assert(heap->size != 0);
@@ -224,9 +212,6 @@ float BLI_heapsimple_top_value(const HeapSimple *heap)
return heap->tree[0].value;
}
-/**
- * Pop the top node off the heap and return its pointer.
- */
void *BLI_heapsimple_pop_min(HeapSimple *heap)
{
BLI_assert(heap->size != 0);
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 674654c99a8..64c2ce2a4a3 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -867,9 +867,6 @@ static void non_recursive_bvh_div_nodes(const BVHTree *tree,
/** \name BLI_bvhtree API
* \{ */
-/**
- * \note many callers don't check for `NULL` return.
- */
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
{
BVHTree *tree;
@@ -1013,7 +1010,6 @@ void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoin
bvhtree_node_inflate(tree, node, tree->epsilon);
}
-/* call before BLI_bvhtree_update_tree() */
bool BLI_bvhtree_update_node(
BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints)
{
@@ -1038,9 +1034,6 @@ bool BLI_bvhtree_update_node(
return true;
}
-/**
- * Call #BLI_bvhtree_update_node() first for every node/point/triangle.
- */
void BLI_bvhtree_update_tree(BVHTree *tree)
{
/* Update bottom=>top
@@ -1054,18 +1047,11 @@ void BLI_bvhtree_update_tree(BVHTree *tree)
node_join(tree, *index);
}
}
-/**
- * Number of times #BLI_bvhtree_insert has been called.
- * mainly useful for asserts functions to check we added the correct number.
- */
int BLI_bvhtree_get_len(const BVHTree *tree)
{
return tree->totleaf;
}
-/**
- * Maximum number of children that a node can have.
- */
int BLI_bvhtree_get_tree_type(const BVHTree *tree)
{
return tree->tree_type;
@@ -1076,9 +1062,6 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree)
return tree->epsilon;
}
-/**
- * This function returns the bounding box of the BVH tree.
- */
void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3])
{
BVHNode *root = tree->nodes[tree->totleaf];
@@ -1264,11 +1247,6 @@ static bool tree_overlap_traverse_num(BVHOverlapData_Thread *data_thread,
return false;
}
-/**
- * Use to check the total number of threads #BLI_bvhtree_overlap will use.
- *
- * \warning Must be the first tree passed to #BLI_bvhtree_overlap!
- */
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree)
{
return (int)MIN2(tree->tree_type, tree->nodes[tree->totleaf]->totnode);
@@ -1717,10 +1695,6 @@ static bool dfs_find_duplicate_fast_dfs(BVHNearestData *data, BVHNode *node)
return false;
}
-/**
- * Find the first node nearby.
- * Favors speed over quality since it doesn't find the best target node.
- */
int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3],
const float dist_sq,
@@ -2020,15 +1994,6 @@ float BLI_bvhtree_bb_raycast(const float bv[6],
return dist;
}
-/**
- * Calls the callback for every ray intersection
- *
- * \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
- * however using this function means existing generic callbacks can be used from custom callbacks
- * without having to handle resetting the hit beforehand.
- * It also avoid redundant argument and return value which aren't meaningful
- * when collecting multiple hits.
- */
void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree,
const float co[3],
const float dir[3],
@@ -2395,18 +2360,6 @@ static bool bvhtree_walk_dfs_recursive(BVHTree_WalkData *walk_data, const BVHNod
return true;
}
-/**
- * This is a generic function to perform a depth first search on the #BVHTree
- * where the search order and nodes traversed depend on callbacks passed in.
- *
- * \param tree: Tree to walk.
- * \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
- * \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
- * returning false exits early.
- * \param walk_order_cb: Callback that indicates which direction to search,
- * either from the node with the lower or higher K-DOP axis value.
- * \param userdata: Argument passed to all callbacks.
- */
void BLI_bvhtree_walk_dfs(BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb,
BVHTree_WalkLeafCallback walk_leaf_cb,
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 4cac526088b..765d2f0be55 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -100,10 +100,6 @@ void BLI_linklist_reverse(LinkNode **listp)
*listp = rhead;
}
-/**
- * Move an item from its current position to a new one inside a single-linked list.
- * Note *listp may be modified.
- */
void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
{
LinkNode *lnk, *lnk_psrc = NULL, *lnk_pdst = NULL;
@@ -171,9 +167,6 @@ void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
}
}
-/**
- * A version of prepend that takes the allocated link.
- */
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink)
{
nlink->link = ptr;
@@ -199,9 +192,6 @@ void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool
BLI_linklist_prepend_nlink(listp, ptr, nlink);
}
-/**
- * A version of append that takes the allocated link.
- */
void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
{
nlink->link = ptr;
diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c
index 0ab27a5adad..f1fc3bba4ea 100644
--- a/source/blender/blenlib/intern/BLI_memarena.c
+++ b/source/blender/blenlib/intern/BLI_memarena.c
@@ -179,16 +179,6 @@ void *BLI_memarena_calloc(MemArena *ma, size_t size)
return ptr;
}
-/**
- * Transfer ownership of allocated blocks from `ma_src` into `ma_dst`,
- * cleaning the contents of `ma_src`.
- *
- * \note Useful for multi-threaded tasks that need a thread-local #MemArena
- * that is kept after the multi-threaded operation is completed.
- *
- * \note Avoid accumulating memory pools where possible
- * as any unused memory in `ma_src` is wasted every merge.
- */
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
{
/* Memory arenas must be compatible. */
@@ -231,10 +221,6 @@ void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
VALGRIND_CREATE_MEMPOOL(ma_src, 0, false);
}
-/**
- * Clear for reuse, avoids re-allocation when an arena may
- * otherwise be free'd and recreated.
- */
void BLI_memarena_clear(MemArena *ma)
{
if (ma->bufs) {
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index 2fbdfbe8a95..4e9d68d92e4 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -99,8 +99,6 @@ void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback)
MEM_freeN(mblk);
}
-/* Reset elem count to 0 but keep as much memory allocated needed for at least the previous elem
- * count. */
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback)
{
int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
@@ -191,9 +189,6 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
return ptr;
}
-/* Direct access. elem is element index inside the chosen chunk.
- * Double usage: You can set chunk to 0 and set the absolute elem index.
- * The correct chunk will be retrieve. */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
{
BLI_assert(chunk < mblk->chunk_len);
diff --git a/source/blender/blenlib/intern/BLI_memiter.c b/source/blender/blenlib/intern/BLI_memiter.c
index effbe5da5c4..98348fe2938 100644
--- a/source/blender/blenlib/intern/BLI_memiter.c
+++ b/source/blender/blenlib/intern/BLI_memiter.c
@@ -125,15 +125,6 @@ static void memiter_init(BLI_memiter *mi)
/** \name Public API's
* \{ */
-/**
- * \param chunk_size_min: Should be a power of two and
- * significantly larger than the average element size used.
- *
- * While allocations of any size are supported, they won't be efficient
- * (effectively becoming a single-linked list).
- *
- * Its intended that many elements can be stored per chunk.
- */
BLI_memiter *BLI_memiter_create(uint chunk_size_min)
{
BLI_memiter *mi = MEM_mallocN(sizeof(BLI_memiter), "BLI_memiter");
@@ -261,7 +252,6 @@ uint BLI_memiter_count(const BLI_memiter *mi)
/** \name Helper API's
* \{ */
-/* Support direct lookup for first. */
void *BLI_memiter_elem_first(BLI_memiter *mi)
{
if (mi->head != NULL) {
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index bd6a124c7cb..df85d3e7553 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -367,11 +367,6 @@ void *BLI_mempool_calloc(BLI_mempool *pool)
return retval;
}
-/**
- * Free an element from the mempool.
- *
- * \note doesn't protect against double frees, take care!
- */
void BLI_mempool_free(BLI_mempool *pool, void *addr)
{
BLI_freenode *newhead = addr;
@@ -475,13 +470,6 @@ void *BLI_mempool_findelem(BLI_mempool *pool, uint index)
return NULL;
}
-/**
- * Fill in \a data with pointers to each element of the mempool,
- * to create lookup table.
- *
- * \param pool: Pool to create a table from.
- * \param data: array of pointers at least the size of 'pool->totused'
- */
void BLI_mempool_as_table(BLI_mempool *pool, void **data)
{
BLI_mempool_iter iter;
@@ -495,9 +483,6 @@ void BLI_mempool_as_table(BLI_mempool *pool, void **data)
BLI_assert((uint)(p - data) == pool->totused);
}
-/**
- * A version of #BLI_mempool_as_table that allocates and returns the data.
- */
void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
{
void **data = MEM_mallocN((size_t)pool->totused * sizeof(void *), allocstr);
@@ -505,9 +490,6 @@ void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
return data;
}
-/**
- * Fill in \a data with the contents of the mempool.
- */
void BLI_mempool_as_array(BLI_mempool *pool, void *data)
{
const uint esize = pool->esize;
@@ -522,9 +504,6 @@ void BLI_mempool_as_array(BLI_mempool *pool, void *data)
BLI_assert((uint)(p - (char *)data) == pool->totused * esize);
}
-/**
- * A version of #BLI_mempool_as_array that allocates and returns the data.
- */
void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
{
char *data = MEM_malloc_arrayN(pool->totused, pool->esize, allocstr);
@@ -532,9 +511,6 @@ void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
return data;
}
-/**
- * Initialize a new mempool iterator, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
- */
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter)
{
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -550,19 +526,6 @@ static void mempool_threadsafe_iternew(BLI_mempool *pool, BLI_mempool_threadsafe
ts_iter->curchunk_threaded_shared = NULL;
}
-/**
- * Initialize an array of mempool iterators, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
- *
- * This is used in threaded code, to generate as much iterators as needed
- * (each task should have its own),
- * such that each iterator goes over its own single chunk,
- * and only getting the next chunk to iterate over has to be
- * protected against concurrency (which can be done in a lockless way).
- *
- * To be used when creating a task for each single item in the pool is totally overkill.
- *
- * See BLI_task_parallel_mempool implementation for detailed usage example.
- */
ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
{
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -625,13 +588,8 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return ret;
}
-#else
-
-/* optimized version of code above */
+#else /* Optimized version of code above. */
-/**
- * Step over the iterator, returning the mempool item or NULL.
- */
void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
{
if (UNLIKELY(iter->curchunk == NULL)) {
@@ -660,11 +618,6 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return ret;
}
-/**
- * A version of #BLI_mempool_iterstep that uses
- * #BLI_mempool_threadsafe_iter.curchunk_threaded_shared for threaded iteration support.
- * (threaded section noted in comments).
- */
void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
{
BLI_mempool_iter *iter = &ts_iter->iter;
@@ -710,12 +663,6 @@ void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
#endif
-/**
- * Empty the pool, as if it were just created.
- *
- * \param pool: The pool to clear.
- * \param totelem_reserve: Optionally reserve how many items should be kept from clearing.
- */
void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
{
BLI_mempool_chunk *mpchunk;
@@ -768,17 +715,11 @@ void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
}
}
-/**
- * Wrap #BLI_mempool_clear_ex with no reserve set.
- */
void BLI_mempool_clear(BLI_mempool *pool)
{
BLI_mempool_clear_ex(pool, -1);
}
-/**
- * Free the mempool its self (and all elements).
- */
void BLI_mempool_destroy(BLI_mempool *pool)
{
mempool_chunk_free_all(pool->chunks);
diff --git a/source/blender/blenlib/intern/BLI_mempool_private.h b/source/blender/blenlib/intern/BLI_mempool_private.h
index e1c8205c80c..90569d87c41 100644
--- a/source/blender/blenlib/intern/BLI_mempool_private.h
+++ b/source/blender/blenlib/intern/BLI_mempool_private.h
@@ -41,10 +41,28 @@ typedef struct ParallelMempoolTaskData {
TaskParallelTLS tls;
} ParallelMempoolTaskData;
+/**
+ * Initialize an array of mempool iterators, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
+ *
+ * This is used in threaded code, to generate as much iterators as needed
+ * (each task should have its own),
+ * such that each iterator goes over its own single chunk,
+ * and only getting the next chunk to iterate over has to be
+ * protected against concurrency (which can be done in a lock-less way).
+ *
+ * To be used when creating a task for each single item in the pool is totally overkill.
+ *
+ * See #BLI_task_parallel_mempool implementation for detailed usage example.
+ */
ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void mempool_iter_threadsafe_destroy(ParallelMempoolTaskData *iter_arr) ATTR_NONNULL();
+/**
+ * A version of #BLI_mempool_iterstep that uses
+ * #BLI_mempool_threadsafe_iter.curchunk_threaded_shared for threaded iteration support.
+ * (threaded section noted in comments).
+ */
void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *iter);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/intern/DLRB_tree.c b/source/blender/blenlib/intern/DLRB_tree.c
index 436b9b8d782..66c394f5eb2 100644
--- a/source/blender/blenlib/intern/DLRB_tree.c
+++ b/source/blender/blenlib/intern/DLRB_tree.c
@@ -29,14 +29,12 @@
/* *********************************************** */
/* Tree API */
-/* Create a new tree, and initialize as necessary */
DLRBT_Tree *BLI_dlrbTree_new(void)
{
/* just allocate for now */
return MEM_callocN(sizeof(DLRBT_Tree), "DLRBT_Tree");
}
-/* Just zero out the pointers used */
void BLI_dlrbTree_init(DLRBT_Tree *tree)
{
if (tree == NULL) {
@@ -62,7 +60,6 @@ static void recursive_tree_free_nodes(DLRBT_Node *node)
MEM_freeN(node);
}
-/* Free the given tree's data but not the tree itself */
void BLI_dlrbTree_free(DLRBT_Tree *tree)
{
if (tree == NULL) {
@@ -109,7 +106,6 @@ static void linkedlist_sync_add_node(DLRBT_Tree *tree, DLRBT_Node *node)
linkedlist_sync_add_node(tree, node->right);
}
-/* Make sure the tree's Double-Linked list representation is valid */
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
{
/* sanity checks */
@@ -127,7 +123,6 @@ void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
/* *********************************************** */
/* Tree Search Utilities */
-/* Find the node which matches or is the closest to the requested node */
DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -175,7 +170,6 @@ DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
return node;
}
-/* Find the node which exactly matches the required data */
DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -223,7 +217,6 @@ DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
return (found == 1) ? (node) : (NULL);
}
-/* Find the node which occurs immediately before the best matching node */
DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -254,7 +247,6 @@ DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
return NULL;
}
-/* Find the node which occurs immediately after the best matching node */
DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
void *search_data)
@@ -285,7 +277,6 @@ DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
return NULL;
}
-/* Check whether there is a node matching the requested node */
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
{
/* check if an exact search throws up anything... */
@@ -522,9 +513,6 @@ static void insert_check_3(DLRBT_Tree *tree, DLRBT_Node *node)
/* ----- */
-/* Balance the tree after the given element has been added to it
- * (using custom code, in the Binary Tree way).
- */
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
{
/* sanity checks */
@@ -541,9 +529,6 @@ void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
/* ----- */
-/* Add the given data to the tree, and return the node added */
-/* NOTE: for duplicates, the update_cb is called (if available),
- * and the existing node is returned */
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb,
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index ee06d8b6347..08696c9168d 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -1399,26 +1399,6 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
/** \name Main Array Storage API
* \{ */
-/**
- * Create a new array store, which can store any number of arrays
- * as long as their stride matches.
- *
- * \param stride: `sizeof()` each element,
- *
- * \note while a stride of `1` will always work,
- * its less efficient since duplicate chunks of memory will be searched
- * at positions unaligned with the array data.
- *
- * \param chunk_count: Number of elements to split each chunk into.
- * - A small value increases the ability to de-duplicate chunks,
- * but adds overhead by increasing the number of chunks to look up when searching for duplicates,
- * as well as some overhead constructing the original array again, with more calls to `memcpy`.
- * - Larger values reduce the *book keeping* overhead,
- * but increase the chance a small,
- * isolated change will cause a larger amount of data to be duplicated.
- *
- * \return A new array store, to be freed with #BLI_array_store_destroy.
- */
BArrayStore *BLI_array_store_create(uint stride, uint chunk_count)
{
BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
@@ -1472,9 +1452,6 @@ static void array_store_free_data(BArrayStore *bs)
}
}
-/**
- * Free the #BArrayStore, including all states and chunks.
- */
void BLI_array_store_destroy(BArrayStore *bs)
{
array_store_free_data(bs);
@@ -1486,9 +1463,6 @@ void BLI_array_store_destroy(BArrayStore *bs)
MEM_freeN(bs);
}
-/**
- * Clear all contents, allowing reuse of \a bs.
- */
void BLI_array_store_clear(BArrayStore *bs)
{
array_store_free_data(bs);
@@ -1506,9 +1480,6 @@ void BLI_array_store_clear(BArrayStore *bs)
/** \name BArrayStore Statistics
* \{ */
-/**
- * \return the total amount of memory that would be used by getting the arrays for all states.
- */
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
{
size_t size_accum = 0;
@@ -1518,10 +1489,6 @@ size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
return size_accum;
}
-/**
- * \return the amount of memory used by all #BChunk.data
- * (duplicate chunks are only counted once).
- */
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
{
size_t size_total = 0;
@@ -1541,18 +1508,6 @@ size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
/** \name BArrayState Access
* \{ */
-/**
- *
- * \param data: Data used to create
- * \param state_reference: The state to use as a reference when adding the new state,
- * typically this is the previous state,
- * however it can be any previously created state from this \a bs.
- *
- * \return The new state,
- * which is used by the caller as a handle to get back the contents of \a data.
- * This may be removed using #BLI_array_store_state_remove,
- * otherwise it will be removed with #BLI_array_store_destroy.
- */
BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data,
const size_t data_len,
@@ -1601,11 +1556,6 @@ BArrayState *BLI_array_store_state_add(BArrayStore *bs,
return state;
}
-/**
- * Remove a state and free any unused #BChunk data.
- *
- * The states can be freed in any order.
- */
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
{
#ifdef USE_PARANOID_CHECKS
@@ -1618,18 +1568,11 @@ void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
MEM_freeN(state);
}
-/**
- * \return the expanded size of the array,
- * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
- */
size_t BLI_array_store_state_size_get(BArrayState *state)
{
return state->chunk_list->total_size;
}
-/**
- * Fill in existing allocated memory with the contents of \a state.
- */
void BLI_array_store_state_data_get(BArrayState *state, void *data)
{
#ifdef USE_PARANOID_CHECKS
@@ -1648,9 +1591,6 @@ void BLI_array_store_state_data_get(BArrayState *state, void *data)
}
}
-/**
- * Allocate an array for \a state and return it.
- */
void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len)
{
void *data = MEM_mallocN(state->chunk_list->total_size, __func__);
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 9a12a7442b7..36bd193810e 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -35,11 +35,6 @@
#include "BLI_array_utils.h"
-/**
- *In-place array reverse.
- *
- * Access via #BLI_array_reverse
- */
void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
{
const uint arr_stride_uint = (uint)arr_stride;
@@ -56,12 +51,6 @@ void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
}
}
-/**
- * In-place array wrap.
- * (rotate the array one step forward or backwards).
- *
- * Access via #BLI_array_wrap
- */
void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
{
char *arr = arr_v;
@@ -82,12 +71,6 @@ void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
}
}
-/**
- *In-place array permute.
- * (re-arrange elements based on an array of indices).
- *
- * Access via #BLI_array_wrap
- */
void _bli_array_permute(
void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp)
{
@@ -117,13 +100,6 @@ void _bli_array_permute(
}
}
-/**
- * In-place array de-duplication of an ordered array.
- *
- * \return The new length of the array.
- *
- * Access via #BLI_array_deduplicate_ordered
- */
uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
{
if (UNLIKELY(arr_len <= 1)) {
@@ -146,13 +122,6 @@ uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
return j + 1;
}
-/**
- * Find the first index of an item in an array.
- *
- * Access via #BLI_array_findindex
- *
- * \note Not efficient, use for error checks/asserts.
- */
int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr;
@@ -164,9 +133,6 @@ int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const
return -1;
}
-/**
- * A version of #BLI_array_findindex that searches from the end of the list.
- */
int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{
const char *arr_step = (const char *)arr + (arr_stride * arr_len);
@@ -205,22 +171,6 @@ void _bli_array_binary_or(
}
}
-/**
- * Utility function to iterate over contiguous items in an array.
- *
- * \param use_wrap: Detect contiguous ranges across the first/last points.
- * In this case the second index of \a span_step may be lower than the first,
- * which indicates the values are wrapped.
- * \param use_delimit_bounds: When false,
- * ranges that defined by the start/end indices are excluded.
- * This option has no effect when \a use_wrap is enabled.
- * \param test_fn: Function to test if the item should be included in the range.
- * \param user_data: User data for \a test_fn.
- * \param span_step: Indices to iterate over,
- * initialize both values to the array length to initialize iteration.
- * \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
- * where calculating the length isn't a simple subtraction.
- */
bool _bli_array_iter_span(const void *arr,
uint arr_len,
size_t arr_stride,
@@ -330,9 +280,6 @@ bool _bli_array_iter_span(const void *arr,
return false;
}
-/**
- * Simple utility to check memory is zeroed.
- */
bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
{
const char *arr_step = (const char *)arr_v;
@@ -345,13 +292,6 @@ bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
return true;
}
-/**
- * Smart function to sample a rect spiraling outside.
- * Nice for selection ID.
- *
- * \param arr_shape: dimensions [w, h].
- * \param center: coordinates [x, y] indicating where to start traversing.
- */
bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2],
size_t elem_size,
diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c
index 1f71a62d191..8347e00adc8 100644
--- a/source/blender/blenlib/intern/astar.c
+++ b/source/blender/blenlib/intern/astar.c
@@ -53,25 +53,11 @@
#include "BLI_astar.h"
-/**
- * Init a node in A* graph.
- *
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data)
{
as_graph->nodes[node_index].custom_data = custom_data;
}
-/**
- * Add a link between two nodes of our A* graph.
- *
- * \param cost: the 'length' of the link
- * (actual distance between two vertices or face centers e.g.).
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
const int node1_index,
const int node2_index,
@@ -93,22 +79,11 @@ void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
BLI_addtail(&(as_graph->nodes[node2_index].neighbor_links), &ld[1]);
}
-/**
- * \return The index of the other node of given link.
- */
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx)
{
return (lnk->nodes[0] == idx) ? lnk->nodes[1] : lnk->nodes[0];
}
-/**
- * Initialize a solution data for given A* graph. Does not compute anything!
- *
- * \param custom_data: an opaque pointer attached to this link, available e.g
- * . to cost callback function.
- *
- * \note BLI_AStarSolution stores nearly all data needed during solution compute.
- */
void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution,
void *custom_data)
@@ -133,12 +108,6 @@ void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
as_solution->g_steps = BLI_memarena_alloc(mem, sizeof(*as_solution->g_steps) * node_num);
}
-/**
- * Clear given solution's data, but does not release its memory. Avoids having to recreate/allocate
- * a memarena in loops, e.g.
- *
- * \note This *has to be called* between each path solving.
- */
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
{
if (as_solution->mem) {
@@ -156,9 +125,6 @@ void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
as_solution->g_steps = NULL;
}
-/**
- * Release the memory allocated for this solution.
- */
void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
{
if (as_solution->mem) {
@@ -167,14 +133,6 @@ void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
}
}
-/**
- * Init an A* graph. Total number of nodes must be known.
- *
- * Nodes might be e.g. vertices, faces, ...
- *
- * \param custom_data: an opaque pointer attached to this link,
- * available e.g. to cost callback function.
- */
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data)
{
MemArena *mem = as_graph->mem;
@@ -199,14 +157,6 @@ void BLI_astar_graph_free(BLI_AStarGraph *as_graph)
}
}
-/**
- * Solve a path in given graph, using given 'cost' callback function.
- *
- * \param max_steps: maximum number of nodes the found path may have.
- * Useful in performance-critical usages.
- * If no path is found within given steps, returns false too.
- * \return true if a path was found, false otherwise.
- */
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph,
const int node_index_src,
const int node_index_dst,
diff --git a/source/blender/blenlib/intern/bitmap.c b/source/blender/blenlib/intern/bitmap.c
index 54edcaec2c8..681736b7927 100644
--- a/source/blender/blenlib/intern/bitmap.c
+++ b/source/blender/blenlib/intern/bitmap.c
@@ -29,13 +29,11 @@
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
-/** Set or clear all bits in the bitmap. */
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
{
memset(bitmap, set ? UCHAR_MAX : 0, BLI_BITMAP_SIZE(bits));
}
-/** Invert all bits in the bitmap. */
void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
@@ -44,13 +42,11 @@ void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits)
}
}
-/** Copy all bits from one bitmap to another. */
void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
memcpy(dst, src, BLI_BITMAP_SIZE(bits));
}
-/** Combine two bitmaps with boolean AND. */
void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
@@ -59,7 +55,6 @@ void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
}
}
-/** Combine two bitmaps with boolean OR. */
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c
index b0afe1349ad..670ea75e9ea 100644
--- a/source/blender/blenlib/intern/bitmap_draw_2d.c
+++ b/source/blender/blenlib/intern/bitmap_draw_2d.c
@@ -41,11 +41,6 @@
/** \name Draw Line
* \{ */
-/**
- * Plot a line from \a p1 to \a p2 (inclusive).
- *
- * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
- */
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2],
const int p2[2],
bool (*callback)(int, int, void *),
@@ -223,9 +218,6 @@ static void draw_tri_flat_min(const int p[2],
}
}
-/**
- * \note Unclipped (clipped version can be added if needed).
- */
void BLI_bitmap_draw_2d_tri_v2i(
/* all 2d */
const int p1[2],
@@ -338,18 +330,6 @@ static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *
return 0;
}
-/**
- * Draws a filled polygon with support for self intersections.
- *
- * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
- * note that \a x_end will always be greater than \a x, so we can use:
- *
- * \code{.c}
- * do {
- * func(x, y);
- * } while (++x != x_end);
- * \endcode
- */
void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
const int ymin,
const int xmax,
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index cf5831cada5..5d35feee699 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -120,6 +120,7 @@ static float box_ymax_get(const BoxPack *box)
{
return box->v[TR]->y;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -165,6 +166,7 @@ static void box_ymax_set(BoxPack *box, const float f)
box->v[TR]->y = f;
box_v34y_update(box);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -275,22 +277,9 @@ static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
}
return 0;
}
+
/** \} */
-/**
- * Main box-packing function accessed from other functions
- * This sets boxes x,y to positive values, sorting from 0,0 outwards.
- * There is no limit to the space boxes may take, only that they will be packed
- * tightly into the lower left hand corner (0,0)
- *
- * \param boxarray: a pre-allocated array of boxes.
- * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
- * 'box->index' is not used at all, the only reason its there
- * is that the box array is sorted by area and programs need to be able
- * to have some way of writing the boxes back to the original data.
- * \param len: the number of boxes in the array.
- * \param r_tot_x, r_tot_y: set so you can normalize the data.
- */
void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r_tot_y)
{
uint box_index, verts_pack_len, i, j, k;
@@ -678,18 +667,6 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
MEM_freeN(vs_ctx.vertarray);
}
-/* Packs boxes into a fixed area.
- * boxes and packed are linked lists containing structs that can be cast to
- * FixedSizeBoxPack (i.e. contains a FixedSizeBoxPack as its first element).
- * Boxes that were packed successfully are placed into *packed and removed from *boxes.
- *
- * The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
- * Better ones could be used, but for the current use case (packing Image tiles into GPU
- * textures) this is fine.
- *
- * Note that packing efficiency depends on the order of the input boxes. Generally speaking,
- * larger boxes should come first, though how exactly size is best defined (e.g. area,
- * perimeter) depends on the particular application. */
void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase *packed)
{
ListBase spaces = {NULL};
diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c
index 74e97d89430..9df32051281 100644
--- a/source/blender/blenlib/intern/buffer.c
+++ b/source/blender/blenlib/intern/buffer.c
@@ -86,11 +86,6 @@ void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count)
buffer->count = new_count;
}
-/**
- * Similar to #BLI_buffer_resize, but use when the existing data can be:
- * - Ignored (malloc'd)
- * - Cleared (when BLI_BUFFER_USE_CALLOC is set)
- */
void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
{
if (UNLIKELY(new_count > buffer->alloc_count)) {
@@ -114,7 +109,6 @@ void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
buffer->count = new_count;
}
-/* Callers use BLI_buffer_append_array. */
void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count)
{
size_t size = buffer->count;
@@ -124,7 +118,6 @@ void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count)
memcpy(bytes + size * buffer->elem_size, new_data, count * buffer->elem_size);
}
-/* callers use BLI_buffer_free */
void _bli_buffer_free(BLI_Buffer *buffer)
{
if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) {
diff --git a/source/blender/blenlib/intern/convexhull_2d.c b/source/blender/blenlib/intern/convexhull_2d.c
index 233a1430fe7..df675b512d9 100644
--- a/source/blender/blenlib/intern/convexhull_2d.c
+++ b/source/blender/blenlib/intern/convexhull_2d.c
@@ -53,14 +53,6 @@ static float is_left(const float p0[2], const float p1[2], const float p2[2])
return (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1]);
}
-/**
- * A.M. Andrew's monotone chain 2D convex hull algorithm
- *
- * \param points: An array of 2D points presorted by increasing x and y-coords.
- * \param n: The number of points in points.
- * \param r_points: An array of the convex hull vertex indices (max is n).
- * \returns the number of points in r_points.
- */
int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[])
{
/* the output array r_points[] will be used as the stack */
@@ -182,16 +174,6 @@ static int pointref_cmp_yx(const void *a_, const void *b_)
return 0;
}
-/**
- * A.M. Andrew's monotone chain 2D convex hull algorithm
- *
- * \param points: An array of 2D points.
- * \param n: The number of points in points.
- * \param r_points: An array of the convex hull vertex indices (max is n).
- * _must_ be allocated as `n * 2` because of how its used internally,
- * even though the final result will be no more than \a n in size.
- * \returns the number of points in r_points.
- */
int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
{
struct PointRef *points_ref = MEM_mallocN(sizeof(*points_ref) * (size_t)n, __func__);
@@ -234,16 +216,6 @@ int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
/** \name Utility Convex-Hull Functions
* \{ */
-/**
- * \return The best angle for fitting the convex hull to an axis aligned bounding box.
- *
- * Intended to be used with #BLI_convexhull_2d
- *
- * \param points_hull: Ordered hull points
- * (result of #BLI_convexhull_2d mapped to a contiguous array).
- *
- * \note we could return the index of the best edge too if its needed.
- */
float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n)
{
unsigned int i, i_prev;
@@ -291,11 +263,6 @@ float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned in
return (area_best != FLT_MAX) ? atan2f(dvec_best[0], dvec_best[1]) : 0.0f;
}
-/**
- * Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation.
- *
- * \param points: arbitrary 2d points.
- */
float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n)
{
int *index_map;
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index 6c397fae836..d8e59b6f6ee 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -272,10 +272,6 @@ void BLI_edgehash_print(EdgeHash *eh)
}
}
-/**
- * Insert edge (\a v0, \a v1) into hash with given value, does
- * not check for duplicates.
- */
void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
{
edgehash_ensure_can_insert(eh);
@@ -283,9 +279,6 @@ void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
edgehash_insert(eh, edge, value);
}
-/**
- * Assign a new value to a key that may already be in edgehash.
- */
bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
{
Edge edge = init_edge(v0, v1);
@@ -307,51 +300,24 @@ bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
}
}
-/**
- * A version of #BLI_edgehash_lookup which accepts a fallback argument.
- */
void *BLI_edgehash_lookup_default(const EdgeHash *eh, uint v0, uint v1, void *default_value)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? entry->value : default_value;
}
-/**
- * Return value for given edge (\a v0, \a v1), or NULL if
- * if key does not exist in hash. (If need exists
- * to differentiate between key-value being NULL and
- * lack of key then see #BLI_edgehash_lookup_p().
- */
void *BLI_edgehash_lookup(const EdgeHash *eh, uint v0, uint v1)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? entry->value : NULL;
}
-/**
- * Return pointer to value for given edge (\a v0, \a v1),
- * or NULL if key does not exist in hash.
- */
void **BLI_edgehash_lookup_p(EdgeHash *eh, uint v0, uint v1)
{
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? &entry->value : NULL;
}
-/**
- * Ensure \a (v0, v1) is exists in \a eh.
- *
- * This handles the common situation where the caller needs ensure a key is added to \a eh,
- * constructing a new value in the case the key isn't found.
- * Otherwise use the existing value.
- *
- * Such situations typically incur multiple lookups, however this function
- * avoids them by ensuring the key is added,
- * returning a pointer to the value so it can be used or initialized by the caller.
- *
- * \returns true when the value didn't need to be added.
- * (when false, the caller _must_ initialize the value).
- */
bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
{
Edge edge = init_edge(v0, v1);
@@ -373,13 +339,6 @@ bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
}
}
-/**
- * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
- *
- * \param v0, v1: The key to remove.
- * \param free_value: Optional callback to free the value.
- * \return true if \a key was removed from \a eh.
- */
bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_value)
{
uint old_length = eh->length;
@@ -390,16 +349,11 @@ bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_val
return old_length > eh->length;
}
-/* same as above but return the value,
- * no free value argument since it will be returned */
-/**
- * Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
- *
- * \param v0, v1: The key to remove.
- * \return the value of \a key int \a eh or NULL.
- */
void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
{
+ /* Same as #BLI_edgehash_remove but return the value,
+ * no free value argument since it will be returned */
+
Edge edge = init_edge(v0, v1);
ITER_SLOTS (eh, edge, slot, index) {
@@ -420,25 +374,16 @@ void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
}
}
-/**
- * Return boolean true/false if edge (v0,v1) in hash.
- */
bool BLI_edgehash_haskey(const EdgeHash *eh, uint v0, uint v1)
{
return edgehash_lookup_entry(eh, v0, v1) != NULL;
}
-/**
- * Return number of keys in hash.
- */
int BLI_edgehash_len(const EdgeHash *eh)
{
return (int)eh->length;
}
-/**
- * Remove all edges from hash.
- */
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint UNUSED(reserve))
{
/* TODO: handle reserve */
@@ -449,9 +394,6 @@ void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint U
CLEAR_MAP(eh);
}
-/**
- * Wraps #BLI_edgehash_clear_ex with zero entries reserved.
- */
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
{
BLI_edgehash_clear_ex(eh, free_value, 0);
@@ -463,11 +405,6 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
/** \name Edge Hash Iterator API
* \{ */
-/**
- * Create a new EdgeHashIterator. The hash table must not be mutated
- * while the iterator is in use, and the iterator will step exactly
- * BLI_edgehash_len(eh) times before becoming done.
- */
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
{
EdgeHashIterator *ehi = MEM_mallocN(sizeof(EdgeHashIterator), __func__);
@@ -475,14 +412,6 @@ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
return ehi;
}
-/**
- * Init an already allocated EdgeHashIterator. The hash table must not
- * be mutated while the iterator is in use, and the iterator will
- * step exactly BLI_edgehash_len(eh) times before becoming done.
- *
- * \param ehi: The EdgeHashIterator to initialize.
- * \param eh: The EdgeHash to iterate over.
- */
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
{
ehi->entries = eh->entries;
@@ -490,9 +419,6 @@ void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
ehi->index = 0;
}
-/**
- * Free an EdgeHashIterator.
- */
void BLI_edgehashIterator_free(EdgeHashIterator *ehi)
{
MEM_freeN(ehi);
@@ -569,12 +495,6 @@ BLI_INLINE void edgeset_insert_at_slot(EdgeSet *es, uint slot, Edge edge)
es->length++;
}
-/**
- * A version of BLI_edgeset_insert which checks first if the key is in the set.
- * \returns true if a new key has been added.
- *
- * \note EdgeHash has no equivalent to this because typically the value would be different.
- */
bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
{
edgeset_ensure_can_insert(es);
@@ -591,10 +511,6 @@ bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
}
}
-/**
- * Adds the key to the set (no checks for unique keys!).
- * Matching #BLI_edgehash_insert
- */
void BLI_edgeset_insert(EdgeSet *es, uint v0, uint v1)
{
edgeset_ensure_can_insert(es);
diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c
index 1acb8299aa2..c6be8836229 100644
--- a/source/blender/blenlib/intern/expr_pylike_eval.c
+++ b/source/blender/blenlib/intern/expr_pylike_eval.c
@@ -124,7 +124,6 @@ struct ExprPyLike_Parsed {
/** \name Public API
* \{ */
-/** Free the parsed data; NULL argument is ok. */
void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
{
if (expr != NULL) {
@@ -132,19 +131,16 @@ void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
}
}
-/** Check if the parsing result is valid for evaluation. */
bool BLI_expr_pylike_is_valid(ExprPyLike_Parsed *expr)
{
return expr != NULL && expr->ops_count > 0;
}
-/** Check if the parsed expression always evaluates to the same value. */
bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr)
{
return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST;
}
-/** Check if the parsed expression uses the parameter with the given index. */
bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
{
int i;
@@ -168,10 +164,6 @@ bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
/** \name Stack Machine Evaluation
* \{ */
-/**
- * Evaluate the expression with the given parameters.
- * The order and number of parameters must match the names given to parse.
- */
eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr,
const double *param_values,
int param_values_len,
@@ -1073,12 +1065,6 @@ static bool parse_expr(ExprParseState *state)
/** \name Main Parsing Function
* \{ */
-/**
- * Compile the expression and return the result.
- *
- * Parse the expression for evaluation later.
- * Returns non-NULL even on failure; use is_valid to check.
- */
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names,
int param_names_len)
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index c52feb097d2..838644054af 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -180,13 +180,6 @@ bool BLI_file_magic_is_zstd(const char header[4])
return false;
}
-/**
- * Returns true if the file with the specified name can be written.
- * This implementation uses access(2), which makes the check according
- * to the real UID and GID of the process, not its effective UID and GID.
- * This shouldn't matter for Blender, which is not going to run privileged
- * anyway.
- */
bool BLI_file_is_writable(const char *filename)
{
bool writable;
@@ -212,10 +205,6 @@ bool BLI_file_is_writable(const char *filename)
return writable;
}
-/**
- * Creates the file with nothing in it, or updates its last-modified date if it already exists.
- * Returns true if successful (like the unix touch command).
- */
bool BLI_file_touch(const char *file)
{
FILE *f = BLI_fopen(file, "r+b");
@@ -954,12 +943,6 @@ int BLI_access(const char *filename, int mode)
return access(filename, mode);
}
-/**
- * Deletes the specified file or directory (depending on dir), optionally
- * doing recursive delete of directory contents.
- *
- * \return zero on success (matching 'remove' behavior).
- */
int BLI_delete(const char *file, bool dir, bool recursive)
{
BLI_assert(!BLI_path_is_rel(file));
@@ -973,12 +956,6 @@ int BLI_delete(const char *file, bool dir, bool recursive)
return remove(file);
}
-/**
- * Soft deletes the specified file or directory (depending on dir) by moving the files to the
- * recycling bin, optionally doing recursive delete of directory contents.
- *
- * \return zero on success (matching 'remove' behavior).
- */
int BLI_delete_soft(const char *file, const char **error_message)
{
BLI_assert(!BLI_path_is_rel(file));
@@ -1251,7 +1228,6 @@ int BLI_create_symlink(const char *file, const char *to)
}
# endif
-/** \return true on success (i.e. given path now exists on FS), false otherwise. */
bool BLI_dir_create_recursive(const char *dirname)
{
char *lslash;
@@ -1301,9 +1277,6 @@ bool BLI_dir_create_recursive(const char *dirname)
return ret;
}
-/**
- * \return zero on success (matching 'rename' behavior).
- */
int BLI_rename(const char *from, const char *to)
{
if (!BLI_exists(from)) {
diff --git a/source/blender/blenlib/intern/filereader_zstd.c b/source/blender/blenlib/intern/filereader_zstd.c
index 55ce32713d9..5a04f5b11f3 100644
--- a/source/blender/blenlib/intern/filereader_zstd.c
+++ b/source/blender/blenlib/intern/filereader_zstd.c
@@ -331,5 +331,8 @@ FileReader *BLI_filereader_new_zstd(FileReader *base)
}
zstd->reader.close = zstd_close;
+ /* Rewind after the seek table check so that zstd_read starts at the file's start. */
+ zstd->base->seek(zstd->base, 0, SEEK_SET);
+
return (FileReader *)zstd;
}
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index ae34074e804..1bd99497432 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -101,9 +101,6 @@ static void queue_free_chunk(struct QueueChunk *data)
}
}
-/**
- * Free the queue's data and the queue itself
- */
void BLI_gsqueue_free(GSQueue *queue)
{
queue_free_chunk(queue->chunk_first);
@@ -111,14 +108,6 @@ void BLI_gsqueue_free(GSQueue *queue)
MEM_freeN(queue);
}
-/**
- * Copies the source value onto the end of the queue
- *
- * \note This copies #GSQueue.elem_size bytes from \a item,
- * (the pointer itself is not stored).
- *
- * \param item: source data to be copied to the queue.
- */
void BLI_gsqueue_push(GSQueue *queue, const void *item)
{
queue->chunk_last_index++;
@@ -153,12 +142,6 @@ void BLI_gsqueue_push(GSQueue *queue, const void *item)
memcpy(queue_get_last_elem(queue), item, queue->elem_size);
}
-/**
- * Retrieves and removes the first element from the queue.
- * The value is copies to \a r_item, which must be at least \a elem_size bytes.
- *
- * Does not reduce amount of allocated memory.
- */
void BLI_gsqueue_pop(GSQueue *queue, void *r_item)
{
BLI_assert(BLI_gsqueue_is_empty(queue) == false);
@@ -187,9 +170,6 @@ size_t BLI_gsqueue_len(const GSQueue *queue)
return queue->totelem;
}
-/**
- * Returns true if the queue is empty, false otherwise
- */
bool BLI_gsqueue_is_empty(const GSQueue *queue)
{
return (queue->chunk_first == NULL);
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 3db1b7df0fa..6a0ca8bb33f 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -284,11 +284,6 @@ static void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
/* Top level public functions. */
-/**
- * Compute MD5 message digest for bytes read from 'stream'.
- * The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
- * \return Non-zero if an error occurred.
- */
int BLI_hash_md5_stream(FILE *stream, void *resblock)
{
#define BLOCKSIZE 4096 /* Important: must be a multiple of 64. */
@@ -362,11 +357,6 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
return 0;
}
-/**
- * Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
- * The result is always in little endian byte order,
- * so that a byte-wise output yields to the wanted ASCII representation of the message digest.
- */
void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock)
{
struct md5_ctx ctx;
diff --git a/source/blender/blenlib/intern/hash_mm2a.c b/source/blender/blenlib/intern/hash_mm2a.c
index 0899491cd0d..a98ae083fc8 100644
--- a/source/blender/blenlib/intern/hash_mm2a.c
+++ b/source/blender/blenlib/intern/hash_mm2a.c
@@ -110,7 +110,6 @@ uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2)
return mm2->hash;
}
-/* Non-incremental version, quicker for small keys. */
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
{
/* Initialize the hash to a 'random' value */
diff --git a/source/blender/blenlib/intern/index_mask.cc b/source/blender/blenlib/intern/index_mask.cc
index cba985b8a44..a73e6caf313 100644
--- a/source/blender/blenlib/intern/index_mask.cc
+++ b/source/blender/blenlib/intern/index_mask.cc
@@ -18,21 +18,11 @@
namespace blender {
-/**
- * Create a sub-mask that is also shifted to the beginning. The shifting to the beginning allows
- * code to work with smaller indices, which is more memory efficient.
- *
- * \return New index mask with the size of #slice. It is either empty or starts with 0. It might
- * reference indices that have been appended to #r_new_indices.
- *
- * Example:
- * this: [2, 3, 5, 7, 8, 9, 10]
- * slice: ^--------^
- * output: [0, 2, 4, 5]
- *
- * All the indices in the sub-mask are shifted by 3 towards zero, so that the first index in the
- * output is zero.
- */
+IndexMask IndexMask::slice(IndexRange slice) const
+{
+ return IndexMask(indices_.slice(slice));
+}
+
IndexMask IndexMask::slice_and_offset(const IndexRange slice, Vector<int64_t> &r_new_indices) const
{
const int slice_size = slice.size();
diff --git a/source/blender/blenlib/intern/lasso_2d.c b/source/blender/blenlib/intern/lasso_2d.c
index a3b111cf0f2..ee10a233d39 100644
--- a/source/blender/blenlib/intern/lasso_2d.c
+++ b/source/blender/blenlib/intern/lasso_2d.c
@@ -65,7 +65,6 @@ bool BLI_lasso_is_point_inside(const int mcoords[][2],
return isect_point_poly_v2_int(pt, mcoords, mcoords_len, true);
}
-/* edge version for lasso select. we assume boundbox check was done */
bool BLI_lasso_is_edge_inside(const int mcoords[][2],
const unsigned int mcoords_len,
int x0,
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 443bef42cc2..a166c846ea7 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -36,11 +36,6 @@
#include "BLI_strict_flags.h"
-/* implementation */
-
-/**
- * moves the entire contents of \a src onto the end of \a dst.
- */
void BLI_movelisttolist(ListBase *dst, ListBase *src)
{
if (src->first == NULL) {
@@ -59,9 +54,6 @@ void BLI_movelisttolist(ListBase *dst, ListBase *src)
src->first = src->last = NULL;
}
-/**
- * moves the entire contents of \a src at the beginning of \a dst.
- */
void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
{
if (src->first == NULL) {
@@ -81,9 +73,6 @@ void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
src->first = src->last = NULL;
}
-/**
- * Prepends \a vlink (assumed to begin with a Link) onto listbase.
- */
void BLI_addhead(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -104,9 +93,6 @@ void BLI_addhead(ListBase *listbase, void *vlink)
listbase->first = link;
}
-/**
- * Appends \a vlink (assumed to begin with a Link) onto listbase.
- */
void BLI_addtail(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -127,9 +113,6 @@ void BLI_addtail(ListBase *listbase, void *vlink)
listbase->last = link;
}
-/**
- * Removes \a vlink from \a listbase. Assumes it is linked into there!
- */
void BLI_remlink(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -153,9 +136,6 @@ void BLI_remlink(ListBase *listbase, void *vlink)
}
}
-/**
- * Checks that \a vlink is linked into listbase, removing it from there if so.
- */
bool BLI_remlink_safe(ListBase *listbase, void *vlink)
{
if (BLI_findindex(listbase, vlink) != -1) {
@@ -166,9 +146,6 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink)
return false;
}
-/**
- * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
- */
void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
{
Link *linka = vlinka;
@@ -222,10 +199,6 @@ void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
}
}
-/**
- * Swaps \a vlinka and \a vlinkb from their respective lists.
- * Assumes they are both already in their \a listbasea!
- */
void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vlinka, void *vlinkb)
{
Link *linka = vlinka;
@@ -251,9 +224,6 @@ void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vli
BLI_remlink(listbasea, &linkc);
}
-/**
- * Removes the head from \a listbase and returns it.
- */
void *BLI_pophead(ListBase *listbase)
{
Link *link;
@@ -263,9 +233,6 @@ void *BLI_pophead(ListBase *listbase)
return link;
}
-/**
- * Removes the tail from \a listbase and returns it.
- */
void *BLI_poptail(ListBase *listbase)
{
Link *link;
@@ -275,9 +242,6 @@ void *BLI_poptail(ListBase *listbase)
return link;
}
-/**
- * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
- */
void BLI_freelinkN(ListBase *listbase, void *vlink)
{
Link *link = vlink;
@@ -320,11 +284,6 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
#undef SORT_IMPL_LINKTYPE
-/**
- * Sorts the elements of listbase into the order defined by cmp
- * (which should return 1 if its first arg should come after its second arg).
- * This uses insertion sort, so NOT ok for large list.
- */
void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
{
if (listbase->first != listbase->last) {
@@ -345,10 +304,6 @@ void BLI_listbase_sort_r(ListBase *listbase,
}
}
-/**
- * Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
- * Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
- */
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
{
Link *prevlink = vprevlink;
@@ -388,10 +343,6 @@ void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
}
}
-/**
- * Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
- * Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
- */
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
{
Link *nextlink = vnextlink;
@@ -431,13 +382,6 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
}
}
-/**
- * Insert a link in place of another, without changing its position in the list.
- *
- * Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
- * - `vreplacelink` *must* be in the list.
- * - `vnewlink` *must not* be in the list.
- */
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
{
Link *l_old = vreplacelink;
@@ -464,14 +408,6 @@ void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlin
}
}
-/**
- * Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
- * item if new position would exceed list (could optionally move to head/tail).
- *
- * \param step: Absolute value defines step size, sign defines direction. E.g pass -1
- * to move \a vlink before previous, or 1 to move behind next.
- * \return If position of \a vlink has changed.
- */
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
{
Link *link = vlink;
@@ -503,11 +439,6 @@ bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
return true;
}
-/**
- * Move the link at the index \a from to the position at index \a to.
- *
- * \return If the move was successful.
- */
bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
{
if (from == to) {
@@ -524,9 +455,6 @@ bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
return BLI_listbase_link_move(listbase, link, to - from);
}
-/**
- * Removes and disposes of the entire contents of listbase using direct free(3).
- */
void BLI_freelist(ListBase *listbase)
{
Link *link, *next;
@@ -541,9 +469,6 @@ void BLI_freelist(ListBase *listbase)
BLI_listbase_clear(listbase);
}
-/**
- * Removes and disposes of the entire contents of \a listbase using guardedalloc.
- */
void BLI_freelistN(ListBase *listbase)
{
Link *link, *next;
@@ -558,11 +483,6 @@ void BLI_freelistN(ListBase *listbase)
BLI_listbase_clear(listbase);
}
-/**
- * Returns the number of elements in \a listbase, up until (and including count_max)
- *
- * \note Use to avoid redundant looping.
- */
int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
{
Link *link;
@@ -575,9 +495,6 @@ int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
return count;
}
-/**
- * Returns the number of elements in \a listbase.
- */
int BLI_listbase_count(const ListBase *listbase)
{
Link *link;
@@ -590,9 +507,6 @@ int BLI_listbase_count(const ListBase *listbase)
return count;
}
-/**
- * Returns the nth element of \a listbase, numbering from 0.
- */
void *BLI_findlink(const ListBase *listbase, int number)
{
Link *link = NULL;
@@ -608,9 +522,6 @@ void *BLI_findlink(const ListBase *listbase, int number)
return link;
}
-/**
- * Returns the nth-last element of \a listbase, numbering from 0.
- */
void *BLI_rfindlink(const ListBase *listbase, int number)
{
Link *link = NULL;
@@ -626,9 +537,6 @@ void *BLI_rfindlink(const ListBase *listbase, int number)
return link;
}
-/**
- * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
- */
int BLI_findindex(const ListBase *listbase, const void *vlink)
{
Link *link = NULL;
@@ -651,10 +559,6 @@ int BLI_findindex(const ListBase *listbase, const void *vlink)
return -1;
}
-/**
- * Finds the first element of \a listbase which contains the null-terminated
- * string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -674,13 +578,10 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of \a listbase which contains the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
{
+ /* Same as #BLI_findstring but find reverse. */
+
Link *link = NULL;
const char *id_iter;
@@ -695,10 +596,6 @@ void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset
return NULL;
}
-/**
- * Finds the first element of \a listbase which contains a pointer to the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -715,13 +612,10 @@ void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int off
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of \a listbase which contains a pointer to the
- * null-terminated string \a id at the specified offset, returning NULL if not found.
- */
void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
{
+ /* Same as #BLI_findstring_ptr but find reverse. */
+
Link *link = NULL;
const char *id_iter;
@@ -737,10 +631,6 @@ void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int of
return NULL;
}
-/**
- * Finds the first element of listbase which contains the specified pointer value
- * at the specified offset, returning NULL if not found.
- */
void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
{
Link *link = NULL;
@@ -757,13 +647,10 @@ void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of listbase which contains the specified pointer value
- * at the specified offset, returning NULL if not found.
- */
void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
{
+ /* Same as #BLI_findptr but find reverse. */
+
Link *link = NULL;
const void *ptr_iter;
@@ -779,10 +666,6 @@ void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
return NULL;
}
-/**
- * Finds the first element of listbase which contains the specified bytes
- * at the specified offset, returning NULL if not found.
- */
void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
@@ -801,16 +684,13 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
return NULL;
}
-/* same as above but find reverse */
-/**
- * Finds the last element of listbase which contains the specified bytes
- * at the specified offset, returning NULL if not found.
- */
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes,
const size_t bytes_size,
const int offset)
{
+ /* Same as #BLI_listbase_bytes_find but find reverse. */
+
Link *link = NULL;
const void *ptr_iter;
@@ -825,13 +705,6 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
return NULL;
}
-/**
- * Find the first item in the list that matches the given string, or the given index as fallback.
- *
- * \note The string is only used is non-NULL and non-empty.
- *
- * \return The found item, or NULL.
- */
void *BLI_listbase_string_or_index_find(const ListBase *listbase,
const char *string,
const size_t string_offset,
@@ -856,10 +729,6 @@ void *BLI_listbase_string_or_index_find(const ListBase *listbase,
return link_at_index;
}
-/**
- * Returns the 0-based index of the first element of listbase which contains the specified
- * null-terminated string at the specified offset, or -1 if not found.
- */
int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
{
Link *link = NULL;
@@ -880,9 +749,6 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
return -1;
}
-/**
- * Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
- */
void BLI_duplicatelist(ListBase *dst, const ListBase *src)
{
struct Link *dst_link, *src_link;
@@ -918,9 +784,6 @@ void BLI_listbase_reverse(ListBase *lb)
lb->last = curr;
}
-/**
- * \param vlink: Link to make first.
- */
void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
{
/* make circular */
@@ -934,9 +797,6 @@ void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
((Link *)lb->last)->next = NULL;
}
-/**
- * \param vlink: Link to make last.
- */
void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
{
/* make circular */
@@ -950,7 +810,6 @@ void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
((Link *)lb->last)->next = NULL;
}
-/* create a generic list node containing link to provided data */
LinkData *BLI_genericNodeN(void *data)
{
LinkData *ld;
diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c
index 1137c4114a5..be70acf622a 100644
--- a/source/blender/blenlib/intern/math_base.c
+++ b/source/blender/blenlib/intern/math_base.c
@@ -42,10 +42,10 @@ int pow_i(int base, int exp)
return result;
}
-/* from python 3.1 floatobject.c
- * ndigits must be between 0 and 21 */
double double_round(double x, int ndigits)
{
+ /* From Python 3.1 `floatobject.c`. */
+
double pow1, pow2, y, z;
if (ndigits >= 0) {
pow1 = pow(10.0, (double)ndigits);
@@ -79,15 +79,6 @@ double double_round(double x, int ndigits)
return z;
}
-/**
- * Floor to the nearest power of 10, e.g.:
- * - 15.0 -> 10.0
- * - 0.015 -> 0.01
- * - 1.0 -> 1.0
- *
- * \param f: Value to floor, must be over 0.0.
- * \note If we wanted to support signed values we could if this becomes necessary.
- */
float floor_power_of_10(float f)
{
BLI_assert(!(f < 0.0f));
@@ -97,15 +88,6 @@ float floor_power_of_10(float f)
return 0.0f;
}
-/**
- * Ceiling to the nearest power of 10, e.g.:
- * - 15.0 -> 100.0
- * - 0.015 -> 0.1
- * - 1.0 -> 1.0
- *
- * \param f: Value to ceiling, must be over 0.0.
- * \note If we wanted to support signed values we could if this becomes necessary.
- */
float ceil_power_of_10(float f)
{
BLI_assert(!(f < 0.0f));
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index f609d5f8e8b..53cf2d61963 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -45,7 +45,6 @@ extern "C" {
# define UNLIKELY(x) (x)
#endif
-/* powf is really slow for raising to integer powers. */
MINLINE float pow2f(float x)
{
return x * x;
@@ -192,21 +191,18 @@ MINLINE double ratiod(double min, double max, double pos)
return range == 0 ? 0 : ((pos - min) / range);
}
-/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b]. */
MINLINE float scalenorm(float a, float b, float x)
{
BLI_assert(x <= 1 && x >= 0);
return (x * (b - a)) + a;
}
-/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b]. */
MINLINE double scalenormd(double a, double b, double x)
{
BLI_assert(x <= 1 && x >= 0);
return (x * (b - a)) + a;
}
-/* Used for zoom values. */
MINLINE float power_of_2(float val)
{
return (float)pow(2.0, ceil(log((double)val) / M_LN2));
@@ -363,16 +359,11 @@ MINLINE signed char round_db_to_char_clamp(double a){
#undef _round_clamp_fl_impl
#undef _round_clamp_db_impl
-/**
- * Round to closest even number, halfway cases are rounded away from zero.
- */
MINLINE float round_to_even(float f)
{
return roundf(f * 0.5f) * 2.0f;
}
-/* integer division that rounds 0.5 up, particularly useful for color blending
- * with integers, to avoid gradual darkening when rounding down */
MINLINE int divide_round_i(int a, int b)
{
return (2 * a + b) / (2 * b);
@@ -397,9 +388,6 @@ MINLINE uint divide_ceil_u(uint a, uint b)
return (a + b - 1) / b;
}
-/**
- * modulo that handles negative numbers, works the same as Python's.
- */
MINLINE int mod_i(int i, int n)
{
return (i % n + n) % n;
@@ -629,27 +617,11 @@ MINLINE size_t clamp_z(size_t value, size_t min, size_t max)
return min_zz(max_zz(value, min), max);
}
-/**
- * Almost-equal for IEEE floats, using absolute difference method.
- *
- * \param max_diff: the maximum absolute difference.
- */
MINLINE int compare_ff(float a, float b, const float max_diff)
{
return fabsf(a - b) <= max_diff;
}
-/**
- * Almost-equal for IEEE floats, using their integer representation
- * (mixing ULP and absolute difference methods).
- *
- * \param max_diff: is the maximum absolute difference (allows to take care of the near-zero area,
- * where relative difference methods cannot really work).
- * \param max_ulps: is the 'maximum number of floats + 1'
- * allowed between \a a and \a b to consider them equal.
- *
- * \see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
- */
MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps)
{
union {
@@ -728,19 +700,11 @@ MINLINE int signum_i(float a)
}
}
-/**
- * Returns number of (base ten) *significant* digits of integer part of given float
- * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
- */
MINLINE int integer_digits_f(const float f)
{
return (f == 0.0f) ? 0 : (int)floor(log10(fabs(f))) + 1;
}
-/**
- * Returns number of (base ten) *significant* digits of integer part of given double
- * (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
- */
MINLINE int integer_digits_d(const double d)
{
return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1;
diff --git a/source/blender/blenlib/intern/math_boolean.cc b/source/blender/blenlib/intern/math_boolean.cc
index 6d4806a3fbc..c16755868aa 100644
--- a/source/blender/blenlib/intern/math_boolean.cc
+++ b/source/blender/blenlib/intern/math_boolean.cc
@@ -33,10 +33,6 @@
namespace blender {
#ifdef WITH_GMP
-/**
- * Return +1 if a, b, c are in CCW order around a circle in the plane.
- * Return -1 if they are in CW order, and 0 if they are in line.
- */
int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
{
mpq_class detleft = (a[0] - c[0]) * (b[1] - c[1]);
@@ -45,11 +41,6 @@ int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
return sgn(det);
}
-/**
- Return +1 if d is in the oriented circle through a, b, and c.
- * The oriented circle goes CCW through a, b, and c.
- * Return -1 if d is outside, and 0 if it is on the circle.
- */
int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d)
{
mpq_class adx = a[0] - d[0];
@@ -76,12 +67,6 @@ int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d)
return sgn(det);
}
-/**
- * Return +1 if d is below the plane containing a, b, c (which appear
- * CCW when viewed from above the plane).
- * Return -1 if d is above the plane.
- * Return 0 if it is on the plane.
- */
int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d)
{
mpq_class adx = a[0] - d[0];
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 14eb78648e0..5e52873649e 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -64,13 +64,11 @@ void hsl_to_rgb(float h, float s, float l, float *r_r, float *r_g, float *r_b)
*r_b = (nb - 0.5f) * chroma + l;
}
-/* convenience function for now */
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
{
hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
}
-/* convenience function for now */
void hsl_to_rgb_v(const float hsl[3], float r_rgb[3])
{
hsl_to_rgb(hsl[0], hsl[1], hsl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
@@ -124,9 +122,6 @@ void yuv_to_rgb(float y, float u, float v, float *r_r, float *r_g, float *r_b, i
*r_b = b;
}
-/* The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f
- *
- * Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace)
{
float sr, sg, sb;
@@ -162,12 +157,14 @@ void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr,
*r_cr = cr;
}
-/* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
-/* RGB outputs are in the range 0 - 1.0f */
-
-/* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace)
{
+ /* FIXME the following comment must be wrong because:
+ * BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009. */
+
+ /* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255
+ * RGB outputs are in the range 0 - 1.0f. */
+
float r = 128.0f, g = 128.0f, b = 128.0f;
switch (colorspace) {
@@ -250,7 +247,6 @@ void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v)
*r_v = r;
}
-/* convenience function for now */
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
{
rgb_to_hsv(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]);
@@ -311,7 +307,6 @@ void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3])
rgb_to_hsl_compat(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]);
}
-/* convenience function for now */
void rgb_to_hsl_v(const float rgb[3], float r_hsl[3])
{
rgb_to_hsl(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]);
@@ -338,13 +333,11 @@ void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float
}
}
-/* convenience function for now */
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3])
{
rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]);
}
-/* clamp hsv to usable values */
void hsv_clamp_v(float hsv[3], float v_max)
{
if (UNLIKELY(hsv[0] < 0.0f || hsv[0] > 1.0f)) {
@@ -354,12 +347,6 @@ void hsv_clamp_v(float hsv[3], float v_max)
CLAMP(hsv[2], 0.0f, v_max);
}
-/**
- * We define a 'cpack' here as a (3 byte color code)
- * number that can be expressed like 0xFFAA66 or so.
- * For that reason it is sensitive for endianness... with this function it works correctly.
- * \see #imm_cpack
- */
unsigned int hsv_to_cpack(float h, float s, float v)
{
unsigned int r, g, b;
@@ -473,12 +460,6 @@ void minmax_rgb(short c[3])
}
}
-/* If the requested RGB shade contains a negative weight for
- * one of the primaries, it lies outside the color gamut
- * accessible from the given triple of primaries. Desaturate
- * it by adding white, equal quantities of R, G, and B, enough
- * to make RGB all positive. The function returns 1 if the
- * components were modified, zero otherwise. */
int constrain_rgb(float *r, float *g, float *b)
{
/* Amount of white needed */
@@ -520,7 +501,6 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
/* ************************************* other ************************************************* */
-/* Applies an hue offset to a float rgb color */
void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
{
float hsv[3];
@@ -538,7 +518,6 @@ void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb + 1, rgb + 2);
}
-/* Applies an hue offset to a byte rgb color */
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
{
float rgb_float[3];
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index 24c4143e587..febe1568176 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -271,20 +271,6 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
*
* \{ */
-/**
- * ITU-R BT.709 primaries
- * https://en.wikipedia.org/wiki/Relative_luminance
- *
- * Real values are:
- * `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
- * according to: "Derivation of Basic Television Color Equations", RP 177-1993
- *
- * As this sums slightly above 1.0, the document recommends to use:
- * `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
- *
- * The high precision values are used to calculate the rounded byte weights so they add up to 255:
- * `54(R) + 182(G) + 19(B)`
- */
MINLINE float rgb_to_grayscale(const float rgb[3])
{
return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]);
@@ -317,11 +303,11 @@ MINLINE int compare_rgb_uchar(const unsigned char col_a[3],
return 0;
}
-/* Using a triangle distribution which gives a more final uniform noise.
- * See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
-/* Return triangle noise in [-0.5..1.5[ range */
MINLINE float dither_random_value(float s, float t)
{
+ /* Using a triangle distribution which gives a more final uniform noise.
+ * See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
+
/* Uniform noise in [0..1[ range, using common GLSL hash function.
* https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner. */
float hash0 = sinf(s * 12.9898f + t * 78.233f) * 43758.5453f;
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 8afb6b5a2be..a155877513a 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -86,11 +86,6 @@ float normal_quad_v3(
return normalize_v3(n);
}
-/**
- * Computes the normal of a planar
- * polygon See Graphics Gems for
- * computing newell normal.
- */
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr)
{
cross_poly_v3(n, verts, nr);
@@ -112,7 +107,6 @@ float area_squared_quad_v3(const float v1[3],
return area_squared_poly_v3(verts, 4);
}
-/* Triangles */
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
{
float n[3];
@@ -162,12 +156,6 @@ float area_squared_poly_v3(const float verts[][3], unsigned int nr)
return len_squared_v3(n);
}
-/**
- * Scalar cross product of a 2d polygon.
- *
- * - equivalent to `area * 2`
- * - useful for checking polygon winding (a positive value is clockwise).
- */
float cross_poly_v2(const float verts[][2], unsigned int nr)
{
unsigned int a;
@@ -236,28 +224,18 @@ float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float
/********************************* Planes **********************************/
-/**
- * Calculate a plane from a point and a direction,
- * \note \a point_no isn't required to be normalized.
- */
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
{
copy_v3_v3(r_plane, plane_no);
r_plane[3] = -dot_v3v3(r_plane, plane_co);
}
-/**
- * Get a point and a direction from a plane.
- */
void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3])
{
mul_v3_v3fl(r_plane_co, plane, (-plane[3] / len_squared_v3(plane)));
copy_v3_v3(r_plane_no, plane);
}
-/**
- * version of #plane_to_point_vector_v3 that gets a unit length vector.
- */
void plane_to_point_vector_v3_normalized(const float plane[4],
float r_plane_co[3],
float r_plane_no[3])
@@ -268,9 +246,6 @@ void plane_to_point_vector_v3_normalized(const float plane[4],
/********************************* Volume **********************************/
-/**
- * The volume from a tetrahedron, points can be in any order
- */
float volume_tetrahedron_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -283,9 +258,6 @@ float volume_tetrahedron_v3(const float v1[3],
return fabsf(determinant_m3_array(m)) / 6.0f;
}
-/**
- * The volume from a tetrahedron, normal pointing inside gives negative volume
- */
float volume_tetrahedron_signed_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -298,12 +270,6 @@ float volume_tetrahedron_signed_v3(const float v1[3],
return determinant_m3_array(m) / 6.0f;
}
-/**
- * The volume from a triangle that is made into a tetrahedron.
- * This uses a simplified formula where the tip of the tetrahedron is in the world origin.
- * Using this method, the total volume of a closed triangle mesh can be calculated.
- * Note that you need to divide the result by 6 to get the actual volume.
- */
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
{
float v_cross[3];
@@ -319,8 +285,6 @@ float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], con
/********************************* Distance **********************************/
-/* distance p to line v1-v2
- * using Hesse formula, NO LINE PIECE! */
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
{
float closest[2];
@@ -334,7 +298,6 @@ float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
return sqrtf(dist_squared_to_line_v2(p, l1, l2));
}
-/* distance p to line-piece v1-v2 */
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
{
float closest[2];
@@ -349,7 +312,6 @@ float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l
return sqrtf(dist_squared_to_line_segment_v2(p, l1, l2));
}
-/* point closest to v1 on line v2-v3 in 2D */
void closest_to_line_segment_v2(float r_close[2],
const float p[2],
const float l1[2],
@@ -371,7 +333,6 @@ void closest_to_line_segment_v2(float r_close[2],
}
}
-/* point closest to v1 on line v2-v3 in 3D */
void closest_to_line_segment_v3(float r_close[3],
const float p[3],
const float l1[3],
@@ -393,15 +354,6 @@ void closest_to_line_segment_v3(float r_close[3],
}
}
-/**
- * Find the closest point on a plane.
- *
- * \param r_close: Return coordinate
- * \param plane: The plane to test against.
- * \param pt: The point to find the nearest of
- *
- * \note non-unit-length planes are supported.
- */
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
{
const float len_sq = len_squared_v3(plane);
@@ -462,9 +414,6 @@ float dist_squared_to_plane3_v3(const float pt[3], const float plane[3])
return len_sq * (fac * fac);
}
-/**
- * Return the signed distance from the point to the plane.
- */
float dist_signed_to_plane_v3(const float pt[3], const float plane[4])
{
const float len_sq = len_squared_v3(plane);
@@ -489,7 +438,6 @@ float dist_to_plane3_v3(const float pt[3], const float plane[3])
return fabsf(dist_signed_to_plane3_v3(pt, plane));
}
-/* distance v1 to line-piece l1-l2 in 3D */
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
{
float closest[3];
@@ -517,29 +465,6 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
return sqrtf(dist_squared_to_line_v3(p, l1, l2));
}
-/**
- * Check if \a p is inside the 2x planes defined by `(v1, v2, v3)`
- * where the 3x points define 2x planes.
- *
- * \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex.
- *
- * \note the distance from \a v1 & \a v3 to \a v2 doesn't matter
- * (it just defines the planes).
- *
- * \return the lowest squared distance to either of the planes.
- * where `(return < 0.0)` is outside.
- *
- * <pre>
- * v1
- * +
- * /
- * x - out / x - inside
- * /
- * +----+
- * v2 v3
- * x - also outside
- * </pre>
- */
float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3],
const float v2[3],
@@ -591,12 +516,6 @@ float dist_signed_squared_to_corner_v3v3v3(const float p[3],
return max_ff(dist_a, dist_b);
}
-/**
- * Compute the squared distance of a point to a line (defined as ray).
- * \param ray_origin: A point on the line.
- * \param ray_direction: Normalized direction of the line.
- * \param co: Point to which the distance is to be calculated.
- */
float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
const float ray_direction[3],
const float co[3])
@@ -613,12 +532,6 @@ float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
return len_squared_v3v3(co, co_projected_on_ray);
}
-/**
- * Find the closest point in a seg to a ray and return the distance squared.
- * \param r_point: Is the point on segment closest to ray
- * (or to ray_origin if the ray and the segment are parallel).
- * \param r_depth: the distance of r_point projection on ray to the ray_origin.
- */
float dist_squared_ray_to_seg_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -655,8 +568,6 @@ float dist_squared_ray_to_seg_v3(const float ray_origin[3],
return len_squared_v3(dvec) - square_f(depth);
}
-/* Returns the coordinates of the nearest vertex and
- * the farthest vertex from a plane (or normal). */
void aabb_get_near_far_from_plane(const float plane_no[3],
const float bbmin[3],
const float bbmax[3],
@@ -707,9 +618,6 @@ void dist_squared_ray_to_aabb_v3_precalc(struct DistRayAABB_Precalc *neasrest_pr
}
}
-/**
- * Returns the distance from a ray to a bound-box (projected on ray)
- */
float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
@@ -810,16 +718,13 @@ float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3],
dist_squared_ray_to_aabb_v3_precalc(&data, ray_origin, ray_direction);
return dist_squared_ray_to_aabb_v3(&data, bb_min, bb_max, r_point, r_depth);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name dist_squared_to_projected_aabb and helpers
* \{ */
-/**
- * \param projmat: Projection Matrix (usually perspective
- * matrix multiplied by object matrix).
- */
void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *precalc,
const float projmat[4][4],
const float winsize[2],
@@ -871,7 +776,6 @@ void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *pre
}
}
-/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */
float dist_squared_to_projected_aabb(struct DistProjectedAABBPrecalc *data,
const float bbmin[3],
const float bbmax[3],
@@ -1014,15 +918,15 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
bool dummy[3] = {true, true, true};
return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
}
+
/** \} */
-/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
- * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc.
- *
- * Set 'r' to the point in triangle (a, b, c) closest to point 'p' */
void closest_on_tri_to_point_v3(
float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
{
+ /* Adapted from "Real-Time Collision Detection" by Christer Ericson,
+ * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. */
+
float ab[3], ac[3], ap[3], d1, d2;
float bp[3], d3, d4, vc, cp[3], d5, d6, vb, va;
float denom, v, w;
@@ -1100,7 +1004,6 @@ void closest_on_tri_to_point_v3(
/******************************* Intersection ********************************/
-/* intersect Line-Line, shorts */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
{
float div, lambda, mu;
@@ -1123,7 +1026,6 @@ int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], cons
return ISECT_LINE_LINE_NONE;
}
-/* intersect Line-Line, floats - gives intersection point */
int isect_line_line_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
{
@@ -1147,7 +1049,6 @@ int isect_line_line_v2_point(
return ISECT_LINE_LINE_COLINEAR;
}
-/* intersect Line-Line, floats */
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
float div, lambda, mu;
@@ -1170,7 +1071,6 @@ int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], co
return ISECT_LINE_LINE_NONE;
}
-/* Returns a point on each segment that is closest to the other. */
void isect_seg_seg_v3(const float a0[3],
const float a1[3],
const float b0[3],
@@ -1236,19 +1136,6 @@ void isect_seg_seg_v3(const float a0[3],
madd_v3_v3v3fl(r_b, b0, b_dir, fac_b);
}
-/**
- * Get intersection point of two 2D segments.
- *
- * \param endpoint_bias: Bias to use when testing for end-point overlap.
- * A positive value considers intersections that extend past the endpoints,
- * negative values contract the endpoints.
- * Note the bias is applied to a 0-1 factor, not scaled to the length of segments.
- *
- * \returns intersection type:
- * - -1: collinear.
- * - 1: intersection.
- * - 0: no intersection.
- */
int isect_seg_seg_v2_point_ex(const float v0[2],
const float v1[2],
const float v2[2],
@@ -1369,18 +1256,6 @@ bool isect_seg_seg_v2_simple(const float v1[2],
#undef CCW
}
-/**
- * If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
- * <pre>
- * pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
- * </pre>
- * \returns intersection type:
- * - ISECT_LINE_LINE_COLINEAR: collinear.
- * - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
- * - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
- * - ISECT_LINE_LINE_NONE: no intersection.
- * Also returns lambda and mu in r_lambda and r_mu.
- */
int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
const double v2[2],
const double v3[2],
@@ -1415,19 +1290,6 @@ int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
return ISECT_LINE_LINE_NONE;
}
-/**
- * \param l1, l2: Coordinates (point of line).
- * \param sp, r: Coordinate and radius (sphere).
- * \return r_p1, r_p2: Intersection coordinates.
- *
- * \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
- * based on the direction defined by `l2 - l1`,
- * this direction compared with the normal of each point on the sphere:
- * \a r_p1 always has a >= 0.0 dot product.
- * \a r_p2 always has a <= 0.0 dot product.
- * For example, when \a l1 is inside the sphere and \a l2 is outside,
- * \a r_p1 will always be between \a l1 and \a l2.
- */
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
@@ -1490,7 +1352,6 @@ int isect_line_sphere_v3(const float l1[3],
return -1;
}
-/* keep in sync with isect_line_sphere_v3 */
int isect_line_sphere_v2(const float l1[2],
const float l2[2],
const float sp[2],
@@ -1498,6 +1359,8 @@ int isect_line_sphere_v2(const float l1[2],
float r_p1[2],
float r_p2[2])
{
+ /* Keep in sync with #isect_line_sphere_v3. */
+
const float ldir[2] = {l2[0] - l1[0], l2[1] - l1[1]};
const float a = dot_v2v2(ldir, ldir);
@@ -1537,12 +1400,13 @@ int isect_line_sphere_v2(const float l1[2],
return -1;
}
-/* point in polygon (keep float and int versions in sync) */
bool isect_point_poly_v2(const float pt[2],
const float verts[][2],
const unsigned int nr,
const bool UNUSED(use_holes))
{
+ /* Keep in sync with #isect_point_poly_v2_int. */
+
unsigned int i, j;
bool isect = false;
for (i = 0, j = nr - 1; i < nr; j = i++) {
@@ -1560,6 +1424,8 @@ bool isect_point_poly_v2_int(const int pt[2],
const unsigned int nr,
const bool UNUSED(use_holes))
{
+ /* Keep in sync with #isect_point_poly_v2. */
+
unsigned int i, j;
bool isect = false;
for (i = 0, j = nr - 1; i < nr; j = i++) {
@@ -1575,7 +1441,6 @@ bool isect_point_poly_v2_int(const int pt[2],
/* point in tri */
-/* only single direction */
bool isect_point_tri_v2_cw(const float pt[2],
const float v1[2],
const float v2[2],
@@ -1612,7 +1477,6 @@ int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2],
return 0;
}
-/* point in quad - only convex quads */
int isect_point_quad_v2(
const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
@@ -1638,10 +1502,6 @@ int isect_point_quad_v2(
return 0;
}
-/* moved from effect.c
- * test if the line starting at p1 ending at p2 intersects the triangle v0..v2
- * return non zero if it does
- */
bool isect_line_segment_tri_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -1692,7 +1552,6 @@ bool isect_line_segment_tri_v3(const float p1[3],
return true;
}
-/* like isect_line_segment_tri_v3, but allows epsilon tolerance around triangle */
bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float p2[3],
const float v0[3],
@@ -1744,10 +1603,6 @@ bool isect_line_segment_tri_epsilon_v3(const float p1[3],
return true;
}
-/* moved from effect.c
- * test if the ray starting at p1 going in d direction intersects the triangle v0..v2
- * return non zero if it does
- */
bool isect_ray_tri_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -1799,12 +1654,6 @@ bool isect_ray_tri_v3(const float ray_origin[3],
return true;
}
-/**
- * if clip is nonzero, will only return true if lambda is >= 0.0
- * (i.e. intersection point is along positive \a ray_direction)
- *
- * \note #line_plane_factor_v3() shares logic.
- */
bool isect_ray_plane_v3(const float ray_origin[3],
const float ray_direction[3],
const float plane[4],
@@ -2146,9 +1995,6 @@ bool isect_ray_line_v3(const float ray_origin[3],
return true;
}
-/**
- * Check if a point is behind all planes.
- */
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
{
int i;
@@ -2162,10 +2008,6 @@ bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
return true;
}
-/**
- * Check if a point is in front all planes.
- * Same as isect_point_planes_v3 but with planes facing the opposite direction.
- */
bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3])
{
for (int i = 0; i < totplane; i++) {
@@ -2177,17 +2019,6 @@ bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane,
return true;
}
-/**
- * Intersect line/plane.
- *
- * \param r_isect_co: The intersection point.
- * \param l1: The first point of the line.
- * \param l2: The second point of the line.
- * \param plane_co: A point on the plane to intersect with.
- * \param plane_no: The direction of the plane (does not need to be normalized).
- *
- * \note #line_plane_factor_v3() shares logic.
- */
bool isect_line_plane_v3(float r_isect_co[3],
const float l1[3],
const float l2[3],
@@ -2211,13 +2042,6 @@ bool isect_line_plane_v3(float r_isect_co[3],
return false;
}
-/**
- * Intersect three planes, return the point where all 3 meet.
- * See Graphics Gems 1 pg 305
- *
- * \param plane_a, plane_b, plane_c: Planes.
- * \param r_isect_co: The resulting intersection point.
- */
bool isect_plane_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
const float plane_c[4],
@@ -2251,17 +2075,6 @@ bool isect_plane_plane_plane_v3(const float plane_a[4],
return false;
}
-/**
- * Intersect two planes, return a point on the intersection and a vector
- * that runs on the direction of the intersection.
- * \note this is a slightly reduced version of #isect_plane_plane_plane_v3
- *
- * \param plane_a, plane_b: Planes.
- * \param r_isect_co: The resulting intersection point.
- * \param r_isect_no: The resulting vector of the intersection.
- *
- * \note \a r_isect_no isn't unit length.
- */
bool isect_plane_plane_v3(const float plane_a[4],
const float plane_b[4],
float r_isect_co[3],
@@ -2296,19 +2109,6 @@ bool isect_plane_plane_v3(const float plane_a[4],
return false;
}
-/**
- * Intersect all planes, calling `callback_fn` for each point that intersects
- * 3 of the planes that isn't outside any of the other planes.
- *
- * This can be thought of as calculating a convex-hull from an array of planes.
- *
- * \param eps_coplanar: Epsilon for testing if two planes are aligned (co-planar).
- * \param eps_isect: Epsilon for testing of a point is behind any of the planes.
- *
- * \warning As complexity is a little under `O(N^3)`, this is only suitable for small arrays.
- *
- * \note This function could be optimized by some spatial structure.
- */
bool isect_planes_v3_fn(
const float planes[][4],
const int planes_len,
@@ -2371,16 +2171,6 @@ bool isect_planes_v3_fn(
return found;
}
-/**
- * Intersect two triangles.
- *
- * \param r_i1, r_i2: Retrieve the overlapping edge between the 2 triangles.
- * \param r_tri_a_edge_isect_count: Indicates how many edges in the first triangle are intersected.
- * \return true when the triangles intersect.
- *
- * \note If it exists, \a r_i1 will be a point on the edge of the 1st triangle.
- * \note intersections between coplanar triangles are currently undetected.
- */
bool isect_tri_tri_v3_ex(const float tri_a[3][3],
const float tri_b[3][3],
float r_i1[3],
@@ -2755,14 +2545,6 @@ static bool getLowestRoot(
return false;
}
-/**
- * Checks status of an AABB in relation to a list of planes.
- *
- * \returns intersection type:
- * - ISECT_AABB_PLANE_BEHIND_ONE (0): AABB is completely behind at least 1 plane;
- * - ISECT_AABB_PLANE_CROSS_ANY (1): AABB intersects at least 1 plane;
- * - ISECT_AABB_PLANE_IN_FRONT_ALL (2): AABB is completely in front of all planes;
- */
int isect_aabb_planes_v3(const float (*planes)[4],
const int totplane,
const float bbmin[3],
@@ -3030,12 +2812,6 @@ bool isect_axial_line_segment_tri_v3(const int axis,
return true;
}
-/**
- * \return The number of point of interests
- * 0 - lines are collinear
- * 1 - lines are coplanar, i1 is set to intersection
- * 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively
- */
int isect_line_line_epsilon_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -3111,10 +2887,6 @@ int isect_line_line_v3(const float v1[3],
return isect_line_line_epsilon_v3(v1, v2, v3, v4, r_i1, r_i2, epsilon);
}
-/**
- * Intersection point strictly between the two lines
- * \return false when no intersection is found.
- */
bool isect_line_line_strict_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -3165,12 +2937,6 @@ bool isect_line_line_strict_v3(const float v1[3],
return false;
}
-/**
- * Check if two rays are not parallel and returns a factor that indicates
- * the distance from \a ray_origin_b to the closest point on ray-a to ray-b.
- *
- * \note Neither directions need to be normalized.
- */
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
@@ -3247,12 +3013,13 @@ void isect_ray_aabb_v3_precalc(struct IsectRayAABB_Precalc *data,
data->sign[2] = data->ray_inv_dir[2] < 0.0f;
}
-/* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
const float bb_min[3],
const float bb_max[3],
float *tmin_out)
{
+ /* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
+
float bbox[2][3];
copy_v3_v3(bbox[0], bb_min);
@@ -3298,13 +3065,6 @@ bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
return true;
}
-/**
- * Test a bounding box (AABB) for ray intersection.
- * Assumes the ray is already local to the boundbox space.
- *
- * \note \a direction should be normalized
- * if you intend to use the \a tmin or \a tmax distance results!
- */
bool isect_ray_aabb_v3_simple(const float orig[3],
const float dir[3],
const float bb_min[3],
@@ -3357,10 +3117,6 @@ float closest_to_ray_v3(float r_close[3],
return lambda;
}
-/**
- * Find closest point to p on line through (l1, l2) and return lambda,
- * where (0 <= lambda <= 1) when cp is in the line segment (l1, l2).
- */
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
{
float u[3];
@@ -3424,13 +3180,6 @@ float ray_point_factor_v3(const float p[3],
return ray_point_factor_v3_ex(p, ray_origin, ray_direction, 0.0f, 0.0f);
}
-/**
- * A simplified version of #closest_to_line_v3
- * we only need to return the `lambda`
- *
- * \param epsilon: avoid approaching divide-by-zero.
- * Passing a zero will just check for nonzero division.
- */
float line_point_factor_v3_ex(const float p[3],
const float l1[3],
const float l2[3],
@@ -3471,9 +3220,6 @@ float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2
return line_point_factor_v2_ex(p, l1, l2, 0.0f, 0.0f);
}
-/**
- * \note #isect_line_plane_v3() shares logic
- */
float line_plane_factor_v3(const float plane_co[3],
const float plane_no[3],
const float l1[3],
@@ -3487,10 +3233,6 @@ float line_plane_factor_v3(const float plane_co[3],
return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f;
}
-/**
- * Ensure the distance between these points is no greater than 'dist'.
- * If it is, scale them both into the center.
- */
void limit_dist_v3(float v1[3], float v2[3], const float dist)
{
const float dist_old = len_v3v3(v1, v2);
@@ -3508,13 +3250,6 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist)
}
}
-/*
- * x1,y2
- * | \
- * | \ .(a,b)
- * | \
- * x1,y1-- x2,y1
- */
int isect_point_tri_v2_int(
const int x1, const int y1, const int x2, const int y2, const int a, const int b)
{
@@ -3603,12 +3338,6 @@ bool isect_point_tri_prism_v3(const float p[3],
return true;
}
-/**
- * \param r_isect_co: The point \a p projected onto the triangle.
- * \return True when \a p is inside the triangle.
- * \note Its up to the caller to check the distance between \a p and \a r_vi
- * against an error margin.
- */
bool isect_point_tri_v3(
const float p[3], const float v1[3], const float v2[3], const float v3[3], float r_isect_co[3])
{
@@ -3739,16 +3468,6 @@ bool clip_segment_v3_plane_n(const float p1[3],
/****************************** Axis Utils ********************************/
-/**
- * \brief Normal to x,y matrix
- *
- * Creates a 3x3 matrix from a normal.
- * This matrix can be applied to vectors so their 'z' axis runs along \a normal.
- * In practice it means you can use x,y as 2d coords. \see
- *
- * \param r_mat: The matrix to return.
- * \param normal: A unit length vector.
- */
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -3766,9 +3485,6 @@ void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
is_zero_v3(normal));
}
-/**
- * Same as axis_dominant_v3_to_m3, but flips the normal
- */
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -3888,12 +3604,6 @@ void interp_weights_quad_v3(float w[4],
}
}
-/**
- * \return
- * - 0 if the point is outside of triangle.
- * - 1 if the point is inside triangle.
- * - 2 if it's on the edge.
- */
int barycentric_inside_triangle_v2(const float w[3])
{
if (IN_RANGE(w[0], 0.0f, 1.0f) && IN_RANGE(w[1], 0.0f, 1.0f) && IN_RANGE(w[2], 0.0f, 1.0f)) {
@@ -3907,9 +3617,6 @@ int barycentric_inside_triangle_v2(const float w[3])
return 0;
}
-/**
- * \return false for degenerated triangles.
- */
bool barycentric_coords_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3934,12 +3641,6 @@ bool barycentric_coords_v2(
return false;
}
-/**
- * \note Using #cross_tri_v2 means locations outside the triangle are correctly weighted.
- *
- * \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
- * although it has double precision and is used for texture baking, so keep both.
- */
void barycentric_weights_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3963,11 +3664,6 @@ void barycentric_weights_v2(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * A version of #barycentric_weights_v2 that doesn't allow negative weights.
- * Useful when negative values cause problems and points are only
- * ever slightly outside of the triangle.
- */
void barycentric_weights_v2_clamped(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
@@ -3991,10 +3687,6 @@ void barycentric_weights_v2_clamped(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * still use 2D X,Y space but this works for verts transformed by a perspective matrix,
- * using their 4th component as a weight
- */
void barycentric_weights_v2_persp(
const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
{
@@ -4018,11 +3710,6 @@ void barycentric_weights_v2_persp(
copy_v3_fl(w, 1.0f / 3.0f);
}
-/**
- * same as #barycentric_weights_v2 but works with a quad,
- * NOTE: untested for values outside the quad's bounds
- * this is #interp_weights_poly_v2 expanded for quads only
- */
void barycentric_weights_v2_quad(const float v1[2],
const float v2[2],
const float v3[2],
@@ -4116,9 +3803,6 @@ void barycentric_weights_v2_quad(const float v1[2],
}
}
-/* given 2 triangles in 3D space, and a point in relation to the first triangle.
- * calculate the location of a point in relation to the second triangle.
- * Useful for finding relative positions with geometry */
void transform_point_by_tri_v3(float pt_tar[3],
float const pt_src[3],
const float tri_tar_p1[3],
@@ -4163,10 +3847,6 @@ void transform_point_by_tri_v3(float pt_tar[3],
madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar);
}
-/**
- * Simply re-interpolates,
- * assumes p_src is between \a l_src_p1-l_src_p2
- */
void transform_point_by_seg_v3(float p_dst[3],
const float p_src[3],
const float l_dst_p1[3],
@@ -4178,8 +3858,6 @@ void transform_point_by_seg_v3(float p_dst[3],
interp_v3_v3v3(p_dst, l_dst_p1, l_dst_p2, t);
}
-/* given an array with some invalid values this function interpolates valid values
- * replacing the invalid ones */
int interp_sparse_array(float *array, const int list_size, const float skipval)
{
int found_invalid = 0;
@@ -4516,7 +4194,6 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[
/** \} */
-/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
@@ -4552,13 +4229,6 @@ void interp_cubic_v3(float x[3],
#define IS_ZERO(x) ((x > (-DBL_EPSILON) && x < DBL_EPSILON) ? 1 : 0)
-/**
- * Barycentric reverse
- *
- * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
- *
- * \note same basic result as #barycentric_weights_v2, see its comment for details.
- */
void resolve_tri_uv_v2(
float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2])
{
@@ -4581,11 +4251,6 @@ void resolve_tri_uv_v2(
}
}
-/**
- * Barycentric reverse 3d
- *
- * Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
- */
void resolve_tri_uv_v3(
float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3])
{
@@ -4617,7 +4282,6 @@ void resolve_tri_uv_v3(
}
}
-/* bilinear reverse */
void resolve_quad_uv_v2(float r_uv[2],
const float st[2],
const float st0[2],
@@ -4628,7 +4292,6 @@ void resolve_quad_uv_v2(float r_uv[2],
resolve_quad_uv_v2_deriv(r_uv, NULL, st, st0, st1, st2, st3);
}
-/* bilinear reverse with derivatives */
void resolve_quad_uv_v2_deriv(float r_uv[2],
float r_deriv[2][2],
const float st[2],
@@ -4719,7 +4382,6 @@ void resolve_quad_uv_v2_deriv(float r_uv[2],
}
}
-/* a version of resolve_quad_uv_v2 that only calculates the 'u' */
float resolve_quad_u_v2(const float st[2],
const float st0[2],
const float st1[2],
@@ -4763,7 +4425,6 @@ float resolve_quad_u_v2(const float st[2],
#undef IS_ZERO
-/* reverse of the functions above */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3])
{
float vec[3];
@@ -4797,9 +4458,6 @@ void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
/***************************** View & Projection *****************************/
-/**
- * Matches `glOrtho` result.
- */
void orthographic_m4(float matrix[4][4],
const float left,
const float right,
@@ -4825,9 +4483,6 @@ void orthographic_m4(float matrix[4][4],
matrix[3][2] = -(farClip + nearClip) / Zdelta;
}
-/**
- * Matches `glFrustum` result.
- */
void perspective_m4(float mat[4][4],
const float left,
const float right,
@@ -4873,8 +4528,6 @@ void perspective_m4_fov(float mat[4][4],
mat[1][1] /= nearClip;
}
-/* translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
- * (used to jitter the view) */
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y)
{
if (winmat[2][3] == -1.0f) {
@@ -4903,12 +4556,6 @@ void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x
}
}
-/**
- * Frustum planes extraction from a projection matrix
- * (homogeneous 4d vector representations of planes).
- *
- * plane parameters can be NULL if you do not need them.
- */
void planes_from_projmat(const float mat[4][4],
float left[4],
float right[4],
@@ -5021,14 +4668,6 @@ void projmat_dimensions_db(const float winmat_fl[4][4],
}
}
-/**
- * Creates a projection matrix for a small region of the viewport.
- *
- * \param projmat: Projection Matrix.
- * \param win_size: Viewport Size.
- * \param x_min, x_max, y_min, y_max: Coordinates of the subregion.
- * \return r_projmat: Resulting Projection Matrix.
- */
void projmat_from_subregion(const float projmat[4][4],
const int win_size[2],
const int x_min,
@@ -5363,8 +5002,6 @@ void accumulate_vertex_normals_v3(float n1[3],
}
}
-/* Add weighted face normal component into normals of the face vertices.
- * Caller must pass pre-allocated vdiffs of nverts length. */
void accumulate_vertex_normals_poly_v3(float **vertnos,
const float polyno[3],
const float **vertcos,
@@ -5444,25 +5081,6 @@ void tangent_from_uv_v3(const float uv1[2],
/****************************** Vector Clouds ********************************/
/* vector clouds */
-/**
- * input
- *
- * \param list_size: 4 lists as pointer to array[list_size]
- * \param pos: current pos array of 'new' positions
- * \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights)
- * \param rpos: Reference rpos array of 'old' positions
- * \param rweight: Reference rweight array of 'old'weights
- * (may be NULL pointer if you have no weights).
- *
- * output
- *
- * \param lloc: Center of mass pos.
- * \param rloc: Center of mass rpos.
- * \param lrot: Rotation matrix.
- * \param lscale: Scale matrix.
- *
- * pointers may be NULL if not needed
- */
void vcloud_estimate_transform_v3(const int list_size,
const float (*pos)[3],
@@ -6057,11 +5675,6 @@ float form_factor_hemi_poly(
return contrib;
}
-/**
- * Check if the edge is convex or concave
- * (depends on face winding)
- * Copied from BM_edge_is_convex().
- */
bool is_edge_convex_v3(const float v1[3],
const float v2[3],
const float f1_no[3],
@@ -6078,9 +5691,6 @@ bool is_edge_convex_v3(const float v1[3],
return false;
}
-/**
- * Evaluate if entire quad is a proper convex quad
- */
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
/**
@@ -6176,12 +5786,6 @@ bool is_poly_convex_v2(const float verts[][2], unsigned int nr)
return true;
}
-/**
- * Check if either of the diagonals along this quad create flipped triangles
- * (normals pointing away from eachother).
- * - (1 << 0): (v1-v3) is flipped.
- * - (1 << 1): (v2-v4) is flipped.
- */
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
float d_12[3], d_23[3], d_34[3], d_41[3];
@@ -6232,14 +5836,6 @@ bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
}
-/**
- * Return the value which the distance between points will need to be scaled by,
- * to define a handle, given both points are on a perfect circle.
- *
- * Use when we want a bezier curve to match a circle as closely as possible.
- *
- * \note the return value will need to be divided by 0.75 for correct results.
- */
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
{
BLI_ASSERT_UNIT_V3(tan_l);
@@ -6267,14 +5863,6 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
}
-/**
- * Utility for computing approximate geodesic distances on triangle meshes.
- *
- * Given triangle with vertex coordinates v0, v1, v2, and known geodesic distances
- * dist1 and dist2 at v1 and v2, estimate a geodesic distance at vertex v0.
- *
- * From "Dart Throwing on Surfaces", EGSR 2009. Section 7, Geodesic Dart Throwing.
- */
float geodesic_distance_propagate_across_triangle(
const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2)
{
diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c
index 857cbfbde9c..09028a1eb9a 100644
--- a/source/blender/blenlib/intern/math_geom_inline.c
+++ b/source/blender/blenlib/intern/math_geom_inline.c
@@ -164,7 +164,6 @@ MINLINE void madd_sh_shfl(float r[9], const float sh[9], const float f)
add_sh_shsh(r, r, tmp);
}
-/* get the 2 dominant axis values, 0==X, 1==Y, 2==Z */
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
{
const float xn = fabsf(axis[0]);
@@ -185,7 +184,6 @@ MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
}
}
-/* same as axis_dominant_v3 but return the max value */
MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3])
{
const float xn = fabsf(axis[0]);
@@ -209,7 +207,6 @@ MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axi
}
}
-/* get the single dominant axis value, 0==X, 1==Y, 2==Z */
MINLINE int axis_dominant_v3_single(const float vec[3])
{
const float x = fabsf(vec[0]);
@@ -218,7 +215,6 @@ MINLINE int axis_dominant_v3_single(const float vec[3])
return ((x > y) ? ((x > z) ? 0 : 2) : ((y > z) ? 1 : 2));
}
-/* the dominant axis of an orthogonal vector */
MINLINE int axis_dominant_v3_ortho_single(const float vec[3])
{
const float x = fabsf(vec[0]);
@@ -243,15 +239,6 @@ MINLINE int min_axis_v3(const float vec[3])
return ((x < y) ? ((x < z) ? 0 : 2) : ((y < z) ? 1 : 2));
}
-/**
- * Simple function to either:
- * - Calculate how many triangles needed from the total number of polygons + loops.
- * - Calculate the first triangle index from the polygon index & that polygons loop-start.
- *
- * \param poly_count: The number of polygons or polygon-index
- * (3+ sided faces, 1-2 sided give incorrect results).
- * \param corner_count: The number of corners (also called loop-index).
- */
MINLINE int poly_to_tri_count(const int poly_count, const int corner_count)
{
BLI_assert(!poly_count || corner_count > poly_count * 2);
@@ -263,17 +250,10 @@ MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
return dot_v3v3(co, plane) + plane[3];
}
-/* useful to calculate an even width shell, by taking the angle between 2 planes.
- * The return value is a scale on the offset.
- * no angle between planes is 1.0, as the angle between the 2 planes approaches 180d
- * the distance gets very high, 180d would be inf, but this case isn't valid */
MINLINE float shell_angle_to_dist(const float angle)
{
return (UNLIKELY(angle < SMALL_NUMBER)) ? 1.0f : fabsf(1.0f / cosf(angle));
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`.
- */
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
{
const float angle_cos = fabsf(dot_v3v3(a, b));
@@ -281,9 +261,6 @@ MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
BLI_ASSERT_UNIT_V3(b);
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b))`.
- */
MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
{
const float angle_cos = fabsf(dot_v2v2(a, b));
@@ -292,9 +269,6 @@ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)`.
- */
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3])
{
float angle_cos;
@@ -306,9 +280,6 @@ MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[
return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
-/**
- * Equivalent to `shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)`.
- */
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2])
{
float angle_cos;
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index bd48edf70c0..54beb74abca 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -567,10 +567,11 @@ static void radangle2imp(float a2, float b2, float th, float *A, float *B, float
*F = a2 * b2;
}
-/* all tests here are done to make sure possible overflows are hopefully minimized */
void BLI_ewa_imp2radangle(
float A, float B, float C, float F, float *a, float *b, float *th, float *ecc)
{
+ /* NOTE: all tests here are done to make sure possible overflows are hopefully minimized. */
+
if (F <= 1e-5f) { /* use arbitrary major radius, zero minor, infinite eccentricity */
*a = sqrtf(A > C ? A : C);
*b = 0.0f;
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index b6d80d76be1..eaf76696a0a 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -469,7 +469,6 @@ void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3])
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
}
-/* R = A * B, ignore the elements on the 4th row/column of A */
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4])
{
float B_[4][4], A_[3][3];
@@ -493,7 +492,6 @@ void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4])
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
}
-/* R = A * B, ignore the elements on the 4th row/column of B */
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3])
{
float B_[3][3], A_[4][4];
@@ -636,6 +634,7 @@ void _va_mul_m3_series_9(float r[3][3],
mul_m3_m3m3(r, r, m7);
mul_m3_m3m3(r, r, m8);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -724,6 +723,7 @@ void _va_mul_m4_series_9(float r[4][4],
mul_m4_m4m4(r, r, m7);
mul_m4_m4m4(r, r, m8);
}
+
/** \} */
void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2])
@@ -805,7 +805,6 @@ void mul_m2_v2(const float mat[2][2], float vec[2])
mul_v2_m2v2(vec, mat, vec);
}
-/** Same as #mul_m4_v3() but doesn't apply translation component. */
void mul_mat3_m4_v3(const float M[4][4], float r[3])
{
const float x = r[0];
@@ -1215,16 +1214,6 @@ bool invert_m4(float m[4][4])
return success;
}
-/**
- * Computes the inverse of mat and puts it in inverse.
- * Uses Gaussian Elimination with partial (maximal column) pivoting.
- * \return true on success (i.e. can always find a pivot) and false on failure.
- * Mark Segal - 1992.
- *
- * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
- * for non-invertible scale matrices, finding a partial solution can
- * be useful to have a valid local transform center, see T57767.
- */
bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4])
{
#ifndef MATH_STANDALONE
@@ -1308,14 +1297,6 @@ bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
#endif
}
-/**
- * Combines transformations, handling scale separately in a manner equivalent
- * to the Aligned Inherit Scale mode, in order to avoid creating shear.
- * If A scale is uniform, the result is equivalent to ordinary multiplication.
- *
- * NOTE: this effectively takes output location from simple multiplication,
- * and uses mul_m4_m4m4_split_channels for rotation and scale.
- */
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4])
{
float loc_a[3], rot_a[3][3], size_a[3];
@@ -1332,9 +1313,6 @@ void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
}
-/**
- * Separately combines location, rotation and scale of the input matrices.
- */
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4])
{
float loc_a[3], rot_a[3][3], size_a[3];
@@ -1383,7 +1361,6 @@ void transpose_m3_m3(float R[3][3], const float M[3][3])
R[2][2] = M[2][2];
}
-/* seems obscure but in-fact a common operation */
void transpose_m3_m4(float R[3][3], const float M[4][4])
{
BLI_assert(&R[0][0] != &M[0][0]);
@@ -1461,11 +1438,6 @@ bool compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit)
return false;
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix.
- *
- * \param axis: Axis to build the orthonormal basis around.
- */
void orthogonalize_m3(float R[3][3], int axis)
{
float size[3];
@@ -1550,11 +1522,6 @@ void orthogonalize_m3(float R[3][3], int axis)
mul_v3_fl(R[2], size[2]);
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix.
- *
- * \param axis: Axis to build the orthonormal basis around.
- */
void orthogonalize_m4(float R[4][4], int axis)
{
float size[3];
@@ -1692,14 +1659,6 @@ static void orthogonalize_stable(float v1[3], float v2[3], float v3[3], bool nor
}
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix,
- * in a way that is symmetric and stable to variations in the input, and
- * preserving the value of the determinant, i.e. the overall volume change.
- *
- * \param axis: Axis to build the orthonormal basis around.
- * \param normalize: Normalize the matrix instead of preserving volume.
- */
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
{
switch (axis) {
@@ -1718,14 +1677,6 @@ void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
}
}
-/**
- * Make an orthonormal matrix around the selected axis of the given matrix,
- * in a way that is symmetric and stable to variations in the input, and
- * preserving the value of the determinant, i.e. the overall volume change.
- *
- * \param axis: Axis to build the orthonormal basis around.
- * \param normalize: Normalize the matrix instead of preserving volume.
- */
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
{
switch (axis) {
@@ -2193,10 +2144,6 @@ void mat4_to_size(float size[3], const float M[4][4])
size[2] = len_v3(M[2]);
}
-/**
- * Extract scale factors from the matrix, with correction to ensure
- * exact volume in case of a sheared matrix.
- */
void mat4_to_size_fix_shear(float size[3], const float M[4][4])
{
mat4_to_size(size, M);
@@ -2208,11 +2155,6 @@ void mat4_to_size_fix_shear(float size[3], const float M[4][4])
}
}
-/**
- * This computes the overall volume scale factor of a transformation matrix.
- * For an orthogonal matrix, it is the product of all three scale values.
- * Returns a negative value if the transform is flipped by negative scale.
- */
float mat3_to_volume_scale(const float mat[3][3])
{
return determinant_m3_array(mat);
@@ -2223,11 +2165,6 @@ float mat4_to_volume_scale(const float mat[4][4])
return determinant_m4_mat3_array(mat);
}
-/**
- * This gets the average scale of a matrix, only use when your scaling
- * data that has no idea of scale axis, examples are bone-envelope-radius
- * and curve radius.
- */
float mat3_to_scale(const float mat[3][3])
{
/* unit length vector */
@@ -2246,7 +2183,6 @@ float mat4_to_scale(const float mat[4][4])
return len_v3(unit_vec);
}
-/** Return 2D scale (in XY plane) of given mat4. */
float mat4_to_xy_scale(const float M[4][4])
{
/* unit length vector in xy plane */
@@ -2367,14 +2303,6 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]);
}
-/* TODO: enum for axis? */
-/**
- * Rotate a matrix in-place.
- *
- * \note To create a new rotation matrix see:
- * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
- * (axis & angle args are compatible).
- */
void rotate_m4(float mat[4][4], const char axis, const float angle)
{
const float angle_cos = cosf(angle);
@@ -2412,7 +2340,6 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
}
}
-/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3])
{
mul_v3_fl(mat[0], scale[0]);
@@ -2420,14 +2347,6 @@ void rescale_m4(float mat[4][4], const float scale[3])
mul_v3_fl(mat[2], scale[2]);
}
-/**
- * Scale or rotate around a pivot point,
- * a convenience function to avoid having to do inline.
- *
- * Since its common to make a scale/rotation matrix that pivots around an arbitrary point.
- *
- * Typical use case is to make 3x3 matrix, copy to 4x4, then pass to this function.
- */
void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
{
float tmat[4][4];
@@ -2495,22 +2414,6 @@ void blend_m4_m4m4(float out[4][4],
/* for builds without Eigen */
#ifndef MATH_STANDALONE
-/**
- * A polar-decomposition-based interpolation between matrix A and matrix B.
- *
- * \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
- * (it typically remains below 2 usec on an average i74700,
- * while #blend_m3_m3m3 remains below 0.4 usec).
- * However, it gives expected results even with non-uniformly scaled matrices,
- * see T46418 for an example.
- *
- * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
- *
- * \param R: Resulting interpolated matrix.
- * \param A: Input matrix which is totally effective with `t = 0.0`.
- * \param B: Input matrix which is totally effective with `t = 1.0`.
- * \param t: Interpolation factor.
- */
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t)
{
/* 'Rotation' component ('U' part of polar decomposition,
@@ -2556,15 +2459,6 @@ void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], con
mul_m3_m3m3(R, U, P);
}
-/**
- * Complete transform matrix interpolation,
- * based on polar-decomposition-based interpolation from #interp_m3_m3m3.
- *
- * \param R: Resulting interpolated matrix.
- * \param A: Input matrix which is totally effective with `t = 0.0`.
- * \param B: Input matrix which is totally effective with `t = 1.0`.
- * \param t: Interpolation factor.
- */
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t)
{
float A3[3][3], B3[3][3], R3[3][3];
@@ -2621,10 +2515,6 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
equals_v4v4(mat1[2], mat2[2]) && equals_v4v4(mat1[3], mat2[3]));
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_rot_size_to_mat4(float R[4][4],
const float loc[3],
const float rot[3][3],
@@ -2635,12 +2525,6 @@ void loc_rot_size_to_mat4(float R[4][4],
copy_v3_v3(R[3], loc);
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- *
- * TODO: need to have a version that allows for rotation order...
- */
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
@@ -2665,10 +2549,6 @@ void loc_eul_size_to_mat4(float R[4][4],
R[3][2] = loc[2];
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_eulO_size_to_mat4(float R[4][4],
const float loc[3],
const float eul[3],
@@ -2694,10 +2574,6 @@ void loc_eulO_size_to_mat4(float R[4][4],
R[3][2] = loc[2];
}
-/**
- * Make a 4x4 matrix out of 3 transform components.
- * Matrices are made in the order: `scale * rot * loc`
- */
void loc_quat_size_to_mat4(float R[4][4],
const float loc[3],
const float quat[4],
@@ -2751,18 +2627,11 @@ void print_m4(const char *str, const float m[4][4])
printf("\n");
}
-/*********************************** SVD ************************************
- * from TNT matrix library
- *
- * Compute the Single Value Decomposition of an arbitrary matrix A
- * That is compute the 3 matrices U,W,V with U column orthogonal (m,n)
- * ,W a diagonal matrix and V an orthogonal square matrix `s.t.A = U.W.Vt`.
- * From this decomposition it is trivial to compute the (pseudo-inverse)
- * of `A` as `Ainv = V.Winv.transpose(U)`.
- */
-
void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
{
+ /* NOTE: originally from TNT (template numeric toolkit) matrix library.
+ * https://math.nist.gov/tnt */
+
float A[4][4];
float work1[4], work2[4];
int m = 4;
@@ -3269,12 +3138,6 @@ void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4])
* where we want to specify the length of the degenerate axes.
* \{ */
-/**
- * A safe version of invert that uses valid axes, calculating the zero'd axis
- * based on the non-zero ones.
- *
- * This works well for transformation matrices, when a single axis is zerod.
- */
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
{
if (UNLIKELY(!invert_m4_m4(Ainv, A))) {
@@ -3299,37 +3162,6 @@ void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3])
/** \} */
-/**
- * #SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces
- * (where conversion can be represented by a matrix multiplication).
- *
- * A SpaceTransform is initialized using:
- * - #BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2)
- *
- * After that the following calls can be used:
- * - Converts a coordinate in ob1 space to the corresponding ob2 space:
- * #BLI_space_transform_apply(&data, co);
- * - Converts a coordinate in ob2 space to the corresponding ob1 space:
- * #BLI_space_transform_invert(&data, co);
- *
- * Same concept as #BLI_space_transform_apply and #BLI_space_transform_invert,
- * but no is normalized after conversion (and not translated at all!):
- * - #BLI_space_transform_apply_normal(&data, no);
- * - #BLI_space_transform_invert_normal(&data, no);
- */
-
-/**
- * Global-invariant transform.
- *
- * This defines a matrix transforming a point in local space to a point in target space
- * such that its global coordinates remain unchanged.
- *
- * In other words, if we have a global point P with local coordinates (x, y, z)
- * and global coordinates (X, Y, Z),
- * this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z)
- * where (x', y', z') are the coordinates of P' in target space
- * such that it keeps (X, Y, Z) coordinates in global space.
- */
void BLI_space_transform_from_matrices(SpaceTransform *data,
const float local[4][4],
const float target[4][4])
@@ -3340,18 +3172,6 @@ void BLI_space_transform_from_matrices(SpaceTransform *data,
invert_m4_m4(data->target2local, data->local2target);
}
-/**
- * Local-invariant transform.
- *
- * This defines a matrix transforming a point in global space
- * such that its local coordinates (from local space to target space) remain unchanged.
- *
- * In other words, if we have a local point p with local coordinates (x, y, z)
- * and global coordinates (X, Y, Z),
- * this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z)
- * where (X', Y', Z') are the coordinates of p' in global space
- * such that it keeps (x, y, z) coordinates in target space.
- */
void BLI_space_transform_global_from_matrices(SpaceTransform *data,
const float local[4][4],
const float target[4][4])
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 34baac6f2a4..dbcf3a6500c 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -34,7 +34,6 @@
# define QUAT_EPSILON 0.0001
#endif
-/* convenience, avoids setting Y axis everywhere */
void unit_axis_angle(float axis[3], float *angle)
{
axis[0] = 0.0f;
@@ -75,25 +74,6 @@ void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
q[2] = t2;
}
-/**
- * \note
- * Assumes a unit quaternion?
- *
- * in fact not, but you may want to use a unit quat, read on...
- *
- * Shortcut for 'q v q*' when \a v is actually a quaternion.
- * This removes the need for converting a vector to a quaternion,
- * calculating q's conjugate and converting back to a vector.
- * It also happens to be faster (17+,24* vs * 24+,32*).
- * If \a q is not a unit quaternion, then \a v will be both rotated by
- * the same amount as if q was a unit quaternion, and scaled by the square of
- * the length of q.
- *
- * For people used to python mathutils, its like:
- * def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
- *
- * \note Multiplying by 3x3 matrix is ~25% faster.
- */
void mul_qt_v3(const float q[4], float r[3])
{
float t0, t1, t2;
@@ -150,11 +130,6 @@ void invert_qt_qt(float q1[4], const float q2[4])
invert_qt(q1);
}
-/**
- * This is just conjugate_qt for cases we know \a q is unit-length.
- * we could use #conjugate_qt directly, but use this function to show intent,
- * and assert if its ever becomes non-unit-length.
- */
void invert_qt_normalized(float q[4])
{
BLI_ASSERT_UNIT_QUAT(q);
@@ -167,7 +142,6 @@ void invert_qt_qt_normalized(float q1[4], const float q2[4])
invert_qt_normalized(q1);
}
-/* Simple multiply. */
void mul_qt_fl(float q[4], const float f)
{
q[0] *= f;
@@ -188,7 +162,6 @@ void sub_qt_qtqt(float q[4], const float a[4], const float b[4])
mul_qt_qtqt(q, a, n_b);
}
-/* raise a unit quaternion to the specified power */
void pow_qt_fl_normalized(float q[4], const float fac)
{
BLI_ASSERT_UNIT_QUAT(q);
@@ -200,10 +173,6 @@ void pow_qt_fl_normalized(float q[4], const float fac)
normalize_v3_length(q + 1, si);
}
-/**
- * Apply the rotation of \a a to \a q keeping the values compatible with \a old.
- * Avoid axis flipping for animated f-curves for eg.
- */
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4])
{
const float eps = 1e-4f;
@@ -471,9 +440,6 @@ float normalize_qt_qt(float r[4], const float q[4])
return normalize_qt(r);
}
-/**
- * Calculate a rotation matrix from 2 normalized vectors.
- */
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3])
{
float axis[3];
@@ -511,7 +477,6 @@ void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float
}
}
-/* NOTE: expects vectors to be normalized. */
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3])
{
float axis[3];
@@ -551,16 +516,6 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q
mul_qt_qtqt(q, tquat, q2);
}
-/**
- * Decompose a quaternion into a swing rotation (quaternion with the selected
- * axis component locked at zero), followed by a twist rotation around the axis.
- *
- * \param q: input quaternion.
- * \param axis: twist axis in [0,1,2]
- * \param r_swing: if not NULL, receives the swing quaternion.
- * \param r_twist: if not NULL, receives the twist quaternion.
- * \returns twist angle.
- */
float quat_split_swing_and_twist(const float q_in[4], int axis, float r_swing[4], float r_twist[4])
{
BLI_assert(axis >= 0 && axis <= 2);
@@ -861,14 +816,6 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t)
}
#endif
-/**
- * Generic function for implementing slerp
- * (quaternions and spherical vector coords).
- *
- * \param t: factor in [0..1]
- * \param cosom: dot product from normalized vectors/quats.
- * \param r_w: calculated weights.
- */
void interp_dot_slerp(const float t, const float cosom, float r_w[2])
{
const float eps = 1e-4f;
@@ -925,8 +872,6 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t)
q[3] = a[3] + t * b[3];
}
-/* same as tri_to_quat() but takes pre-computed normal from the triangle
- * used for ngons when we know their normal */
void tri_to_quat_ex(
float quat[4], const float v1[3], const float v2[3], const float v3[3], const float no_orig[3])
{
@@ -979,9 +924,6 @@ void tri_to_quat_ex(
mul_qt_qtqt(quat, q1, q2);
}
-/**
- * \return the length of the normal, use to test for degenerate triangles.
- */
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3])
{
float vec[3];
@@ -1020,7 +962,6 @@ void axis_angle_to_quat(float r[4], const float axis[3], const float angle)
}
}
-/* Quaternions to Axis Angle */
void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
{
float ha, si;
@@ -1054,7 +995,6 @@ void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
}
}
-/* Axis Angle to Euler Rotation */
void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle)
{
float q[4];
@@ -1064,7 +1004,6 @@ void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], co
quat_to_eulO(eul, order, q);
}
-/* Euler Rotation to Axis Angle */
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order)
{
float q[4];
@@ -1074,15 +1013,6 @@ void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const s
quat_to_axis_angle(axis, angle, q);
}
-/**
- * axis angle to 3x3 matrix
- *
- * This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
- *
- * \param axis: rotation axis (must be normalized).
- * \param angle_sin: sin(angle)
- * \param angle_cos: cos(angle)
- */
void axis_angle_normalized_to_mat3_ex(float mat[3][3],
const float axis[3],
const float angle_sin,
@@ -1123,7 +1053,6 @@ void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const flo
axis_angle_normalized_to_mat3_ex(R, axis, sinf(angle), cosf(angle));
}
-/* axis angle to 3x3 matrix - safer version (normalization of axis performed) */
void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle)
{
float nor[3];
@@ -1137,7 +1066,6 @@ void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle)
axis_angle_normalized_to_mat3(R, nor, angle);
}
-/* axis angle to 4x4 matrix - safer version (normalization of axis performed) */
void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle)
{
float tmat[3][3];
@@ -1147,7 +1075,6 @@ void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle)
copy_m4_m3(R, tmat);
}
-/* 3x3 matrix to axis angle */
void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float mat[3][3])
{
float q[4];
@@ -1167,7 +1094,6 @@ void mat3_to_axis_angle(float axis[3], float *angle, const float mat[3][3])
quat_to_axis_angle(axis, angle, q);
}
-/* 4x4 matrix to axis angle */
void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float mat[4][4])
{
float q[4];
@@ -1178,7 +1104,6 @@ void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float mat[
quat_to_axis_angle(axis, angle, q);
}
-/* 4x4 matrix to axis angle */
void mat4_to_axis_angle(float axis[3], float *angle, const float mat[4][4])
{
float q[4];
@@ -1196,7 +1121,6 @@ void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle
copy_m4_m3(R, mat3);
}
-/* rotation matrix from a single axis */
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle)
{
const float angle_cos = cosf(angle);
@@ -1305,7 +1229,6 @@ void expmap_to_quat(float r[4], const float expmap[3])
/******************************** XYZ Eulers *********************************/
-/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3])
{
double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1332,7 +1255,6 @@ void eul_to_mat3(float mat[3][3], const float eul[3])
mat[2][2] = (float)(cj * ci);
}
-/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3])
{
double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1390,7 +1312,6 @@ static void mat3_normalized_to_eul2(const float mat[3][3], float eul1[3], float
}
}
-/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3])
{
float eul1[3], eul2[3];
@@ -1413,7 +1334,6 @@ void mat3_to_eul(float eul[3], const float mat[3][3])
mat3_normalized_to_eul(eul, unit_mat);
}
-/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float m[4][4])
{
float mat3[3][3];
@@ -1427,7 +1347,6 @@ void mat4_to_eul(float eul[3], const float m[4][4])
mat3_to_eul(eul, mat3);
}
-/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4])
{
float unit_mat[3][3];
@@ -1435,7 +1354,6 @@ void quat_to_eul(float eul[3], const float quat[4])
mat3_normalized_to_eul(eul, unit_mat);
}
-/* XYZ order */
void eul_to_quat(float quat[4], const float eul[3])
{
float ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1460,7 +1378,6 @@ void eul_to_quat(float quat[4], const float eul[3])
quat[3] = cj * cs - sj * sc;
}
-/* XYZ order */
void rotate_eul(float beul[3], const char axis, const float ang)
{
float eul[3], mat1[3][3], mat2[3][3], totmat[3][3];
@@ -1486,7 +1403,6 @@ void rotate_eul(float beul[3], const char axis, const float ang)
mat3_to_eul(beul, totmat);
}
-/* order independent! */
void compatible_eul(float eul[3], const float oldrot[3])
{
/* we could use M_PI as pi_thresh: which is correct but 5.1 gives better results.
@@ -1539,7 +1455,6 @@ void compatible_eul(float eul[3], const float oldrot[3])
/* uses 2 methods to retrieve eulers, and picks the closest */
-/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
{
float eul1[3], eul2[3];
@@ -1622,7 +1537,6 @@ static const RotOrderInfo *get_rotation_order_info(const short order)
return &rotOrders[5];
}
-/* Construct quaternion from Euler angles (in radians). */
void eulO_to_quat(float q[4], const float e[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -1660,7 +1574,6 @@ void eulO_to_quat(float q[4], const float e[3], const short order)
}
}
-/* Convert quaternion to Euler angles (in radians). */
void quat_to_eulO(float e[3], short const order, const float q[4])
{
float unit_mat[3][3];
@@ -1669,7 +1582,6 @@ void quat_to_eulO(float e[3], short const order, const float q[4])
mat3_normalized_to_eulO(e, order, unit_mat);
}
-/* Construct 3x3 matrix from Euler angles (in radians). */
void eulO_to_mat3(float M[3][3], const float e[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -1747,7 +1659,6 @@ static void mat3_normalized_to_eulo2(const float mat[3][3],
}
}
-/* Construct 4x4 matrix from Euler angles (in radians). */
void eulO_to_mat4(float mat[4][4], const float e[3], const short order)
{
float unit_mat[3][3];
@@ -1757,7 +1668,6 @@ void eulO_to_mat4(float mat[4][4], const float e[3], const short order)
copy_m4_m3(mat, unit_mat);
}
-/* Convert 3x3 matrix to Euler angles (in radians). */
void mat3_normalized_to_eulO(float eul[3], const short order, const float m[3][3])
{
float eul1[3], eul2[3];
@@ -1783,7 +1693,6 @@ void mat3_to_eulO(float eul[3], const short order, const float m[3][3])
mat3_normalized_to_eulO(eul, order, unit_mat);
}
-/* Convert 4x4 matrix to Euler angles (in radians). */
void mat4_normalized_to_eulO(float eul[3], const short order, const float m[4][4])
{
float mat3[3][3];
@@ -1801,7 +1710,6 @@ void mat4_to_eulO(float eul[3], const short order, const float m[4][4])
mat3_normalized_to_eulO(eul, order, mat3);
}
-/* uses 2 methods to retrieve eulers, and picks the closest */
void mat3_normalized_to_compatible_eulO(float eul[3],
const float oldrot[3],
const short order,
@@ -1901,7 +1809,6 @@ void rotate_eulO(float beul[3], const short order, char axis, float ang)
mat3_to_eulO(beul, order, totmat);
}
-/* the matrix is written to as 3 axis vectors */
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
@@ -2190,7 +2097,6 @@ void copy_dq_dq(DualQuat *r, const DualQuat *dq)
memcpy(r, dq, sizeof(DualQuat));
}
-/* axis matches eTrackToAxis_Modes */
void quat_apply_track(float quat[4], short axis, short upflag)
{
/* rotations are hard coded to match vec_to_quat */
@@ -2271,7 +2177,6 @@ void vec_apply_track(float vec[3], short axis)
}
}
-/* lens/angle conversion (radians) */
float focallength_to_fov(float focal_length, float sensor)
{
return 2.0f * atanf((sensor / 2.0f) / focal_length);
@@ -2298,7 +2203,6 @@ float angle_wrap_deg(float angle)
return mod_inline(angle + 180.0f, 360.0f) - 180.0f;
}
-/* returns an angle compatible with angle_compat */
float angle_compat_rad(float angle, float angle_compat)
{
return angle_compat + angle_wrap_rad(angle - angle_compat);
@@ -2387,10 +2291,6 @@ BLI_INLINE int _axis_signed(const int axis)
return (axis < 3) ? axis : axis - 3;
}
-/**
- * Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
- * where the first 2 are a source and the second 2 are the target.
- */
bool mat3_from_axis_conversion(
int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
{
@@ -2423,9 +2323,6 @@ bool mat3_from_axis_conversion(
return false;
}
-/**
- * Use when the second axis can be guessed.
- */
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3])
{
if (src_axis == dst_axis) {
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index 131afc19f28..f7630efd203 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -32,13 +32,6 @@
/********************************** Eigen Solvers *********************************/
-/**
- * \brief Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
- *
- * \param m3: the 3D symmetric matrix.
- * \return r_eigen_values the computed eigen values (NULL if not needed).
- * \return r_eigen_vectors the computed eigen vectors (NULL if not needed).
- */
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
float r_eigen_values[3],
float r_eigen_vectors[3][3])
@@ -54,14 +47,6 @@ bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors);
}
-/**
- * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
- *
- * \param m3: the matrix to decompose.
- * \return r_U the computed left singular vector of \a m3 (NULL if not needed).
- * \return r_S the computed singular values of \a m3 (NULL if not needed).
- * \return r_V the computed right singular vector of \a m3 (NULL if not needed).
- */
void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3])
{
EIG_svd_square_matrix(3, (const float *)m3, (float *)r_U, (float *)r_S, (float *)r_V);
@@ -69,16 +54,6 @@ void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3
/***************************** Simple Solvers ************************************/
-/**
- * \brief Solve a tridiagonal system of equations:
- *
- * a[i] * r_x[i-1] + b[i] * r_x[i] + c[i] * r_x[i+1] = d[i]
- *
- * Ignores a[0] and c[count-1]. Uses the Thomas algorithm, e.g. see wiki.
- *
- * \param r_x: output vector, may be shared with any of the input ones
- * \return true if success
- */
bool BLI_tridiagonal_solve(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
{
@@ -124,12 +99,6 @@ bool BLI_tridiagonal_solve(
return isfinite(x_prev);
}
-/**
- * \brief Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
- *
- * \param r_x: output vector, may be shared with any of the input ones
- * \return true if success
- */
bool BLI_tridiagonal_solve_cyclic(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
{
@@ -194,21 +163,6 @@ bool BLI_tridiagonal_solve_cyclic(
return success;
}
-/**
- * \brief Solve a generic f(x) = 0 equation using Newton's method.
- *
- * \param func_delta: Callback computing the value of f(x).
- * \param func_jacobian: Callback computing the Jacobian matrix of the function at x.
- * \param func_correction: Callback for forcing the search into an arbitrary custom domain.
- * May be NULL.
- * \param userdata: Data for the callbacks.
- * \param epsilon: Desired precision.
- * \param max_iterations: Limit on the iterations.
- * \param trace: Enables logging to console.
- * \param x_init: Initial solution vector.
- * \param result: Final result.
- * \return true if success
- */
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
Newton3D_JacobianFunc func_jacobian,
Newton3D_CorrectionFunc func_correction,
diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c
index b90ac99dbfe..8087e7a962a 100644
--- a/source/blender/blenlib/intern/math_statistics.c
+++ b/source/blender/blenlib/intern/math_statistics.c
@@ -87,18 +87,6 @@ static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
}
}
-/**
- * \brief Compute the covariance matrix of given set of nD coordinates.
- *
- * \param n: the dimension of the vectors (and hence, of the covariance matrix to compute).
- * \param cos_vn: the nD points to compute covariance from.
- * \param nbr_cos_vn: the number of nD coordinates in cos_vn.
- * \param center: the center (or mean point) of cos_vn. If NULL,
- * it is assumed cos_vn is already centered.
- * \param use_sample_correction: whether to apply sample correction
- * (i.e. get 'sample variance' instead of 'population variance').
- * \return r_covmat the computed covariance matrix.
- */
void BLI_covariance_m_vn_ex(const int n,
const float *cos_vn,
const int nbr_cos_vn,
@@ -128,14 +116,6 @@ void BLI_covariance_m_vn_ex(const int n,
BLI_task_parallel_range(0, n * n, &data, covariance_m_vn_ex_task_cb, &settings);
}
-/**
- * \brief Compute the covariance matrix of given set of 3D coordinates.
- *
- * \param cos_v3: the 3D points to compute covariance from.
- * \param nbr_cos_v3: the number of 3D coordinates in cos_v3.
- * \return r_covmat the computed covariance matrix.
- * \return r_center the computed center (mean) of 3D points (may be NULL).
- */
void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
const int nbr_cos_v3,
const bool use_sample_correction,
diff --git a/source/blender/blenlib/intern/math_time.c b/source/blender/blenlib/intern/math_time.c
index b85de7817dd..4484144a81e 100644
--- a/source/blender/blenlib/intern/math_time.c
+++ b/source/blender/blenlib/intern/math_time.c
@@ -23,13 +23,6 @@
#include "BLI_math.h"
-/** Explode given time value expressed in seconds, into a set of days, hours, minutes, seconds
- * and/or milliseconds (depending on which return parameters are not NULL).
- *
- * \note The smallest given return parameter will get the potential fractional remaining time
- * value. E.g. if you give `seconds=90.0` and do not pass `r_seconds` and `r_milliseconds`,
- * `r_minutes` will be set to `1.5`.
- */
void BLI_math_time_seconds_decompose(double seconds,
double *r_days,
double *r_hours,
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 35dfe421cf0..a0afab8a179 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -37,8 +37,6 @@ void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float
r[1] = s * a[1] + t * b[1];
}
-/* weight 3 2D vectors,
- * 'w' must be unit length but is not a vector, just 3 weights */
void interp_v2_v2v2v2(
float r[2], const float a[2], const float b[2], const float c[2], const float t[3])
{
@@ -65,12 +63,6 @@ void interp_v4_v4v4(float r[4], const float a[4], const float b[4], const float
r[3] = s * a[3] + t * b[3];
}
-/**
- * slerp, treat vectors as spherical coordinates
- * \see #interp_qt_qtqt
- *
- * \return success
- */
bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t)
{
float cosom, w[2];
@@ -115,9 +107,6 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c
return true;
}
-/**
- * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors.
- */
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t)
{
if (UNLIKELY(!interp_v3_v3v3_slerp(target, a, b, t))) {
@@ -186,8 +175,6 @@ void interp_v2_v2v2v2v2_cubic(float p[2],
/** \} */
-/* weight 3 vectors,
- * 'w' must be unit length but is not a vector, just 3 weights */
void interp_v3_v3v3v3(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
{
@@ -196,8 +183,6 @@ void interp_v3_v3v3v3(
p[2] = v1[2] * w[0] + v2[2] * w[1] + v3[2] * w[2];
}
-/* weight 3 vectors,
- * 'w' must be unit length but is not a vector, just 4 weights */
void interp_v3_v3v3v3v3(float p[3],
const float v1[3],
const float v2[3],
@@ -311,18 +296,6 @@ void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const uint nbr)
}
}
-/**
- * Specialized function for calculating normals.
- * Fast-path for:
- *
- * \code{.c}
- * add_v3_v3v3(r, a, b);
- * normalize_v3(r)
- * mul_v3_fl(r, angle_normalized_v3v3(a, b) / M_PI_2);
- * \endcode
- *
- * We can use the length of (a + b) to calculate the angle.
- */
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3])
{
/* trick, we want the middle of 2 normals as well as the angle between them
@@ -341,10 +314,6 @@ void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3])
acosf(normalize_v3(r) / 2.0f);
mul_v3_fl(r, angle);
}
-/**
- * Same as mid_v3_v3v3_angle_weighted
- * but \a r is assumed to be accumulated normals, divided by their total.
- */
void mid_v3_angle_weighted(float r[3])
{
/* trick, we want the middle of 2 normals as well as the angle between them
@@ -407,13 +376,6 @@ bool is_finite_v4(const float v[4])
/********************************** Angles ***********************************/
-/* Return the angle in radians between vecs 1-2 and 2-3 in radians
- * If v1 is a shoulder, v2 is the elbow and v3 is the hand,
- * this would return the angle at the elbow.
- *
- * note that when v1/v2/v3 represent 3 points along a straight line
- * that the angle returned will be pi (180deg), rather than 0.0
- */
float angle_v3v3v3(const float a[3], const float b[3], const float c[3])
{
float vec1[3], vec2[3];
@@ -426,7 +388,6 @@ float angle_v3v3v3(const float a[3], const float b[3], const float c[3])
return angle_normalized_v3v3(vec1, vec2);
}
-/* Quicker than full angle computation */
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3])
{
float vec1[3], vec2[3];
@@ -439,7 +400,6 @@ float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3])
return dot_v3v3(vec1, vec2);
}
-/* Return the shortest angle in radians between the 2 vectors */
float angle_v3v3(const float a[3], const float b[3])
{
float vec1[3], vec2[3];
@@ -466,7 +426,6 @@ float angle_v2v2v2(const float a[2], const float b[2], const float c[2])
return angle_normalized_v2v2(vec1, vec2);
}
-/* Quicker than full angle computation */
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2])
{
float vec1[2], vec2[2];
@@ -479,7 +438,6 @@ float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2])
return dot_v2v2(vec1, vec2);
}
-/* Return the shortest angle in radians between the 2 vectors */
float angle_v2v2(const float a[2], const float b[2])
{
float vec1[2], vec2[2];
@@ -534,9 +492,6 @@ float angle_normalized_v2v2(const float a[2], const float b[2])
return (float)M_PI - 2.0f * saasin(len_v2v2(a, v2_n) / 2.0f);
}
-/**
- * Angle between 2 vectors, about an axis (axis can be considered a plane).
- */
float angle_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3])
{
float v1_proj[3], v2_proj[3];
@@ -568,9 +523,6 @@ float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const f
return angle;
}
-/**
- * Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
- */
float angle_on_axis_v3v3v3_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -652,9 +604,6 @@ void angle_poly_v3(float *angles, const float *verts[3], int len)
/********************************* Geometry **********************************/
-/**
- * Project \a p onto \a v_proj
- */
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
{
if (UNLIKELY(is_zero_v2(v_proj))) {
@@ -666,9 +615,6 @@ void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2])
mul_v2_v2fl(out, v_proj, mul);
}
-/**
- * Project \a p onto \a v_proj
- */
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3])
{
if (UNLIKELY(is_zero_v3(v_proj))) {
@@ -691,9 +637,6 @@ void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]
mul_v3_v3db_db(out, v_proj, mul);
}
-/**
- * Project \a p onto a unit length \a v_proj
- */
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2])
{
BLI_ASSERT_UNIT_V2(v_proj);
@@ -702,9 +645,6 @@ void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_pr
mul_v2_v2fl(out, v_proj, mul);
}
-/**
- * Project \a p onto a unit length \a v_proj
- */
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3])
{
BLI_ASSERT_UNIT_V3(v_proj);
@@ -713,19 +653,6 @@ void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_pr
mul_v3_v3fl(out, v_proj, mul);
}
-/**
- * In this case plane is a 3D vector only (no 4th component).
- *
- * Projecting will make \a out a copy of \a p orthogonal to \a v_plane.
- *
- * \note If \a p is exactly perpendicular to \a v_plane, \a out will just be a copy of \a p.
- *
- * \note This function is a convenience to call:
- * \code{.c}
- * project_v3_v3v3(out, p, v_plane);
- * sub_v3_v3v3(out, p, out);
- * \endcode
- */
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
{
const float mul = dot_v3v3(p, v_plane) / dot_v3v3(v_plane, v_plane);
@@ -756,7 +683,6 @@ void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const floa
madd_v2_v2v2fl(out, p, v_plane, -mul);
}
-/* project a vector on a plane defined by normal and a plane point p */
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3])
{
float vector[3];
@@ -769,7 +695,6 @@ void project_v3_plane(float out[3], const float plane_no[3], const float plane_c
madd_v3_v3fl(out, plane_no, -mul);
}
-/* Returns a vector bisecting the angle at b formed by a, b and c */
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
{
float d_12[3], d_23[3];
@@ -781,22 +706,6 @@ void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const floa
normalize_v3(r);
}
-/**
- * Returns a reflection vector from a vector and a normal vector
- * reflect = vec - ((2 * dot(vec, mirror)) * mirror).
- *
- * <pre>
- * v
- * + ^
- * \ |
- * \|
- * + normal: axis of reflection
- * /
- * /
- * +
- * out: result (negate for a 'bounce').
- * </pre>
- */
void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
{
BLI_ASSERT_UNIT_V3(normal);
@@ -813,11 +722,6 @@ void reflect_v3_v3v3_db(double out[3], const double v[3], const double normal[3]
madd_v3_v3v3db_db(out, v, normal, -dot2);
}
-/**
- * Takes a vector and computes 2 orthogonal directions.
- *
- * \note if \a n is n unit length, computed values will be too.
- */
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
{
const float eps = FLT_EPSILON;
@@ -843,11 +747,6 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
}
}
-/**
- * Calculates \a p - a perpendicular vector to \a v
- *
- * \note return vector won't maintain same length.
- */
void ortho_v3_v3(float out[3], const float v[3])
{
const int axis = axis_dominant_v3_single(v);
@@ -873,9 +772,6 @@ void ortho_v3_v3(float out[3], const float v[3])
}
}
-/**
- * no brainer compared to v3, just have for consistency.
- */
void ortho_v2_v2(float out[2], const float v[2])
{
BLI_assert(out != v);
@@ -884,9 +780,6 @@ void ortho_v2_v2(float out[2], const float v[2])
out[1] = v[0];
}
-/**
- * Rotate a point \a p by \a angle around origin (0, 0)
- */
void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
{
const float co = cosf(angle);
@@ -898,10 +791,6 @@ void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
r[1] = si * p[0] + co * p[1];
}
-/**
- * Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
- * http://local.wasp.uwa.edu.au/~pbourke/geometry/
- */
void rotate_normalized_v3_v3v3fl(float out[3],
const float p[3],
const float axis[3],
@@ -1040,7 +929,6 @@ void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)
}
}
-/** ensure \a v1 is \a dist from \a v2 */
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist)
{
if (!equals_v3v3(v2, v1)) {
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index bb32b511005..648f876acaa 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -101,6 +101,7 @@ MINLINE void copy_v4_fl(float r[4], float f)
}
/* unsigned char */
+
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2])
{
r[0] = a[0];
@@ -144,6 +145,7 @@ MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a)
}
/* char */
+
MINLINE void copy_v2_v2_char(char r[2], const char a[2])
{
r[0] = a[0];
@@ -224,6 +226,7 @@ MINLINE void copy_v4_v4_int(int r[4], const int a[4])
}
/* double */
+
MINLINE void zero_v3_db(double r[3])
{
r[0] = 0.0;
@@ -252,7 +255,6 @@ MINLINE void copy_v4_v4_db(double r[4], const double a[4])
r[3] = a[3];
}
-/* int <-> float */
MINLINE void round_v2i_v2fl(int r[2], const float a[2])
{
r[0] = (int)roundf(a[0]);
@@ -266,6 +268,7 @@ MINLINE void copy_v2fl_v2i(float r[2], const int a[2])
}
/* double -> float */
+
MINLINE void copy_v2fl_v2db(float r[2], const double a[2])
{
r[0] = (float)a[0];
@@ -288,6 +291,7 @@ MINLINE void copy_v4fl_v4db(float r[4], const double a[4])
}
/* float -> double */
+
MINLINE void copy_v2db_v2fl(double r[2], const float a[2])
{
r[0] = (double)a[0];
@@ -331,6 +335,7 @@ MINLINE void swap_v4_v4(float a[4], float b[4])
}
/* float args -> vec */
+
MINLINE void copy_v2_fl2(float v[2], float x, float y)
{
v[0] = x;
@@ -639,26 +644,11 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2])
r[1] = mat[1] * vec[0] + (+mat[0]) * vec[1];
}
-/**
- * Convenience function to get the projected depth of a position.
- * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
- *
- * Matches logic for:
- *
- * \code{.c}
- * float co_4d[4] = {co[0], co[1], co[2], 1.0};
- * mul_m4_v4(mat, co_4d);
- * return co_4d[3];
- * \endcode
- */
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3])
{
return (mat[0][3] * co[0]) + (mat[1][3] * co[1]) + (mat[2][3] * co[2]) + mat[3][3];
}
-/**
- * Has the effect of #mul_m3_v3(), on a single axis.
- */
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3])
{
return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
@@ -672,10 +662,6 @@ MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3])
return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
-/**
- * Has the effect of #mul_mat3_m4_v3(), on a single axis.
- * (no adding translation)
- */
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3])
{
return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
@@ -817,7 +803,6 @@ MINLINE void negate_v4_v4(float r[4], const float a[4])
r[3] = -a[3];
}
-/* could add more... */
MINLINE void negate_v3_short(short r[3])
{
r[0] = (short)-r[0];
@@ -962,8 +947,6 @@ MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
r[2] = a[0] * b[1] - a[1] * b[0];
}
-/* cross product suffers from severe precision loss when vectors are
- * nearly parallel or opposite; doing the computation in double helps a lot */
MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3])
{
BLI_assert(r != a && r != b);
@@ -980,10 +963,6 @@ MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3])
r[2] = a[0] * b[1] - a[1] * b[0];
}
-/* Newell's Method */
-/* excuse this fairly specific function,
- * its used for polygon normals all over the place
- * could use a better name */
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
{
n[0] += (v_prev[1] - v_curr[1]) * (v_prev[2] + v_curr[2]);
@@ -1158,9 +1137,6 @@ MINLINE float len_v4v4(const float a[4], const float b[4])
return len_v4(d);
}
-/**
- * \note any vectors containing `nan` will be zeroed out.
- */
MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_length)
{
float d = dot_v2v2(a, a);
@@ -1192,9 +1168,6 @@ MINLINE float normalize_v2_length(float n[2], const float unit_length)
return normalize_v2_v2_length(n, n, unit_length);
}
-/**
- * \note any vectors containing `nan` will be zeroed out.
- */
MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_length)
{
float d = dot_v3v3(a, a);
@@ -1498,18 +1471,6 @@ MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4])
/** \} */
-/**
- * <pre>
- * + l1
- * |
- * neg <- | -> pos
- * |
- * + l2
- * </pre>
- *
- * \return Positive value when 'pt' is left-of-line
- * (looking from 'l1' -> 'l2').
- */
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2])
{
return (((l1[0] - pt[0]) * (l2[1] - pt[1])) - ((l2[0] - pt[0]) * (l1[1] - pt[1])));
diff --git a/source/blender/blenlib/intern/memory_utils.c b/source/blender/blenlib/intern/memory_utils.c
index 4bb93877401..2befcb1bb19 100644
--- a/source/blender/blenlib/intern/memory_utils.c
+++ b/source/blender/blenlib/intern/memory_utils.c
@@ -30,9 +30,6 @@
#include "BLI_strict_flags.h"
-/**
- * Check if memory is zeroed, as with `memset(arr, 0, arr_size)`.
- */
bool BLI_memory_is_zero(const void *arr, const size_t arr_size)
{
const char *arr_byte = arr;
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index 8b029d11c3f..ce4db0c6b9d 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -1370,6 +1370,11 @@ static bool is_pwn(const IMesh &tm, const TriMeshTopology &tmtopo)
}
threading::parallel_for(tris.index_range(), 2048, [&](IndexRange range) {
+ if (!is_pwn.load()) {
+ /* Early out if mesh is already determined to be non-pwn. */
+ return;
+ }
+
for (int j : range) {
const Edge &edge = tris[j].first;
int tot_orient = 0;
@@ -1395,9 +1400,7 @@ static bool is_pwn(const IMesh &tm, const TriMeshTopology &tmtopo)
std::cout << "edge causing non-pwn: " << edge << "\n";
}
is_pwn = false;
-# ifdef WITH_TBB
- tbb::task::self().cancel_group_execution();
-# endif
+ break;
}
}
});
@@ -3673,10 +3676,6 @@ static void dump_test_spec(IMesh &imesh)
}
}
-/**
- * Do the boolean operation op on the polygon mesh imesh_in.
- * See the header file for a complete description.
- */
IMesh boolean_mesh(IMesh &imesh,
BoolOpType op,
int nshapes,
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc
index feb7b64f766..ab1db3f1fda 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -150,7 +150,6 @@ Plane::Plane(const double3 &norm, const double d) : norm(norm), d(d)
norm_exact = mpq3(0, 0, 0); /* Marks as "exact not yet populated". */
}
-/** This is wrong for degenerate planes, but we don't expect to call it on those. */
bool Plane::exact_populated() const
{
return norm_exact[0] != 0 || norm_exact[1] != 0 || norm_exact[2] != 0;
@@ -803,11 +802,6 @@ std::ostream &operator<<(std::ostream &os, const IMesh &mesh)
return os;
}
-/**
- * Assume bounding boxes have been expanded by a sufficient epsilon on all sides
- * so that the comparisons against the bb bounds are sufficient to guarantee that
- * if an overlap or even touching could happen, this will return true.
- */
bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b)
{
return isect_aabb_aabb_v3(bb_a.min, bb_a.max, bb_b.min, bb_b.max);
@@ -2276,12 +2270,6 @@ static Array<Face *> triangulate_poly(Face *f, IMeshArena *arena)
return ans;
}
-/**
- * Return an #IMesh that is a triangulation of a mesh with general
- * polygonal faces, #IMesh.
- * Added diagonals will be distinguishable by having edge original
- * indices of #NO_INDEX.
- */
IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena)
{
Vector<Face *> face_tris;
@@ -2568,79 +2556,6 @@ static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map,
}
/**
- * Data needed for parallelization of calc_subdivided_non_cluster_tris.
- */
-struct OverlapTriRange {
- int tri_index;
- int overlap_start;
- int len;
-};
-struct SubdivideTrisData {
- Array<IMesh> &r_tri_subdivided;
- const IMesh &tm;
- const Map<std::pair<int, int>, ITT_value> &itt_map;
- Span<BVHTreeOverlap> overlap;
- IMeshArena *arena;
-
- /* This vector gives, for each triangle in tm that has an intersection
- * we want to calculate: what the index of that triangle in tm is,
- * where it starts in the ov structure as indexA, and how many
- * overlap pairs have that same indexA (they will be continuous). */
- Vector<OverlapTriRange> overlap_tri_range;
-
- SubdivideTrisData(Array<IMesh> &r_tri_subdivided,
- const IMesh &tm,
- const Map<std::pair<int, int>, ITT_value> &itt_map,
- Span<BVHTreeOverlap> overlap,
- IMeshArena *arena)
- : r_tri_subdivided(r_tri_subdivided),
- tm(tm),
- itt_map(itt_map),
- overlap(overlap),
- arena(arena)
- {
- }
-};
-
-static void calc_subdivided_tri_range_func(void *__restrict userdata,
- const int iter,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- constexpr int dbg_level = 0;
- SubdivideTrisData *data = static_cast<SubdivideTrisData *>(userdata);
- OverlapTriRange &otr = data->overlap_tri_range[iter];
- int t = otr.tri_index;
- if (dbg_level > 0) {
- std::cout << "calc_subdivided_tri_range_func\nt=" << t << " start=" << otr.overlap_start
- << " len=" << otr.len << "\n";
- }
- constexpr int inline_capacity = 100;
- Vector<ITT_value, inline_capacity> itts(otr.len);
- for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
- int t_other = data->overlap[j].indexB;
- std::pair<int, int> key = canon_int_pair(t, t_other);
- ITT_value itt;
- if (data->itt_map.contains(key)) {
- itt = data->itt_map.lookup(key);
- }
- if (itt.kind != INONE) {
- itts.append(itt);
- }
- if (dbg_level > 0) {
- std::cout << " tri t" << t_other << "; result = " << itt << "\n";
- }
- }
- if (itts.size() > 0) {
- CDT_data cd_data = prepare_cdt_input(data->tm, t, itts);
- do_cdt(cd_data);
- data->r_tri_subdivided[t] = extract_subdivided_tri(cd_data, data->tm, t, data->arena);
- if (dbg_level > 0) {
- std::cout << "subdivide output\n" << data->r_tri_subdivided[t];
- }
- }
-}
-
-/**
* For each triangle in tm, fill in the corresponding slot in
* r_tri_subdivided with the result of intersecting it with
* all the other triangles in the mesh, if it intersects any others.
@@ -2658,10 +2573,14 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
std::cout << "\nCALC_SUBDIVIDED_TRIS\n\n";
}
Span<BVHTreeOverlap> overlap = ov.overlap();
- SubdivideTrisData data(r_tri_subdivided, tm, itt_map, overlap, arena);
+ struct OverlapTriRange {
+ int tri_index;
+ int overlap_start;
+ int len;
+ };
+ Vector<OverlapTriRange> overlap_tri_range;
int overlap_tot = overlap.size();
- data.overlap_tri_range = Vector<OverlapTriRange>();
- data.overlap_tri_range.reserve(overlap_tot);
+ overlap_tri_range.reserve(overlap_tot);
int overlap_index = 0;
while (overlap_index < overlap_tot) {
int t = overlap[overlap_index].indexA;
@@ -2676,7 +2595,7 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
int len = i - overlap_index + 1;
if (!(len == 1 && overlap[overlap_index].indexB == t)) {
OverlapTriRange range = {t, overlap_index, len};
- data.overlap_tri_range.append(range);
+ overlap_tri_range.append(range);
# ifdef PERFDEBUG
bumpperfcount(0, len); /* Non-cluster overlaps. */
# endif
@@ -2684,13 +2603,50 @@ static void calc_subdivided_non_cluster_tris(Array<IMesh> &r_tri_subdivided,
}
overlap_index = i + 1;
}
- int overlap_tri_range_tot = data.overlap_tri_range.size();
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 50;
- settings.use_threading = intersect_use_threading;
- BLI_task_parallel_range(
- 0, overlap_tri_range_tot, &data, calc_subdivided_tri_range_func, &settings);
+ int overlap_tri_range_tot = overlap_tri_range.size();
+ Array<CDT_data> cd_data(overlap_tri_range_tot);
+ int grain_size = 64;
+ threading::parallel_for(overlap_tri_range.index_range(), grain_size, [&](IndexRange range) {
+ for (int otr_index : range) {
+ OverlapTriRange &otr = overlap_tri_range[otr_index];
+ int t = otr.tri_index;
+ if (dbg_level > 0) {
+ std::cout << "handling overlap range\nt=" << t << " start=" << otr.overlap_start
+ << " len=" << otr.len << "\n";
+ }
+ constexpr int inline_capacity = 100;
+ Vector<ITT_value, inline_capacity> itts(otr.len);
+ for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
+ int t_other = overlap[j].indexB;
+ std::pair<int, int> key = canon_int_pair(t, t_other);
+ ITT_value itt;
+ if (itt_map.contains(key)) {
+ itt = itt_map.lookup(key);
+ }
+ if (itt.kind != INONE) {
+ itts.append(itt);
+ }
+ if (dbg_level > 0) {
+ std::cout << " tri t" << t_other << "; result = " << itt << "\n";
+ }
+ }
+ if (itts.size() > 0) {
+ cd_data[otr_index] = prepare_cdt_input(tm, t, itts);
+ do_cdt(cd_data[otr_index]);
+ }
+ }
+ });
+ /* Extract the new faces serially, so that Boolean is repeatable regardless of parallelism. */
+ for (int otr_index : overlap_tri_range.index_range()) {
+ CDT_data &cdd = cd_data[otr_index];
+ if (cdd.vert.size() > 0) {
+ int t = overlap_tri_range[otr_index].tri_index;
+ r_tri_subdivided[t] = extract_subdivided_tri(cdd, tm, t, arena);
+ if (dbg_level > 1) {
+ std::cout << "subdivide output for tri " << t << " = " << r_tri_subdivided[t];
+ }
+ }
+ }
/* Now have to put in the triangles that are the same as the input ones, and not in clusters.
*/
threading::parallel_for(tm.face_index_range(), 2048, [&](IndexRange range) {
@@ -2994,7 +2950,6 @@ static IMesh remove_degenerate_tris(const IMesh &tm_in)
return ans;
}
-/* This is the main routine for calculating the self_intersection of a triangle mesh. */
IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena)
{
return trimesh_nary_intersect(
@@ -3169,9 +3124,6 @@ static std::ostream &operator<<(std::ostream &os, const ITT_value &itt)
return os;
}
-/**
- * Writing the obj_mesh has the side effect of populating verts.
- */
void write_obj_mesh(IMesh &m, const std::string &objname)
{
/* Would like to use #BKE_tempdir_base() here, but that brings in dependence on kernel library.
@@ -3227,7 +3179,7 @@ struct PerfCounts {
static PerfCounts *perfdata = nullptr;
-static void perfdata_init(void)
+static void perfdata_init()
{
perfdata = new PerfCounts;
@@ -3279,7 +3231,7 @@ static void doperfmax(int maxnum, int val)
perfdata->max[maxnum] = max_ii(perfdata->max[maxnum], val);
}
-static void dump_perfdata(void)
+static void dump_perfdata()
{
std::cout << "\nPERFDATA\n";
for (int i : perfdata->count.index_range()) {
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index a0938f4f713..ce4dee16d32 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -429,15 +429,17 @@ static float orgBlenderNoise(float x, float y, float z)
return n;
}
-/* as orgBlenderNoise(), returning signed noise */
static float orgBlenderNoiseS(float x, float y, float z)
{
+ /* NOTE: As #orgBlenderNoise(), returning signed noise. */
+
return (2.0f * orgBlenderNoise(x, y, z) - 1.0f);
}
-/* separated from orgBlenderNoise above, with scaling */
float BLI_noise_hnoise(float noisesize, float x, float y, float z)
{
+ /* NOTE: Separated from orgBlenderNoise, with scaling. */
+
if (noisesize == 0.0f) {
return 0.0f;
}
@@ -447,7 +449,6 @@ float BLI_noise_hnoise(float noisesize, float x, float y, float z)
return orgBlenderNoise(x, y, z);
}
-/* original turbulence functions */
float BLI_noise_turbulence(float noisesize, float x, float y, float z, int nr)
{
float s, d = 0.5, div = 1.0;
@@ -926,8 +927,6 @@ static float dist_Minkovsky(float x, float y, float z, float e)
return powf(powf(fabsf(x), e) + powf(fabsf(y), e) + powf(fabsf(z), e), 1.0f / e);
}
-/* Not 'pure' Worley, but the results are virtually the same.
- * Returns distances in da and point coords in pa */
void BLI_noise_voronoi(float x, float y, float z, float *da, float *pa, float me, int dtype)
{
float (*distfunc)(float, float, float, float);
@@ -1137,13 +1136,11 @@ static float BLI_cellNoiseU(float x, float y, float z)
return ((float)(n * (n * n * 15731 + 789221) + 1376312589) / 4294967296.0f);
}
-/* idem, signed */
float BLI_noise_cell(float x, float y, float z)
{
return (2.0f * BLI_cellNoiseU(x, y, z) - 1.0f);
}
-/* returns a vector/point/color in ca, using point hasharray directly */
void BLI_noise_cell_v3(float x, float y, float z, float ca[3])
{
/* avoid precision issues on unit coordinates */
@@ -1166,9 +1163,6 @@ void BLI_noise_cell_v3(float x, float y, float z, float ca[3])
/** \name Public API's
* \{ */
-/**
- * newnoise: generic noise function for use with different `noisebasis`.
- */
float BLI_noise_generic_noise(
float noisesize, float x, float y, float z, bool hard, int noisebasis)
{
@@ -1226,7 +1220,6 @@ float BLI_noise_generic_noise(
return noisefunc(x, y, z);
}
-/* newnoise: generic turbulence function for use with different noisebasis */
float BLI_noise_generic_turbulence(
float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis)
{
@@ -1289,21 +1282,12 @@ float BLI_noise_generic_turbulence(
return sum;
}
-/*
- * The following code is based on Ken Musgrave's explanations and sample
- * source code in the book "Texturing and Modeling: A procedural approach"
- */
-
-/**
- * Procedural `fBm` evaluated at "point"; returns value stored in "value".
- *
- * \param H: is the fractal increment parameter.
- * \param lacunarity: is the gap between successive frequencies.
- * \param octaves: is the number of frequencies in the `fBm`.
- */
float BLI_noise_mg_fbm(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
{
+ /* The following code is based on Ken Musgrave's explanations and sample
+ * source code in the book "Texturing and Modeling: A procedural approach". */
+
float (*noisefunc)(float, float, float);
switch (noisebasis) {
case 1:
@@ -1358,24 +1342,13 @@ float BLI_noise_mg_fbm(
} /* fBm() */
-/**
- * Procedural multi-fractal evaluated at "point";
- * returns value stored in "value".
- *
- * \param H: determines the highest fractal dimension.
- * \param lacunarity: is gap between successive frequencies.
- * \param octaves: is the number of frequencies in the `fBm`.
- *
- * \note There used to be a parameter called `offset`, old docs read:
- * is the zero offset, which determines multi-fractality.
- */
-
-/* this one is in fact rather confusing,
- * there seem to be errors in the original source code (in all three versions of proc.text&mod),
- * I modified it to something that made sense to me, so it might be wrong... */
float BLI_noise_mg_multi_fractal(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
{
+ /* This one is in fact rather confusing,
+ * there seem to be errors in the original source code (in all three versions of proc.text&mod),
+ * I modified it to something that made sense to me, so it might be wrong. */
+
float (*noisefunc)(float, float, float);
switch (noisebasis) {
case 1:
@@ -1428,15 +1401,6 @@ float BLI_noise_mg_multi_fractal(
return value;
}
-/**
- * Heterogeneous procedural terrain function: stats by altitude method.
- * Evaluated at "point"; returns value stored in "value".
- *
- * \param H: Determines the fractal dimension of the roughest areas.
- * \param lacunarity: Is the gap between successive frequencies.
- * \param octaves: Is the number of frequencies in the `fBm`.
- * \param offset: Raises the terrain from `sea level`.
- */
float BLI_noise_mg_hetero_terrain(float x,
float y,
float z,
@@ -1507,13 +1471,6 @@ float BLI_noise_mg_hetero_terrain(float x,
return value;
}
-/* Hybrid additive/multiplicative multifractal terrain model.
- *
- * Some good parameter values to start with:
- *
- * H: 0.25
- * offset: 0.7
- */
float BLI_noise_mg_hybrid_multi_fractal(float x,
float y,
float z,
@@ -1590,14 +1547,6 @@ float BLI_noise_mg_hybrid_multi_fractal(float x,
} /* HybridMultifractal() */
-/* Ridged multifractal terrain model.
- *
- * Some good parameter values to start with:
- *
- * H: 1.0
- * offset: 1.0
- * gain: 2.0
- */
float BLI_noise_mg_ridged_multi_fractal(float x,
float y,
float z,
@@ -1669,9 +1618,6 @@ float BLI_noise_mg_ridged_multi_fractal(float x,
return result;
} /* RidgedMultifractal() */
-/* "Variable Lacunarity Noise"
- * A distorted variety of Perlin noise.
- */
float BLI_noise_mg_variable_lacunarity(
float x, float y, float z, float distortion, int nbas1, int nbas2)
{
diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc
index 959385bff31..a6ad18801fd 100644
--- a/source/blender/blenlib/intern/noise.cc
+++ b/source/blender/blenlib/intern/noise.cc
@@ -58,13 +58,12 @@
#include "BLI_utildefines.h"
namespace blender::noise {
-/* ------------------------------
- * Jenkins Lookup3 Hash Functions
- * ------------------------------
+
+/* -------------------------------------------------------------------- */
+/** \name Jenkins Lookup3 Hash Functions
*
* https://burtleburtle.net/bob/c/lookup3.c
- *
- */
+ * \{ */
BLI_INLINE uint32_t hash_bit_rotate(uint32_t x, uint32_t k)
{
@@ -283,16 +282,17 @@ float4 hash_float_to_float4(float4 k)
hash_float_to_float(float4(k.y, k.z, k.w, k.x)));
}
-/* ------------
- * Perlin Noise
- * ------------
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Perlin Noise
*
* Perlin, Ken. "Improving noise." Proceedings of the 29th annual conference on Computer graphics
* and interactive techniques. 2002.
*
* This implementation is functionally identical to the implementations in EEVEE, OSL, and SVM. So
* any changes should be applied in all relevant implementations.
- */
+ * \{ */
/* Linear Interpolation. */
BLI_INLINE float mix(float v0, float v1, float x)
@@ -757,25 +757,19 @@ float3 perlin_float3_fractal_distorted(float4 position,
perlin_fractal(position + random_float4_offset(5.0f), octaves, roughness));
}
-/* --------------
- * Musgrave Noise
- * --------------
- */
+/** \} */
-/* 1D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
+/* -------------------------------------------------------------------- */
+/** \name Musgrave Noise
+ * \{ */
float musgrave_fBm(const float co,
const float H,
const float lacunarity,
const float octaves_unclamped)
{
+ /* From "Texturing and Modelling: A procedural approach". */
+
float p = co;
float value = 0.0f;
float pwr = 1.0f;
@@ -796,13 +790,6 @@ float musgrave_fBm(const float co,
return value;
}
-/* 1D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
float musgrave_multi_fractal(const float co,
const float H,
const float lacunarity,
@@ -828,14 +815,6 @@ float musgrave_multi_fractal(const float co,
return value;
}
-/* 1D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hetero_terrain(const float co,
const float H,
const float lacunarity,
@@ -867,14 +846,6 @@ float musgrave_hetero_terrain(const float co,
return value;
}
-/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hybrid_multi_fractal(const float co,
const float H,
const float lacunarity,
@@ -912,14 +883,6 @@ float musgrave_hybrid_multi_fractal(const float co,
return value;
}
-/* 1D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_ridged_multi_fractal(const float co,
const float H,
const float lacunarity,
@@ -951,20 +914,13 @@ float musgrave_ridged_multi_fractal(const float co,
return value;
}
-/* 2D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
float musgrave_fBm(const float2 co,
const float H,
const float lacunarity,
const float octaves_unclamped)
{
+ /* From "Texturing and Modelling: A procedural approach". */
+
float2 p = co;
float value = 0.0f;
float pwr = 1.0f;
@@ -985,13 +941,6 @@ float musgrave_fBm(const float2 co,
return value;
}
-/* 2D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
float musgrave_multi_fractal(const float2 co,
const float H,
const float lacunarity,
@@ -1017,14 +966,6 @@ float musgrave_multi_fractal(const float2 co,
return value;
}
-/* 2D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hetero_terrain(const float2 co,
const float H,
const float lacunarity,
@@ -1057,14 +998,6 @@ float musgrave_hetero_terrain(const float2 co,
return value;
}
-/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hybrid_multi_fractal(const float2 co,
const float H,
const float lacunarity,
@@ -1102,14 +1035,6 @@ float musgrave_hybrid_multi_fractal(const float2 co,
return value;
}
-/* 2D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_ridged_multi_fractal(const float2 co,
const float H,
const float lacunarity,
@@ -1141,20 +1066,13 @@ float musgrave_ridged_multi_fractal(const float2 co,
return value;
}
-/* 3D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
float musgrave_fBm(const float3 co,
const float H,
const float lacunarity,
const float octaves_unclamped)
{
+ /* From "Texturing and Modelling: A procedural approach". */
+
float3 p = co;
float value = 0.0f;
float pwr = 1.0f;
@@ -1176,13 +1094,6 @@ float musgrave_fBm(const float3 co,
return value;
}
-/* 3D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
float musgrave_multi_fractal(const float3 co,
const float H,
const float lacunarity,
@@ -1209,14 +1120,6 @@ float musgrave_multi_fractal(const float3 co,
return value;
}
-/* 3D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hetero_terrain(const float3 co,
const float H,
const float lacunarity,
@@ -1249,14 +1152,6 @@ float musgrave_hetero_terrain(const float3 co,
return value;
}
-/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hybrid_multi_fractal(const float3 co,
const float H,
const float lacunarity,
@@ -1294,14 +1189,6 @@ float musgrave_hybrid_multi_fractal(const float3 co,
return value;
}
-/* 3D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_ridged_multi_fractal(const float3 co,
const float H,
const float lacunarity,
@@ -1333,20 +1220,13 @@ float musgrave_ridged_multi_fractal(const float3 co,
return value;
}
-/* 4D Musgrave fBm
- *
- * H: fractal increment parameter
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- *
- * from "Texturing and Modelling: A procedural approach"
- */
-
float musgrave_fBm(const float4 co,
const float H,
const float lacunarity,
const float octaves_unclamped)
{
+ /* From "Texturing and Modelling: A procedural approach". */
+
float4 p = co;
float value = 0.0f;
float pwr = 1.0f;
@@ -1368,13 +1248,6 @@ float musgrave_fBm(const float4 co,
return value;
}
-/* 4D Musgrave Multifractal
- *
- * H: highest fractal dimension
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- */
-
float musgrave_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -1401,14 +1274,6 @@ float musgrave_multi_fractal(const float4 co,
return value;
}
-/* 4D Musgrave Heterogeneous Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hetero_terrain(const float4 co,
const float H,
const float lacunarity,
@@ -1441,14 +1306,6 @@ float musgrave_hetero_terrain(const float4 co,
return value;
}
-/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_hybrid_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -1486,14 +1343,6 @@ float musgrave_hybrid_multi_fractal(const float4 co,
return value;
}
-/* 4D Ridged Multifractal Terrain
- *
- * H: fractal dimension of the roughest area
- * lacunarity: gap between successive frequencies
- * octaves: number of frequencies in the fBm
- * offset: raises the terrain from `sea level'
- */
-
float musgrave_ridged_multi_fractal(const float4 co,
const float H,
const float lacunarity,
@@ -1525,8 +1374,12 @@ float musgrave_ridged_multi_fractal(const float4 co,
return value;
}
-/*
- * Voronoi: Ported from Cycles code.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Voronoi Noise
+ *
+ * \note Ported from Cycles code.
*
* Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
*
@@ -1541,7 +1394,7 @@ float musgrave_ridged_multi_fractal(const float4 co,
*
* With optimization to change -2..2 scan window to -1..1 for better performance,
* as explained in https://www.shadertoy.com/view/llG3zy.
- */
+ * \{ */
/* **** 1D Voronoi **** */
@@ -2516,4 +2369,6 @@ void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *
*r_radius = float4::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
}
+/** \} */
+
} // namespace blender::noise
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 182fe211110..c824def9104 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -69,17 +69,6 @@ static bool BLI_path_is_abs(const char *name);
/* implementation */
-/**
- * Looks for a sequence of decimal digits in string, preceding any filename extension,
- * returning the integer value if found, or 0 if not.
- *
- * \param string: String to scan.
- * \param head: Optional area to return copy of part of string prior to digits,
- * or before dot if no digits.
- * \param tail: Optional area to return copy of part of string following digits,
- * or from dot if no digits.
- * \param r_num_len: Optional to return number of digits found.
- */
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_num_len)
{
uint nums = 0, nume = 0;
@@ -147,10 +136,6 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
return 0;
}
-/**
- * Returns in area pointed to by string a string of the form "<head><pic><tail>", where pic
- * is formatted as numlen digits with leading zeroes.
- */
void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic)
{
@@ -159,17 +144,6 @@ void BLI_path_sequence_encode(
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
-/* ******************** string encoding ***************** */
-
-/**
- * Remove redundant characters from \a path and optionally make absolute.
- *
- * \param relabase: The path this is relative to, or ignored when NULL.
- * \param path: Can be any input, and this function converts it to a regular full path.
- * Also removes garbage from directory paths, like `/../` or double slashes etc.
- *
- * \note \a path isn't protected for max string names...
- */
void BLI_path_normalize(const char *relabase, char *path)
{
ptrdiff_t a;
@@ -260,9 +234,6 @@ void BLI_path_normalize(const char *relabase, char *path)
#endif
}
-/**
- * Cleanup filepath ensuring a trailing slash.
- */
void BLI_path_normalize_dir(const char *relabase, char *dir)
{
/* Would just create an unexpected "/" path, just early exit entirely. */
@@ -274,28 +245,6 @@ void BLI_path_normalize_dir(const char *relabase, char *dir)
BLI_path_slash_ensure(dir);
}
-/**
- * Make given name safe to be used in paths.
- *
- * \return true if \a fname was changed, false otherwise.
- *
- * For now, simply replaces reserved chars (as listed in
- * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
- * by underscores ('_').
- *
- * \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
- * but again can be an issue in some cases, so we simply replace it by an underscore too
- * (good practice anyway).
- * REMOVED based on popular demand (see T45900).
- * Percent '%' char is a bit same case - not recommended to use it,
- * but supported by all decent file-systems/operating-systems around.
- *
- * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
- * this can lead to issues.
- *
- * \note On Windows, it also checks for forbidden names
- * (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
- */
bool BLI_filename_make_safe(char *fname)
{
const char *invalid =
@@ -366,11 +315,6 @@ bool BLI_filename_make_safe(char *fname)
return changed;
}
-/**
- * Make given path OS-safe.
- *
- * \return true if \a path was changed, false otherwise.
- */
bool BLI_path_make_safe(char *path)
{
/* Simply apply BLI_filename_make_safe() over each component of the path.
@@ -404,16 +348,11 @@ bool BLI_path_make_safe(char *path)
return changed;
}
-/**
- * Does path begin with the special "//" prefix that Blender uses to indicate
- * a path relative to the .blend file.
- */
bool BLI_path_is_rel(const char *path)
{
return path[0] == '/' && path[1] == '/';
}
-/* return true if the path is a UNC share */
bool BLI_path_is_unc(const char *name)
{
return name[0] == '\\' && name[1] == '\\';
@@ -512,10 +451,6 @@ void BLI_path_normalize_unc_16(wchar_t *path_16)
}
#endif
-/**
- * Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
- * the same `relfile`, will convert it back to its original value.
- */
void BLI_path_rel(char *file, const char *relfile)
{
const char *lslash;
@@ -654,18 +589,6 @@ void BLI_path_rel(char *file, const char *relfile)
}
}
-/**
- * Appends a suffix to the string, fitting it before the extension
- *
- * string = Foo.png, suffix = 123, separator = _
- * Foo.png -> Foo_123.png
- *
- * \param string: original (and final) string
- * \param maxlen: Maximum length of string
- * \param suffix: String to append to the original string
- * \param sep: Optional separator character
- * \return true if succeeded
- */
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
{
#ifdef DEBUG_STRSIZE
@@ -701,10 +624,6 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
return true;
}
-/**
- * Replaces path with the path of its parent directory, returning true if
- * it was able to find a parent directory within the path.
- */
bool BLI_path_parent_dir(char *path)
{
const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
@@ -721,10 +640,6 @@ bool BLI_path_parent_dir(char *path)
return false;
}
-/**
- * Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
- * leaving the path of the lowest-level directory that does exist and we can read.
- */
bool BLI_path_parent_dir_until_exists(char *dir)
{
bool valid_path = true;
@@ -795,10 +710,6 @@ static void ensure_digits(char *path, int digits)
}
}
-/**
- * Replaces "#" character sequence in last slash-separated component of `path`
- * with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
- */
bool BLI_path_frame(char *path, int frame, int digits)
{
int ch_sta, ch_end;
@@ -817,11 +728,6 @@ bool BLI_path_frame(char *path, int frame, int digits)
return false;
}
-/**
- * Replaces "#" character sequence in last slash-separated component of `path`
- * with sta and end as decimal integers, with leading zeroes as necessary, to make digits
- * digits each, with a hyphen in-between.
- */
bool BLI_path_frame_range(char *path, int sta, int end, int digits)
{
int ch_sta, ch_end;
@@ -848,9 +754,6 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
return false;
}
-/**
- * Get the frame from a filename formatted by blender's frame scheme
- */
bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
{
if (*path) {
@@ -952,19 +855,12 @@ void BLI_path_frame_strip(char *path, char *r_ext)
*c = '\0';
}
-/**
- * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
- */
bool BLI_path_frame_check_chars(const char *path)
{
int ch_sta, ch_end; /* dummy args */
return stringframe_chars(path, &ch_sta, &ch_end);
}
-/**
- * Creates a display string from path to be used menus and the user interface.
- * Like `bpy.path.display_name()`.
- */
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
{
/* Strip leading underscores and spaces. */
@@ -1003,16 +899,6 @@ void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
}
}
-/**
- * If path begins with "//", strips that and replaces it with `basepath` directory.
- *
- * \note Also converts drive-letter prefix to something more sensible
- * if this is a non-drive-letter-based system.
- *
- * \param path: The path to convert.
- * \param basepath: The directory to base relative paths with.
- * \return true if the path was relative (started with "//").
- */
bool BLI_path_abs(char *path, const char *basepath)
{
const bool wasrelative = BLI_path_is_rel(path);
@@ -1114,33 +1000,30 @@ bool BLI_path_abs(char *path, const char *basepath)
return wasrelative;
}
-/**
- * Checks for relative path, expanding them relative to the current working directory.
- * Returns true if the expansion was performed.
- *
- * \note Should only be called with command line paths.
- * This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
- * In most cases #BLI_path_abs should be used instead.
- */
-bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
+bool BLI_path_is_abs_from_cwd(const char *path)
{
-#ifdef DEBUG_STRSIZE
- memset(path, 0xff, sizeof(*path) * maxlen);
-#endif
- bool wasrelative = true;
- const int filelen = strlen(path);
+ bool is_abs = false;
+ const int path_len_clamp = BLI_strnlen(path, 3);
#ifdef WIN32
- if ((filelen >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
- wasrelative = false;
+ if ((path_len_clamp >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
+ is_abs = true;
}
#else
- if (filelen >= 2 && path[0] == '/') {
- wasrelative = false;
+ if (path_len_clamp >= 2 && path[0] == '/') {
+ is_abs = true;
}
#endif
+ return is_abs;
+}
- if (wasrelative) {
+bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
+{
+#ifdef DEBUG_STRSIZE
+ memset(path, 0xff, sizeof(*path) * maxlen);
+#endif
+
+ if (!BLI_path_is_abs_from_cwd(path)) {
char cwd[FILE_MAX];
/* in case the full path to the blend isn't used */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
@@ -1151,9 +1034,10 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
else {
printf("Could not get the current working directory - $PWD for an unknown reason.\n");
}
+ return true;
}
- return wasrelative;
+ return false;
}
#ifdef _WIN32
@@ -1209,9 +1093,6 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
}
#endif /* WIN32 */
-/**
- * Search for a binary (executable)
- */
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name)
{
#ifdef DEBUG_STRSIZE
@@ -1264,10 +1145,6 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na
return retval;
}
-/**
- * Sets the specified environment variable to the specified value,
- * and clears it if `val == NULL`.
- */
void BLI_setenv(const char *env, const char *val)
{
/* free windows */
@@ -1286,12 +1163,6 @@ void BLI_setenv(const char *env, const char *val)
#endif
}
-/**
- * Only set an env var if already not there.
- * Like Unix setenv(env, val, 0);
- *
- * (not used anywhere).
- */
void BLI_setenv_if_new(const char *env, const char *val)
{
if (BLI_getenv(env) == NULL) {
@@ -1299,14 +1170,6 @@ void BLI_setenv_if_new(const char *env, const char *val)
}
}
-/**
- * Get an env var, result has to be used immediately.
- *
- * On windows #getenv gets its variables from a static copy of the environment variables taken at
- * process start-up, causing it to not pick up on environment variables created during runtime.
- * This function uses an alternative method to get environment variables that does pick up on
- * runtime environment variables. The result will be UTF-8 encoded.
- */
const char *BLI_getenv(const char *env)
{
#ifdef _MSC_VER
@@ -1336,11 +1199,6 @@ const char *BLI_getenv(const char *env)
#endif
}
-/**
- * Ensures that the parent directory of `name` exists.
- *
- * \return true on success (i.e. given path now exists on file-system), false otherwise.
- */
bool BLI_make_existing_file(const char *name)
{
char di[FILE_MAX];
@@ -1350,15 +1208,6 @@ bool BLI_make_existing_file(const char *name)
return BLI_dir_create_recursive(di);
}
-/**
- * Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
- * front if specified and `dir` begins with "//"). Normalizes all occurrences of path
- * separators, including ensuring there is exactly one between the copies of `dir` and `file`,
- * and between the copies of `relabase` and `dir`.
- *
- * \param relabase: Optional prefix to substitute for "//" on front of `dir`.
- * \param string: Area to return result.
- */
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
{
int sl;
@@ -1452,7 +1301,6 @@ static bool path_extension_check_ex(const char *str,
(BLI_strcasecmp(ext, str + str_len - ext_len) == 0));
}
-/* does str end with ext. */
bool BLI_path_extension_check(const char *str, const char *ext)
{
return path_extension_check_ex(str, strlen(str), ext, strlen(ext));
@@ -1480,7 +1328,6 @@ bool BLI_path_extension_check_n(const char *str, ...)
return ret;
}
-/* does str end with any of the suffixes in *ext_array. */
bool BLI_path_extension_check_array(const char *str, const char **ext_array)
{
const size_t str_len = strlen(str);
@@ -1496,10 +1343,6 @@ bool BLI_path_extension_check_array(const char *str, const char **ext_array)
return false;
}
-/**
- * Semicolon separated wildcards, eg: `*.zip;*.py;*.exe`
- * does str match any of the semicolon-separated glob patterns in #fnmatch.
- */
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
{
const char *ext_step = ext_fnmatch;
@@ -1526,15 +1369,6 @@ bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
return false;
}
-/**
- * Does basic validation of the given glob string, to prevent common issues from string
- * truncation.
- *
- * For now, only forbids last group to be a wildcard-only one, if there are more than one group
- * (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`)
- *
- * \returns true if it had to modify given \a ext_fnmatch pattern.
- */
bool BLI_path_extension_glob_validate(char *ext_fnmatch)
{
bool only_wildcards = false;
@@ -1561,10 +1395,6 @@ bool BLI_path_extension_glob_validate(char *ext_fnmatch)
return false;
}
-/**
- * Removes any existing extension on the end of \a path and appends \a ext.
- * \return false if there was no room.
- */
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext)
{
#ifdef DEBUG_STRSIZE
@@ -1592,9 +1422,6 @@ bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext)
return true;
}
-/**
- * Strip's trailing '.'s and adds the extension only when needed
- */
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext)
{
#ifdef DEBUG_STRSIZE
@@ -1640,14 +1467,6 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam
return false;
}
-/**
- * Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
- *
- * - Won't change \a string.
- * - Won't create any directories.
- * - Doesn't use CWD, or deal with relative paths.
- * - Only fill's in \a dir and \a file when they are non NULL.
- */
void BLI_split_dirfile(
const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
{
@@ -1673,26 +1492,16 @@ void BLI_split_dirfile(
}
}
-/**
- * Copies the parent directory part of string into `dir`, max length `dirlen`.
- */
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
{
BLI_split_dirfile(string, dir, NULL, dirlen, 0);
}
-/**
- * Copies the leaf filename part of string into `file`, max length `filelen`.
- */
void BLI_split_file_part(const char *string, char *file, const size_t filelen)
{
BLI_split_dirfile(string, NULL, file, 0, filelen);
}
-/**
- * Returns a pointer to the last extension (e.g. the position of the last period).
- * Returns NULL if there is no extension.
- */
const char *BLI_path_extension(const char *filepath)
{
const char *extension = strrchr(filepath, '.');
@@ -1707,9 +1516,6 @@ const char *BLI_path_extension(const char *filepath)
return extension;
}
-/**
- * Append a filename to a dir, ensuring slash separates.
- */
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
{
size_t dirlen = BLI_strnlen(dst, maxlen);
@@ -1727,13 +1533,6 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
}
-/**
- * Simple appending of filename to dir, does not check for valid path!
- * Puts result into `dst`, which may be same area as `dir`.
- *
- * \note Consider using #BLI_path_join for more general path joining
- * that de-duplicates separators and can handle an arbitrary number of paths.
- */
void BLI_join_dirfile(char *__restrict dst,
const size_t maxlen,
const char *__restrict dir,
@@ -1776,13 +1575,6 @@ void BLI_join_dirfile(char *__restrict dst,
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
}
-/**
- * Join multiple strings into a path, ensuring only a single path separator between each,
- * and trailing slash is kept.
- *
- * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
- * duplicate slashes will be cleaned up.
- */
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
{
#ifdef DEBUG_STRSIZE
@@ -1863,27 +1655,12 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat
return ofs;
}
-/**
- * like Python's `os.path.basename()`
- *
- * \return The pointer into \a path string immediately after last slash,
- * or start of \a path if none found.
- */
const char *BLI_path_basename(const char *path)
{
const char *const filename = BLI_path_slash_rfind(path);
return filename ? filename + 1 : path;
}
-/**
- * Get an element of the path at an index, eg:
- * "/some/path/file.txt" where an index of...
- * - 0 or -3: "some"
- * - 1 or -2: "path"
- * - 2 or -1: "file.txt"
- *
- * Ignores multiple slashes at any point in the path (including start/end).
- */
bool BLI_path_name_at_index(const char *__restrict path,
const int index,
int *__restrict r_offset,
@@ -1975,9 +1752,6 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
return BLI_str_startswith(containee_native, container_native);
}
-/**
- * Returns pointer to the leftmost path separator in string. Not actually used anywhere.
- */
const char *BLI_path_slash_find(const char *string)
{
const char *const ffslash = strchr(string, '/');
@@ -1993,9 +1767,6 @@ const char *BLI_path_slash_find(const char *string)
return (ffslash < fbslash) ? ffslash : fbslash;
}
-/**
- * Returns pointer to the rightmost path separator in string.
- */
const char *BLI_path_slash_rfind(const char *string)
{
const char *const lfslash = strrchr(string, '/');
@@ -2011,10 +1782,6 @@ const char *BLI_path_slash_rfind(const char *string)
return (lfslash > lbslash) ? lfslash : lbslash;
}
-/**
- * Appends a slash to string if there isn't one there already.
- * Returns the new length of the string.
- */
int BLI_path_slash_ensure(char *string)
{
int len = strlen(string);
@@ -2026,9 +1793,6 @@ int BLI_path_slash_ensure(char *string)
return len;
}
-/**
- * Removes the last slash and everything after it to the end of string, if there is one.
- */
void BLI_path_slash_rstrip(char *string)
{
int len = strlen(string);
@@ -2043,9 +1807,6 @@ void BLI_path_slash_rstrip(char *string)
}
}
-/**
- * Changes to the path separators to the native ones for this OS.
- */
void BLI_path_slash_native(char *path)
{
#ifdef WIN32
diff --git a/source/blender/blenlib/intern/polyfill_2d.c b/source/blender/blenlib/intern/polyfill_2d.c
index 9af98359199..2a02abf147a 100644
--- a/source/blender/blenlib/intern/polyfill_2d.c
+++ b/source/blender/blenlib/intern/polyfill_2d.c
@@ -841,9 +841,6 @@ static void polyfill_calc(PolyFill *pf)
pf_triangulate(pf);
}
-/**
- * A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations.
- */
void BLI_polyfill_calc_arena(const float (*coords)[2],
const uint coords_tot,
const int coords_sign,
@@ -889,19 +886,6 @@ void BLI_polyfill_calc_arena(const float (*coords)[2],
#endif
}
-/**
- * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
- *
- * \param coords: 2D coordinates describing vertices of the polygon,
- * in either clockwise or counterclockwise order.
- * \param coords_tot: Total points in the array.
- * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
- *
- * \param r_tris: This array is filled in with triangle indices in clockwise order.
- * The length of the array must be `coords_tot - 2`.
- * Indices are guaranteed to be assigned to unique triangles, with valid indices,
- * even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
- */
void BLI_polyfill_calc(const float (*coords)[2],
const uint coords_tot,
const int coords_sign,
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index ed07b002e32..684094234cf 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -92,21 +92,6 @@ BLI_INLINE bool is_boundary_edge(uint i_a, uint i_b, const uint coord_last)
BLI_assert(i_a < i_b);
return ((i_a + 1 == i_b) || UNLIKELY((i_a == 0) && (i_b == coord_last)));
}
-/**
- * Assuming we have 2 triangles sharing an edge (2 - 4),
- * check if the edge running from (1 - 3) gives better results.
- *
- * \param lock_degenerate: Use to avoid rotating out of a degenerate state:
- * - When true, an existing zero area face on either side of the (2 - 4
- * split will return a positive value.
- * - When false, the check must be non-biased towards either split direction.
- * \param r_area: Return the area of the quad,
- * This can be useful when comparing the return value with near zero epsilons.
- * In this case the epsilon can be scaled by the area to avoid the return value
- * of very large faces not having a reliable way to detect near-zero output.
- *
- * \return (negative number means the edge can be rotated, lager == better).
- */
float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
@@ -316,12 +301,6 @@ static void polyedge_rotate(struct HalfEdge *edges, struct HalfEdge *e)
ed[3]->v = ed[2]->v;
}
-/**
- * The intention is that this calculates the output of #BLI_polyfill_calc
- * \note assumes the \a coords form a boundary,
- * so any edges running along contiguous (wrapped) indices,
- * are ignored since the edges won't share 2 faces.
- */
void BLI_polyfill_beautify(const float (*coords)[2],
const uint coords_tot,
uint (*tris)[3],
diff --git a/source/blender/blenlib/intern/rand.cc b/source/blender/blenlib/intern/rand.cc
index db5e08d37ce..1d2274ede37 100644
--- a/source/blender/blenlib/intern/rand.cc
+++ b/source/blender/blenlib/intern/rand.cc
@@ -59,9 +59,6 @@ RNG *BLI_rng_new(unsigned int seed)
return rng;
}
-/**
- * A version of #BLI_rng_new that hashes the seed.
- */
RNG *BLI_rng_new_srandom(unsigned int seed)
{
RNG *rng = new RNG();
@@ -84,9 +81,6 @@ void BLI_rng_seed(RNG *rng, unsigned int seed)
rng->rng.seed(seed);
}
-/**
- * Use a hash table to create better seed.
- */
void BLI_rng_srandom(RNG *rng, unsigned int seed)
{
rng->rng.seed_random(seed);
@@ -107,17 +101,11 @@ unsigned int BLI_rng_get_uint(RNG *rng)
return rng->rng.get_uint32();
}
-/**
- * \return Random value (0..1), but never 1.0.
- */
double BLI_rng_get_double(RNG *rng)
{
return rng->rng.get_double();
}
-/**
- * \return Random value (0..1), but never 1.0.
- */
float BLI_rng_get_float(RNG *rng)
{
return rng->rng.get_float();
@@ -133,9 +121,6 @@ void BLI_rng_get_float_unit_v3(RNG *rng, float v[3])
copy_v3_v3(v, rng->rng.get_unit_float3());
}
-/**
- * Generate a random point inside given tri.
- */
void BLI_rng_get_tri_sample_float_v2(
RNG *rng, const float v1[2], const float v2[2], const float v3[2], float r_pt[2])
{
@@ -190,11 +175,6 @@ void BLI_rng_shuffle_bitmap(struct RNG *rng, BLI_bitmap *bitmap, unsigned int bi
}
}
-/**
- * Simulate getting \a n random values.
- *
- * \note Useful when threaded code needs consistent values, independent of task division.
- */
void BLI_rng_skip(RNG *rng, int n)
{
rng->rng.skip((uint)n);
@@ -202,7 +182,6 @@ void BLI_rng_skip(RNG *rng, int n)
/***/
-/* fill an array with random numbers */
void BLI_array_frand(float *ar, int count, unsigned int seed)
{
RNG rng;
@@ -272,7 +251,7 @@ struct RNG_THREAD_ARRAY {
RNG rng_tab[BLENDER_MAX_THREADS];
};
-RNG_THREAD_ARRAY *BLI_rng_threaded_new(void)
+RNG_THREAD_ARRAY *BLI_rng_threaded_new()
{
unsigned int i;
RNG_THREAD_ARRAY *rngarr = (RNG_THREAD_ARRAY *)MEM_mallocN(sizeof(RNG_THREAD_ARRAY),
@@ -402,9 +381,6 @@ void BLI_hammersley_2d_sequence(unsigned int n, double *r)
namespace blender {
-/**
- * Set a randomized hash of the value as seed.
- */
void RandomNumberGenerator::seed_random(uint32_t seed)
{
this->seed(seed + hash[seed & 255]);
@@ -434,9 +410,6 @@ float3 RandomNumberGenerator::get_unit_float3()
return {0.0f, 0.0f, 1.0f};
}
-/**
- * Generate a random point inside the given triangle.
- */
float2 RandomNumberGenerator::get_triangle_sample(float2 v1, float2 v2, float2 v3)
{
float u = this->get_float();
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 35e24ecc785..091945c9b12 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -30,6 +30,7 @@
#include <float.h>
#include <limits.h>
+#include "BLI_math_base.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -38,13 +39,6 @@
/* avoid including BLI_math */
static void unit_m4(float m[4][4]);
-/**
- * Determine if a rect is empty. An empty
- * rect is one with a zero (or negative)
- * width or height.
- *
- * \return True if \a rect is empty.
- */
bool BLI_rcti_is_empty(const rcti *rect)
{
return ((rect->xmax <= rect->xmin) || (rect->ymax <= rect->ymin));
@@ -167,10 +161,6 @@ bool BLI_rctf_isect_pt_v(const rctf *rect, const float xy[2])
return true;
}
-/**
- * \returns shortest distance from \a rect to x/y (0 if inside)
- */
-
int BLI_rcti_length_x(const rcti *rect, const int x)
{
if (x < rect->xmin) {
@@ -215,9 +205,6 @@ float BLI_rctf_length_y(const rctf *rect, const float y)
return 0.0f;
}
-/**
- * is \a rct_b inside \a rct_a
- */
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b)
{
return ((rct_a->xmin <= rct_b->xmin) && (rct_a->xmax >= rct_b->xmax) &&
@@ -401,35 +388,35 @@ bool BLI_rctf_isect_circle(const rctf *rect, const float xy[2], const float radi
return dx * dx + dy * dy <= radius * radius;
}
-void BLI_rctf_union(rctf *rct1, const rctf *rct2)
+void BLI_rctf_union(rctf *rct_a, const rctf *rct_b)
{
- if (rct1->xmin > rct2->xmin) {
- rct1->xmin = rct2->xmin;
+ if (rct_a->xmin > rct_b->xmin) {
+ rct_a->xmin = rct_b->xmin;
}
- if (rct1->xmax < rct2->xmax) {
- rct1->xmax = rct2->xmax;
+ if (rct_a->xmax < rct_b->xmax) {
+ rct_a->xmax = rct_b->xmax;
}
- if (rct1->ymin > rct2->ymin) {
- rct1->ymin = rct2->ymin;
+ if (rct_a->ymin > rct_b->ymin) {
+ rct_a->ymin = rct_b->ymin;
}
- if (rct1->ymax < rct2->ymax) {
- rct1->ymax = rct2->ymax;
+ if (rct_a->ymax < rct_b->ymax) {
+ rct_a->ymax = rct_b->ymax;
}
}
-void BLI_rcti_union(rcti *rct1, const rcti *rct2)
+void BLI_rcti_union(rcti *rct_a, const rcti *rct_b)
{
- if (rct1->xmin > rct2->xmin) {
- rct1->xmin = rct2->xmin;
+ if (rct_a->xmin > rct_b->xmin) {
+ rct_a->xmin = rct_b->xmin;
}
- if (rct1->xmax < rct2->xmax) {
- rct1->xmax = rct2->xmax;
+ if (rct_a->xmax < rct_b->xmax) {
+ rct_a->xmax = rct_b->xmax;
}
- if (rct1->ymin > rct2->ymin) {
- rct1->ymin = rct2->ymin;
+ if (rct_a->ymin > rct_b->ymin) {
+ rct_a->ymin = rct_b->ymin;
}
- if (rct1->ymax < rct2->ymax) {
- rct1->ymax = rct2->ymax;
+ if (rct_a->ymax < rct_b->ymax) {
+ rct_a->ymax = rct_b->ymax;
}
}
@@ -453,13 +440,6 @@ void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax)
BLI_rcti_sanitize(rect);
}
-/**
- * Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
- * If this returns false, #BLI_rctf_sanitize() can be called to address this.
- *
- * This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
- * have max < min. Usually this is what you'd want though.
- */
bool BLI_rctf_is_valid(const rctf *rect)
{
return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
@@ -470,9 +450,6 @@ bool BLI_rcti_is_valid(const rcti *rect)
return (rect->xmin <= rect->xmax) && (rect->ymin <= rect->ymax);
}
-/**
- * Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
- */
void BLI_rctf_sanitize(rctf *rect)
{
if (rect->xmin > rect->xmax) {
@@ -541,6 +518,14 @@ void BLI_rcti_do_minmax_v(rcti *rect, const int xy[2])
}
}
+void BLI_rcti_do_minmax_rcti(rcti *rect, const rcti *other)
+{
+ rect->xmin = min_ii(rect->xmin, other->xmin);
+ rect->xmax = max_ii(rect->xmax, other->xmax);
+ rect->ymin = min_ii(rect->ymin, other->ymin);
+ rect->ymax = max_ii(rect->ymax, other->ymax);
+}
+
void BLI_rctf_do_minmax_v(rctf *rect, const float xy[2])
{
if (xy[0] < rect->xmin) {
@@ -557,7 +542,6 @@ void BLI_rctf_do_minmax_v(rctf *rect, const float xy[2])
}
}
-/* given 2 rectangles - transform a point from one to another */
void BLI_rctf_transform_pt_v(const rctf *dst,
const rctf *src,
float xy_dst[2],
@@ -570,12 +554,6 @@ void BLI_rctf_transform_pt_v(const rctf *dst,
xy_dst[1] = dst->ymin + ((dst->ymax - dst->ymin) * xy_dst[1]);
}
-/**
- * Calculate a 4x4 matrix representing the transformation between two rectangles.
- *
- * \note Multiplying a vector by this matrix does *not*
- * give the same value as #BLI_rctf_transform_pt_v.
- */
void BLI_rctf_transform_calc_m4_pivot_min_ex(
const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y)
{
@@ -622,7 +600,6 @@ void BLI_rctf_recenter(rctf *rect, float x, float y)
BLI_rctf_translate(rect, dx, dy);
}
-/* change width & height around the central location */
void BLI_rcti_resize_x(rcti *rect, int x)
{
rect->xmin = BLI_rcti_cent_x(rect) - (x / 2);
@@ -777,14 +754,6 @@ bool BLI_rcti_clamp_pt_v(const rcti *rect, int xy[2])
return changed;
}
-/**
- * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
- *
- * Keeps the top left corner within the bounds, which for user interface
- * elements is typically where the most important information is.
- *
- * \return true if a change is made.
- */
bool BLI_rctf_clamp(rctf *rect, const rctf *rect_bounds, float r_xy[2])
{
bool changed = false;
@@ -1106,9 +1075,6 @@ void print_rcti(const char *str, const rcti *rect)
} \
((void)0)
-/**
- * Expand the rectangle to fit a rotated \a src.
- */
void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle)
{
const float mat2[2] = {sinf(angle), cosf(angle)};
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index 33c0f4afd01..89c2a695829 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -369,11 +369,6 @@ static bool scanfill_preprocess_self_isect(ScanFillContext *sf_ctx,
return true;
}
-/**
- * Call before scanfill to remove self intersections.
- *
- * \return false if no changes were made.
- */
bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx,
ListBase *remvertbase,
ListBase *remedgebase)
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index 006a3798dcd..2278daf5516 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -214,7 +214,6 @@ void BLI_smallhash_init(SmallHash *sh)
BLI_smallhash_init_ex(sh, 0);
}
-/* NOTE: does *not* free *sh itself! only the direct data! */
void BLI_smallhash_release(SmallHash *sh)
{
if (sh->buckets != sh->buckets_stack) {
@@ -239,13 +238,6 @@ void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item)
e->val = item;
}
-/**
- * Inserts a new value to a key that may already be in ghash.
- *
- * Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups)
- *
- * \returns true if a new key has been added.
- */
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item)
{
SmallHashEntry *e = smallhash_lookup(sh, key);
@@ -389,12 +381,6 @@ void BLI_smallhash_print(SmallHash *sh)
#endif
#ifdef DEBUG
-/**
- * Measure how well the hash function performs
- * (1.0 is perfect - no stepping needed).
- *
- * Smaller is better!
- */
double BLI_smallhash_calc_quality(SmallHash *sh)
{
uint64_t sum = 0;
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 4a9bdd48a0a..629a6eaa78c 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -91,9 +91,6 @@ BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
return stack;
}
-/**
- * Create a new homogeneous stack with elements of 'elem_size' bytes.
- */
BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description)
{
return BLI_stack_new_ex(elem_size, description, CHUNK_SIZE_DEFAULT);
@@ -108,9 +105,6 @@ static void stack_free_chunks(struct StackChunk *data)
}
}
-/**
- * Free the stack's data and the stack itself
- */
void BLI_stack_free(BLI_Stack *stack)
{
stack_free_chunks(stack->chunk_curr);
@@ -118,12 +112,6 @@ void BLI_stack_free(BLI_Stack *stack)
MEM_freeN(stack);
}
-/**
- * Push a new item onto the stack.
- *
- * \return a pointer #BLI_Stack.elem_size
- * bytes of uninitialized memory (caller must fill in).
- */
void *BLI_stack_push_r(BLI_Stack *stack)
{
stack->chunk_index++;
@@ -152,26 +140,12 @@ void *BLI_stack_push_r(BLI_Stack *stack)
return stack_get_last_elem(stack);
}
-/**
- * Copies the source value onto the stack
- *
- * \note This copies #BLI_Stack.elem_size bytes from \a src,
- * (the pointer itself is not stored).
- *
- * \param src: source data to be copied to the stack.
- */
void BLI_stack_push(BLI_Stack *stack, const void *src)
{
void *dst = BLI_stack_push_r(stack);
memcpy(dst, src, stack->elem_size);
}
-/**
- * Retrieves and removes the top element from the stack.
- * The value is copies to \a dst, which must be at least \a elem_size bytes.
- *
- * Does not reduce amount of allocated memory.
- */
void BLI_stack_pop(BLI_Stack *stack, void *dst)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
@@ -181,15 +155,6 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst)
BLI_stack_discard(stack);
}
-/**
- * A version of #BLI_stack_pop which fills in an array.
- *
- * \param dst: The destination array,
- * must be at least (#BLI_Stack.elem_size * \a n) bytes long.
- * \param n: The number of items to pop.
- *
- * \note The first item in the array will be last item added to the stack.
- */
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
{
BLI_assert(n <= BLI_stack_count(stack));
@@ -200,11 +165,6 @@ void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
}
}
-/**
- * A version of #BLI_stack_pop_n which fills in an array (in the reverse order).
- *
- * \note The first item in the array will be first item added to the stack.
- */
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n)
{
BLI_assert(n <= BLI_stack_count(stack));
@@ -224,9 +184,6 @@ void *BLI_stack_peek(BLI_Stack *stack)
return stack_get_last_elem(stack);
}
-/**
- * Removes the top element from the stack.
- */
void BLI_stack_discard(BLI_Stack *stack)
{
BLI_assert(BLI_stack_is_empty(stack) == false);
@@ -247,9 +204,6 @@ void BLI_stack_discard(BLI_Stack *stack)
}
}
-/**
- * Discards all elements without freeing.
- */
void BLI_stack_clear(BLI_Stack *stack)
{
#ifdef USE_TOTELEM
@@ -304,9 +258,6 @@ size_t BLI_stack_count(const BLI_Stack *stack)
#endif
}
-/**
- * Returns true if the stack is empty, false otherwise
- */
bool BLI_stack_is_empty(const BLI_Stack *stack)
{
#ifdef USE_TOTELEM
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 47bb2f0e8dd..c5e30ac6a6b 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -72,12 +72,6 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-/**
- * Copies the current working directory into *dir (max size maxncpy), and
- * returns a pointer to same.
- *
- * \note can return NULL when the size is not big enough
- */
char *BLI_current_working_dir(char *dir, const size_t maxncpy)
{
#if defined(WIN32)
@@ -102,10 +96,6 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy)
#endif
}
-/**
- * Returns the number of free bytes on the volume containing the specified pathname. */
-/* Not actually used anywhere.
- */
double BLI_dir_free_space(const char *dir)
{
#ifdef WIN32
@@ -201,9 +191,6 @@ int64_t BLI_lseek(int fd, int64_t offset, int whence)
#endif
}
-/**
- * Returns the file size of an opened file descriptor.
- */
size_t BLI_file_descriptor_size(int file)
{
BLI_stat_t st;
@@ -213,9 +200,6 @@ size_t BLI_file_descriptor_size(int file)
return st.st_size;
}
-/**
- * Returns the size of a file.
- */
size_t BLI_file_size(const char *path)
{
BLI_stat_t stats;
@@ -343,10 +327,6 @@ bool BLI_file_alias_target(const char *filepath,
}
#endif
-/**
- * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails
- * (most likely doesn't exist or no access).
- */
int BLI_exists(const char *path)
{
#if defined(WIN32)
@@ -430,18 +410,11 @@ int BLI_stat(const char *path, struct stat *buffer)
}
#endif
-/**
- * Does the specified path point to a directory?
- * \note Would be better in fileops.c except that it needs stat.h so add here
- */
bool BLI_is_dir(const char *file)
{
return S_ISDIR(BLI_exists(file));
}
-/**
- * Does the specified path point to a non-directory?
- */
bool BLI_is_file(const char *path)
{
const int mode = BLI_exists(path);
@@ -528,33 +501,6 @@ void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t
return mem;
}
-/**
- * Return the text file data with:
-
- * - Newlines replaced with '\0'.
- * - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'.
- *
- * This is an alternative to using #BLI_file_read_as_lines,
- * allowing us to loop over lines without converting it into a linked list
- * with individual allocations.
- *
- * \param trim_trailing_space: Replace trailing spaces & tabs with nil.
- * This arguments prevents the caller from counting blank lines (if that's important).
- * \param pad_bytes: When this is non-zero, the first byte is set to nil,
- * to simplify parsing the file.
- * It's recommended to pass in 1, so all text is nil terminated.
- *
- * Example looping over lines:
- *
- * \code{.c}
- * size_t data_len;
- * char *data = BLI_file_read_text_as_mem_with_newline_as_nil(filepath, true, 1, &data_len);
- * char *data_end = data + data_len;
- * for (char *line = data; line != data_end; line = strlen(line) + 1) {
- * printf("line='%s'\n", line);
- * }
- * \endcode
- */
void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
bool trim_trailing_space,
size_t pad_bytes,
@@ -585,9 +531,6 @@ void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
return mem;
}
-/**
- * Reads the contents of a text file and returns the lines in a linked list.
- */
LinkNode *BLI_file_read_as_lines(const char *filepath)
{
FILE *fp = BLI_fopen(filepath, "r");
@@ -634,15 +577,11 @@ LinkNode *BLI_file_read_as_lines(const char *filepath)
return lines.list;
}
-/*
- * Frees memory from a previous call to BLI_file_read_as_lines.
- */
void BLI_file_free_lines(LinkNode *lines)
{
BLI_linklist_freeN(lines);
}
-/** is file1 older than file2 */
bool BLI_file_older(const char *file1, const char *file2)
{
#ifdef WIN32
diff --git a/source/blender/blenlib/intern/storage_apple.mm b/source/blender/blenlib/intern/storage_apple.mm
index 8af98d61ecb..b0234b9a093 100644
--- a/source/blender/blenlib/intern/storage_apple.mm
+++ b/source/blender/blenlib/intern/storage_apple.mm
@@ -99,7 +99,7 @@ static bool find_attribute(const std::string &attributes, const char *search_att
*/
static bool test_onedrive_file_is_placeholder(const char *path)
{
- /* Note: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file
+ /* NOTE: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file
* attribute. In theory this attribute can also be set on files that aren't located inside a
* OneDrive folder. Maybe additional checks are required? */
@@ -184,3 +184,20 @@ eFileAttributes BLI_file_attributes(const char *path)
return (eFileAttributes)ret;
}
+
+const char *BLI_expand_tilde(const char *path_with_tilde)
+{
+ static char path_expanded[FILE_MAX];
+ @autoreleasepool {
+ const NSString *const str_with_tilde = [[NSString alloc] initWithCString:path_with_tilde
+ encoding:NSUTF8StringEncoding];
+ if (!str_with_tilde) {
+ return nullptr;
+ }
+ const NSString *const str_expanded = [str_with_tilde stringByExpandingTildeInPath];
+ [str_expanded getCString:path_expanded
+ maxLength:sizeof(path_expanded)
+ encoding:NSUTF8StringEncoding];
+ }
+ return path_expanded;
+}
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 62c8625378d..2c626773871 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -42,15 +42,10 @@
// #define DEBUG_STRSIZE
-/**
- * Duplicates the first \a len bytes of cstring \a str
- * into a newly mallocN'd string and returns it. \a str
- * is assumed to be at least len bytes long.
- *
- * \param str: The string to be duplicated
- * \param len: The number of bytes to duplicate
- * \retval Returns the duplicated string
- */
+/* -------------------------------------------------------------------- */
+/** \name String Duplicate/Copy
+ * \{ */
+
char *BLI_strdupn(const char *str, const size_t len)
{
char *n = MEM_mallocN(len + 1, "strdup");
@@ -60,24 +55,11 @@ char *BLI_strdupn(const char *str, const size_t len)
return n;
}
-/**
- * Duplicates the cstring \a str into a newly mallocN'd
- * string and returns it.
- *
- * \param str: The string to be duplicated
- * \retval Returns the duplicated string
- */
char *BLI_strdup(const char *str)
{
return BLI_strdupn(str, strlen(str));
}
-/**
- * Appends the two strings, and returns new mallocN'ed string
- * \param str1: first string for copy
- * \param str2: second string for append
- * \retval Returns dst
- */
char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
{
/* include the NULL terminator of str2 only */
@@ -95,16 +77,6 @@ char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2)
return str;
}
-/**
- * Like strncpy but ensures dst is always
- * '\0' terminated.
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param maxncpy: Maximum number of characters to copy (generally
- * the size of dst)
- * \retval Returns dst
- */
char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
{
size_t srclen = BLI_strnlen(src, maxncpy - 1);
@@ -119,16 +91,6 @@ char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t
return dst;
}
-/**
- * Like BLI_strncpy but ensures dst is always padded by given char,
- * on both sides (unless src is empty).
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param pad: the char to use for padding
- * \param maxncpy: Maximum number of characters to copy (generally the size of dst)
- * \retval Returns dst
- */
char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src,
const char pad,
@@ -171,19 +133,6 @@ char *BLI_strncpy_ensure_pad(char *__restrict dst,
return dst;
}
-/**
- * Like strncpy but ensures dst is always
- * '\0' terminated.
- *
- * \note This is a duplicate of #BLI_strncpy that returns bytes copied.
- * And is a drop in replacement for 'snprintf(str, sizeof(str), "%s", arg);'
- *
- * \param dst: Destination for copy
- * \param src: Source string to copy
- * \param maxncpy: Maximum number of characters to copy (generally
- * the size of dst)
- * \retval The number of bytes copied (The only difference from BLI_strncpy).
- */
size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
{
size_t srclen = BLI_strnlen(src, maxncpy - 1);
@@ -205,9 +154,12 @@ size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src)
return srclen;
}
-/**
- * Portable replacement for `vsnprintf`.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Printing
+ * \{ */
+
size_t BLI_vsnprintf(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
@@ -231,9 +183,6 @@ size_t BLI_vsnprintf(char *__restrict buffer,
return n;
}
-/**
- * A version of #BLI_vsnprintf that returns `strlen(buffer)`
- */
size_t BLI_vsnprintf_rlen(char *__restrict buffer,
size_t maxncpy,
const char *__restrict format,
@@ -258,9 +207,6 @@ size_t BLI_vsnprintf_rlen(char *__restrict buffer,
return n;
}
-/**
- * Portable replacement for #snprintf
- */
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
{
size_t n;
@@ -277,9 +223,6 @@ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict
return n;
}
-/**
- * A version of #BLI_snprintf that returns `strlen(dst)`
- */
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
{
size_t n;
@@ -296,10 +239,6 @@ size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__res
return n;
}
-/**
- * Print formatted string into a newly #MEM_mallocN'd string
- * and return it.
- */
char *BLI_sprintfN(const char *__restrict format, ...)
{
DynStr *ds;
@@ -318,18 +257,12 @@ char *BLI_sprintfN(const char *__restrict format, ...)
return n;
}
-/**
- * This roughly matches C and Python's string escaping with double quotes - `"`.
- *
- * Since every character may need escaping,
- * it's common to create a buffer twice as large as the input.
- *
- * \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`.
- * \param src: The un-escaped source string.
- * \param dst_maxncpy: The maximum number of bytes allowable to copy.
- *
- * \note This is used for creating animation paths in blend files.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Escape/Un-Escape
+ * \{ */
+
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
{
@@ -381,18 +314,6 @@ BLI_INLINE bool str_unescape_pair(char c_next, char *r_out)
return false;
}
-/**
- * This roughly matches C and Python's string escaping with double quotes - `"`.
- *
- * The destination will never be larger than the source, it will either be the same
- * or up to half when all characters are escaped.
- *
- * \param dst: The destination string, at least the size of `strlen(src) + 1`.
- * \param src: The escaped source string.
- * \param src_maxncpy: The maximum number of bytes allowable to copy from `src`.
- * \param dst_maxncpy: The maximum number of bytes allowable to copy into `dst`.
- * \param r_is_complete: Set to true when
- */
size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src,
const size_t src_maxncpy,
@@ -418,16 +339,6 @@ size_t BLI_str_unescape_ex(char *__restrict dst,
return len;
}
-/**
- * See #BLI_str_unescape_ex doc-string.
- *
- * This function makes the assumption that `dst` always has
- * at least `src_maxncpy` bytes available.
- *
- * Use #BLI_str_unescape_ex if `dst` has a smaller fixed size.
- *
- * \note This is used for parsing animation paths in blend files (runs often).
- */
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
{
size_t len = 0;
@@ -442,14 +353,6 @@ size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const
return len;
}
-/**
- * Find the first un-escaped quote in the string (to find the end of the string).
- *
- * \param str: Typically this is the first character in a quoted string.
- * Where the character before `*str` would be `"`.
-
- * \return The pointer to the first un-escaped quote.
- */
const char *BLI_str_escape_find_quote(const char *str)
{
bool escape = false;
@@ -462,18 +365,12 @@ const char *BLI_str_escape_find_quote(const char *str)
return (*str == '"') ? str : NULL;
}
-/**
- * Return the range of the quoted string (excluding quotes) `str` after `prefix`.
- *
- * A version of #BLI_str_quoted_substrN that calculates the range
- * instead of un-escaping and allocating the result.
- *
- * \param str: String potentially including `prefix`.
- * \param prefix: Quoted string prefix.
- * \param r_start: The start of the quoted string (after the first quote).
- * \param r_end: The end of the quoted string (before the last quote).
- * \return True when a quoted string range could be found after `prefix`.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Quote/Un-Quote
+ * \{ */
+
bool BLI_str_quoted_substr_range(const char *__restrict str,
const char *__restrict prefix,
int *__restrict r_start,
@@ -539,19 +436,6 @@ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict
}
#endif
-/**
- * Fills \a result with text within "" that appear after some the contents of \a prefix.
- * i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
- *
- * \param str: is the entire string to chop.
- * \param prefix: is the part of the string to step over.
- * \param result: The buffer to fill.
- * \param result_maxlen: The maximum size of the buffer (including nil terminator).
- * \return True if the prefix was found and the entire quoted string was copied into result.
- *
- * Assume that the strings returned must be freed afterwards,
- * and that the inputs will contain data we want.
- */
bool BLI_str_quoted_substr(const char *__restrict str,
const char *__restrict prefix,
char *result,
@@ -570,19 +454,12 @@ bool BLI_str_quoted_substr(const char *__restrict str,
return is_complete;
}
-/**
- * string with all instances of substr_old replaced with substr_new,
- * Returns a copy of the c-string \a str into a newly #MEM_mallocN'd
- * and returns it.
- *
- * \note A rather wasteful string-replacement utility, though this shall do for now...
- * Feel free to replace this with an even safe + nicer alternative
- *
- * \param str: The string to replace occurrences of substr_old in
- * \param substr_old: The text in the string to find and replace
- * \param substr_new: The text in the string to find and replace
- * \retval Returns the duplicated string
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Replace
+ * \{ */
+
char *BLI_str_replaceN(const char *__restrict str,
const char *__restrict substr_old,
const char *__restrict substr_new)
@@ -638,13 +515,6 @@ char *BLI_str_replaceN(const char *__restrict str,
return BLI_strdup(str);
}
-/**
- * In-place replace every \a src to \a dst in \a str.
- *
- * \param str: The string to operate on.
- * \param src: The character to replace.
- * \param dst: The character to replace with.
- */
void BLI_str_replace_char(char *str, char src, char dst)
{
while (*str) {
@@ -655,13 +525,6 @@ void BLI_str_replace_char(char *str, char src, char dst)
}
}
-/**
- * Simple exact-match string replacement.
- *
- * \param replace_table: Array of source, destination pairs.
- *
- * \note Larger tables should use a hash table.
- */
bool BLI_str_replace_table_exact(char *string,
const size_t string_len,
const char *replace_table[][2],
@@ -678,19 +541,15 @@ bool BLI_str_replace_table_exact(char *string,
/** \} */
-/**
- * Compare two strings without regard to case.
- *
- * \retval True if the strings are equal, false otherwise.
- */
+/* -------------------------------------------------------------------- */
+/** \name String Comparison/Matching
+ * \{ */
+
int BLI_strcaseeq(const char *a, const char *b)
{
return (BLI_strcasecmp(a, b) == 0);
}
-/**
- * Portable replacement for `strcasestr` (not available in MSVC)
- */
char *BLI_strcasestr(const char *s, const char *find)
{
char c, sc;
@@ -745,9 +604,6 @@ bool BLI_string_all_words_matched(const char *name,
return all_words_matched;
}
-/**
- * Variation of #BLI_strcasestr with string length limited to \a len
- */
char *BLI_strncasestr(const char *s, const char *find, size_t len)
{
char c, sc;
@@ -875,10 +731,6 @@ static int left_number_strcmp(const char *s1, const char *s2, int *tiebreaker)
return 0;
}
-/**
- * Case insensitive, *natural* string comparison,
- * keeping numbers in order.
- */
int BLI_strcasecmp_natural(const char *s1, const char *s2)
{
int d1 = 0, d2 = 0;
@@ -946,10 +798,6 @@ int BLI_strcasecmp_natural(const char *s1, const char *s2)
return strcmp(s1, s2);
}
-/**
- * Like strcmp, but will ignore any heading/trailing pad char for comparison.
- * So e.g. if pad is '*', '*world' and 'world*' will compare equal.
- */
int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
{
size_t str1_len, str2_len;
@@ -990,7 +838,79 @@ int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad)
}
}
-/* determine the length of a fixed-size string */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Comparison at Start/End
+ * \{ */
+
+int BLI_str_index_in_array_n(const char *__restrict str,
+ const char **__restrict str_array,
+ const int str_array_len)
+{
+ int index;
+ const char **str_iter = str_array;
+
+ for (index = 0; index < str_array_len; str_iter++, index++) {
+ if (STREQ(str, *str_iter)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
+{
+ int index;
+ const char **str_iter = str_array;
+
+ for (index = 0; *str_iter; str_iter++, index++) {
+ if (STREQ(str, *str_iter)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
+{
+ for (; *str && *start; str++, start++) {
+ if (*str != *start) {
+ return false;
+ }
+ }
+
+ return (*start == '\0');
+}
+
+bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
+{
+ size_t elength = strlen(end);
+
+ if (elength < slength) {
+ const char *iter = &str[slength - elength];
+ while (*iter) {
+ if (*iter++ != *end++) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
+{
+ const size_t slength = strlen(str);
+ return BLI_strn_endswith(str, end, slength);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Length
+ * \{ */
+
size_t BLI_strnlen(const char *s, const size_t maxlen)
{
size_t len;
@@ -1003,6 +923,12 @@ size_t BLI_strnlen(const char *s, const size_t maxlen)
return len;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Case Conversion
+ * \{ */
+
void BLI_str_tolower_ascii(char *str, const size_t len)
{
size_t i;
@@ -1025,9 +951,12 @@ void BLI_str_toupper_ascii(char *str, const size_t len)
}
}
-/**
- * Strip white-space from end of the string.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Stripping
+ * \{ */
+
void BLI_str_rstrip(char *str)
{
for (int i = (int)strlen(str) - 1; i >= 0; i--) {
@@ -1040,15 +969,6 @@ void BLI_str_rstrip(char *str)
}
}
-/**
- * Strip trailing zeros from a float, eg:
- * 0.0000 -> 0.0
- * 2.0010 -> 2.001
- *
- * \param str:
- * \param pad:
- * \return The number of zeros stripped.
- */
int BLI_str_rstrip_float_zero(char *str, const char pad)
{
char *p = strchr(str, '.');
@@ -1069,138 +989,22 @@ int BLI_str_rstrip_float_zero(char *str, const char pad)
return totstrip;
}
-/**
- * Return index of a string in a string array.
- *
- * \param str: The string to find.
- * \param str_array: Array of strings.
- * \param str_array_len: The length of the array, or -1 for a NULL-terminated array.
- * \return The index of str in str_array or -1.
- */
-int BLI_str_index_in_array_n(const char *__restrict str,
- const char **__restrict str_array,
- const int str_array_len)
-{
- int index;
- const char **str_iter = str_array;
-
- for (index = 0; index < str_array_len; str_iter++, index++) {
- if (STREQ(str, *str_iter)) {
- return index;
- }
- }
- return -1;
-}
-
-/**
- * Return index of a string in a string array.
- *
- * \param str: The string to find.
- * \param str_array: Array of strings, (must be NULL-terminated).
- * \return The index of str in str_array or -1.
- */
-int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
-{
- int index;
- const char **str_iter = str_array;
-
- for (index = 0; *str_iter; str_iter++, index++) {
- if (STREQ(str, *str_iter)) {
- return index;
- }
- }
- return -1;
-}
-
-/**
- * Find if a string starts with another string.
- *
- * \param str: The string to search within.
- * \param start: The string we look for at the start.
- * \return If str starts with start.
- */
-bool BLI_str_startswith(const char *__restrict str, const char *__restrict start)
-{
- for (; *str && *start; str++, start++) {
- if (*str != *start) {
- return false;
- }
- }
-
- return (*start == '\0');
-}
-
-bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t slength)
-{
- size_t elength = strlen(end);
+/** \} */
- if (elength < slength) {
- const char *iter = &str[slength - elength];
- while (*iter) {
- if (*iter++ != *end++) {
- return false;
- }
- }
- return true;
- }
- return false;
-}
+/* -------------------------------------------------------------------- */
+/** \name String Split (Partition)
+ * \{ */
-/**
- * Find if a string ends with another string.
- *
- * \param str: The string to search within.
- * \param end: The string we look for at the end.
- * \return If str ends with end.
- */
-bool BLI_str_endswith(const char *__restrict str, const char *__restrict end)
-{
- const size_t slength = strlen(str);
- return BLI_strn_endswith(str, end, slength);
-}
-
-/**
- * Find the first char matching one of the chars in \a delim, from left.
- *
- * \param str: The string to search within.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
{
return BLI_str_partition_ex(str, NULL, delim, sep, suf, false);
}
-/**
- * Find the first char matching one of the chars in \a delim, from right.
- *
- * \param str: The string to search within.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
{
return BLI_str_partition_ex(str, NULL, delim, sep, suf, true);
}
-/**
- * Find the first char matching one of the chars in \a delim, either from left or right.
- *
- * \param str: The string to search within.
- * \param end: If non-NULL, the right delimiter of the string.
- * \param delim: The set of delimiters to search for, as unicode values.
- * \param sep: Return value, set to the first delimiter found (or NULL if none found).
- * \param suf: Return value, set to next char after the first delimiter found
- * (or NULL if none found).
- * \param from_right: If %true, search from the right of \a str, else, search from its left.
- * \return The length of the prefix (i.e. *sep - str).
- */
size_t BLI_str_partition_ex(const char *str,
const char *end,
const char delim[],
@@ -1251,6 +1055,47 @@ size_t BLI_str_partition_ex(const char *str,
return end ? (size_t)(end - str) : strlen(str);
}
+int BLI_string_find_split_words(
+ const char *str, const size_t len, const char delim, int r_words[][2], int words_max)
+{
+ int n = 0, i;
+ bool charsearch = true;
+
+ /* Skip leading spaces */
+ for (i = 0; (i < len) && (str[i] != '\0'); i++) {
+ if (str[i] != delim) {
+ break;
+ }
+ }
+
+ for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
+ if ((str[i] != delim) && (charsearch == true)) {
+ r_words[n][0] = i;
+ charsearch = false;
+ }
+ else {
+ if ((str[i] == delim) && (charsearch == false)) {
+ r_words[n][1] = i - r_words[n][0];
+ n++;
+ charsearch = true;
+ }
+ }
+ }
+
+ if (charsearch == false) {
+ r_words[n][1] = i - r_words[n][0];
+ n++;
+ }
+
+ return n;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name String Formatting (Numeric)
+ * \{ */
+
static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_len)
{
char *p_src = src;
@@ -1275,14 +1120,6 @@ static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_
return (size_t)(p_dst - dst);
}
-/**
- * Format ints with decimal grouping.
- * 1000 -> 1,000
- *
- * \param dst: The resulting string
- * \param num: Number to format
- * \return The length of \a dst
- */
size_t BLI_str_format_int_grouped(char dst[16], int num)
{
char src[16];
@@ -1291,14 +1128,6 @@ size_t BLI_str_format_int_grouped(char dst[16], int num)
return BLI_str_format_int_grouped_ex(src, dst, num_len);
}
-/**
- * Format uint64_t with decimal grouping.
- * 1000 -> 1,000
- *
- * \param dst: The resulting string
- * \param num: Number to format
- * \return The length of \a dst
- */
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
{
/* NOTE: Buffer to hold maximum unsigned int64, which is 1.8e+19. but
@@ -1309,16 +1138,6 @@ size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
return BLI_str_format_int_grouped_ex(src, dst, num_len);
}
-/**
- * Format a size in bytes using binary units.
- * 1000 -> 1 KB
- * Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
- *
- * \param dst: The resulting string.
- * Dimension of 14 to support largest possible value for \a bytes (#LLONG_MAX).
- * \param bytes: Number to format.
- * \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
- */
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
{
double bytes_converted = bytes;
@@ -1345,24 +1164,6 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base
BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_len - len);
}
-/**
- * Format a count to up to 6 places (plus '\0' terminator) string using long number
- * names abbreviations. Used to produce a compact representation of large numbers.
- *
- * 1 -> 1
- * 15 -> 15
- * 155 -> 155
- * 1555 -> 1.6K
- * 15555 -> 15.6K
- * 155555 -> 156K
- * 1555555 -> 1.6M
- * 15555555 -> 15.6M
- * 155555555 -> 156M
- * 1000000000 -> 1B
- * ...
- *
- * Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
- */
void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format)
{
float number_to_format_converted = number_to_format;
@@ -1384,47 +1185,4 @@ void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format)
BLI_snprintf(dst, dst_len, "%.*f%s", decimals, number_to_format_converted, units[order]);
}
-/**
- * Find the ranges needed to split \a str into its individual words.
- *
- * \param str: The string to search for words.
- * \param len: Size of the string to search.
- * \param delim: Character to use as a delimiter.
- * \param r_words: Info about the words found. Set to [index, len] pairs.
- * \param words_max: Max number of words to find
- * \return The number of words found in \a str
- */
-int BLI_string_find_split_words(
- const char *str, const size_t len, const char delim, int r_words[][2], int words_max)
-{
- int n = 0, i;
- bool charsearch = true;
-
- /* Skip leading spaces */
- for (i = 0; (i < len) && (str[i] != '\0'); i++) {
- if (str[i] != delim) {
- break;
- }
- }
-
- for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
- if ((str[i] != delim) && (charsearch == true)) {
- r_words[n][0] = i;
- charsearch = false;
- }
- else {
- if ((str[i] == delim) && (charsearch == false)) {
- r_words[n][1] = i - r_words[n][0];
- n++;
- charsearch = true;
- }
- }
- }
-
- if (charsearch == false) {
- r_words[n][1] = i - r_words[n][0];
- n++;
- }
-
- return n;
-}
+/** \} */
diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc
index 08ba473f96b..c5528dce2f2 100644
--- a/source/blender/blenlib/intern/string_search.cc
+++ b/source/blender/blenlib/intern/string_search.cc
@@ -35,14 +35,6 @@ static int64_t count_utf8_code_points(StringRef str)
return static_cast<int64_t>(BLI_strnlen_utf8(str.data(), static_cast<size_t>(str.size())));
}
-/**
- * Computes the cost of transforming string a into b. The cost/distance is the minimal number of
- * operations that need to be executed. Valid operations are deletion, insertion, substitution and
- * transposition.
- *
- * This function is utf8 aware in the sense that it works at the level of individual code points
- * (1-4 bytes long) instead of on individual bytes.
- */
int damerau_levenshtein_distance(StringRef a, StringRef b)
{
constexpr int deletion_cost = 1;
@@ -106,10 +98,6 @@ int damerau_levenshtein_distance(StringRef a, StringRef b)
return v1.last();
}
-/**
- * Returns -1 when this is no reasonably good match.
- * Otherwise returns the number of errors in the match.
- */
int get_fuzzy_match_errors(StringRef query, StringRef full)
{
/* If it is a perfect partial match, return immediately. */
@@ -346,10 +334,6 @@ static int score_query_against_words(Span<StringRef> query_words, Span<StringRef
return total_match_score;
}
-/**
- * Splits a string into words and normalizes them (currently that just means converting to lower
- * case). The returned strings are allocated in the given allocator.
- */
void extract_normalized_words(StringRef str,
LinearAllocator<> &allocator,
Vector<StringRef, 64> &r_words)
@@ -405,6 +389,7 @@ struct SearchItem {
blender::Span<blender::StringRef> normalized_words;
int length;
void *user_data;
+ int weight;
};
struct StringSearch {
@@ -417,25 +402,21 @@ StringSearch *BLI_string_search_new()
return new StringSearch();
}
-/**
- * Add a new possible result to the search.
- * The caller keeps ownership of all parameters.
- */
-void BLI_string_search_add(StringSearch *search, const char *str, void *user_data)
+void BLI_string_search_add(StringSearch *search,
+ const char *str,
+ void *user_data,
+ const int weight)
{
using namespace blender;
Vector<StringRef, 64> words;
StringRef str_ref{str};
string_search::extract_normalized_words(str_ref, search->allocator, words);
- search->items.append(
- {search->allocator.construct_array_copy(words.as_span()), (int)str_ref.size(), user_data});
+ search->items.append({search->allocator.construct_array_copy(words.as_span()),
+ (int)str_ref.size(),
+ user_data,
+ weight});
}
-/**
- * Filter and sort all previously added search items.
- * Returns an array containing the filtered user data.
- * The caller has to free the returned array.
- */
int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data)
{
using namespace blender;
@@ -474,6 +455,11 @@ int BLI_string_search_query(StringSearch *search, const char *query, void ***r_d
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
return search->items[a].length < search->items[b].length;
});
+ /* Prefer items with larger weights. Use `stable_sort` so that if the weights are the same,
+ * the order won't be changed. */
+ std::stable_sort(indices.begin(), indices.end(), [&](int a, int b) {
+ return search->items[a].weight > search->items[b].weight;
+ });
}
sorted_result_indices.extend(indices);
}
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index b9ea538ff24..807344a912c 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -42,9 +42,11 @@
// #define DEBUG_STRSIZE
-/* array copied from glib's gutf8.c, */
-/* NOTE: last two values (0xfe and 0xff) are forbidden in utf-8,
- * so they are considered 1 byte length too. */
+/**
+ * Array copied from GLIB's `gutf8.c`.
+ * \note last two values (0xfe and 0xff) are forbidden in UTF-8,
+ * so they are considered 1 byte length too.
+ */
static const size_t utf8_skip_data[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -56,22 +58,18 @@ static const size_t utf8_skip_data[256] = {
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1,
};
-/* from libswish3, originally called u8_isvalid(),
- * modified to return the index of the bad character (byte index not utf).
- * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
-
-/* based on the valid_utf8 routine from the PCRE library by Philip Hazel
- *
- * length is in bytes, since without knowing whether the string is valid
- * it's hard to know how many characters there are! */
-
-/**
- * Find first utf-8 invalid byte in given \a str, of \a length bytes.
- *
- * \return the offset of the first invalid byte.
- */
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length)
{
+ /* NOTE(@campbellbarton): from libswish3, originally called u8_isvalid(),
+ * modified to return the index of the bad character (byte index not UTF).
+ * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044.
+ *
+ * Comment from code in: `libswish3`.
+ * Based on the `valid_utf8` routine from the PCRE library by Philip Hazel
+ *
+ * length is in bytes, since without knowing whether the string is valid
+ * it's hard to know how many characters there are! */
+
const unsigned char *p, *perr, *pend = (const unsigned char *)str + length;
unsigned char c;
int ab;
@@ -195,11 +193,6 @@ utf8_error:
return ((const char *)perr - (const char *)str);
}
-/**
- * Remove any invalid utf-8 byte (taking into account multi-bytes sequence of course).
- *
- * \return number of stripped bytes.
- */
int BLI_str_utf8_invalid_strip(char *str, size_t length)
{
ptrdiff_t bad_char;
@@ -312,7 +305,6 @@ size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
return len;
}
-/* wchar len in utf8 */
size_t BLI_wstrlen_utf8(const wchar_t *src)
{
size_t len = 0;
@@ -362,11 +354,6 @@ size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_
return len;
}
-/**
- * \param strc: the string to measure the length.
- * \param maxlen: the string length (in bytes)
- * \return the unicode length (not in bytes!)
- */
size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
{
size_t len_bytes;
@@ -389,8 +376,6 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w,
/* end wchar_t / utf8 functions */
/* --------------------------------------------------------------------------*/
-/* count columns that character/string occupies, based on wcwidth.c */
-
int BLI_wcwidth(char32_t ucs)
{
return mk_wcwidth(ucs);
@@ -475,10 +460,10 @@ int BLI_str_utf8_char_width_safe(const char *p)
} \
(void)0
-/* uses glib functions but not from glib */
-/* gets the size of a single utf8 char */
int BLI_str_utf8_size(const char *p)
{
+ /* NOTE: uses glib functions but not from GLIB. */
+
int mask = 0, len;
const unsigned char c = (unsigned char)*p;
@@ -489,7 +474,6 @@ int BLI_str_utf8_size(const char *p)
return len;
}
-/* use when we want to skip errors */
int BLI_str_utf8_size_safe(const char *p)
{
int mask = 0, len;
@@ -502,21 +486,10 @@ int BLI_str_utf8_size_safe(const char *p)
return len;
}
-/* was g_utf8_get_char */
-/**
- * BLI_str_utf8_as_unicode:
- * \param p: a pointer to Unicode character encoded as UTF-8
- *
- * Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
- * If \a p does not point to a valid UTF-8 encoded character, results are
- * undefined. If you are not sure that the bytes are complete
- * valid Unicode characters, you should use g_utf8_get_char_validated()
- * instead.
- *
- * Return value: the resulting character
- */
uint BLI_str_utf8_as_unicode(const char *p)
{
+ /* Originally `g_utf8_get_char` in GLIB. */
+
int i, len;
uint mask = 0;
uint result;
@@ -531,19 +504,6 @@ uint BLI_str_utf8_as_unicode(const char *p)
return result;
}
-/**
- * UTF8 decoding that steps over the index (unless an error is encountered).
- *
- * \param p: The text to step over.
- * \param p_len: The length of `p`.
- * \param index: Index of `p` to step over.
- * \return the code-point or #BLI_UTF8_ERR if there is a decoding error.
- *
- * \note The behavior for clipped text (where `p_len` limits decoding trailing bytes)
- * must have the same behavior is encountering a nil byte,
- * so functions that only use the first part of a string has matching behavior to functions
- * that null terminate the text.
- */
uint BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p,
const size_t p_len,
size_t *__restrict index)
@@ -569,16 +529,6 @@ uint BLI_str_utf8_as_unicode_step_or_error(const char *__restrict p,
return result;
}
-/**
- * UTF8 decoding that steps over the index (unless an error is encountered).
- *
- * \param p: The text to step over.
- * \param p_len: The length of `p`.
- * \param index: Index of `p` to step over.
- * \return the code-point `(p + *index)` if there is a decoding error.
- *
- * \note Falls back to `LATIN1` for text drawing.
- */
uint BLI_str_utf8_as_unicode_step(const char *__restrict p,
const size_t p_len,
size_t *__restrict index)
@@ -633,18 +583,6 @@ size_t BLI_str_utf8_from_unicode_len(const uint c)
return len;
}
-/**
- * BLI_str_utf8_from_unicode:
- *
- * \param c: a Unicode character code
- * \param outbuf: output buffer, must have at least `outbuf_len` bytes of space.
- * If the length required by `c` exceeds `outbuf_len`,
- * the bytes available bytes will be zeroed and `outbuf_len` returned.
- *
- * Converts a single character to UTF-8.
- *
- * \return number of bytes written.
- */
size_t BLI_str_utf8_from_unicode(uint c, char *outbuf, const size_t outbuf_len)
{
@@ -724,7 +662,6 @@ size_t BLI_str_utf32_as_utf8(char *__restrict dst,
return len;
}
-/* utf32 len in utf8 */
size_t BLI_str_utf32_as_utf8_len(const char32_t *src)
{
size_t len = 0;
@@ -736,24 +673,10 @@ size_t BLI_str_utf32_as_utf8_len(const char32_t *src)
return len;
}
-/* was g_utf8_find_prev_char */
-/**
- * BLI_str_find_prev_char_utf8:
- * \param str: pointer to the beginning of a UTF-8 encoded string
- * \param p: pointer to some position within \a str
- *
- * Given a position \a p with a UTF-8 encoded string \a str, find the start
- * of the previous UTF-8 character starting before. \a p Returns \a str_start if no
- * UTF-8 characters are present in \a str_start before \a p.
- *
- * \a p does not have to be at the beginning of a UTF-8 character. No check
- * is made to see if the character found is actually valid other than
- * it starts with an appropriate byte.
- *
- * \return A pointer to the found character.
- */
const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
{
+ /* Originally `g_utf8_find_prev_char` in GLIB. */
+
BLI_assert(p >= str_start);
if (str_start < p) {
for (--p; p >= str_start; p--) {
@@ -765,22 +688,10 @@ const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
return p;
}
-/* was g_utf8_find_next_char */
-/**
- * BLI_str_find_next_char_utf8:
- * \param p: a pointer to a position within a UTF-8 encoded string
- * \param end: a pointer to the byte following the end of the string.
- *
- * Finds the start of the next UTF-8 character in the string after \a p
- *
- * \a p does not have to be at the beginning of a UTF-8 character. No check
- * is made to see if the character found is actually valid other than
- * it starts with an appropriate byte.
- *
- * \return a pointer to the found character or a pointer to the null terminating character '\0'.
- */
const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end)
{
+ /* Originally `g_utf8_find_next_char` in GLIB. */
+
BLI_assert(p <= str_end);
if ((p < str_end) && (*p != '\0')) {
for (++p; p < str_end && (*p & 0xc0) == 0x80; p++) {
diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c
index b62b9c3bc7a..21162904dbd 100644
--- a/source/blender/blenlib/intern/string_utils.c
+++ b/source/blender/blenlib/intern/string_utils.c
@@ -38,20 +38,6 @@
# pragma GCC diagnostic error "-Wsign-conversion"
#endif
-/**
- * Looks for a numeric suffix preceded by delim character on the end of
- * name, puts preceding part into *left and value of suffix into *nr.
- * Returns the length of *left.
- *
- * Foo.001 -> "Foo", 1
- * Returning the length of "Foo"
- *
- * \param left: Where to return copy of part preceding delim
- * \param nr: Where to return value of numeric suffix
- * \param name: String to split
- * \param delim: Delimiter character
- * \return Length of \a left
- */
size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
{
const size_t name_len = strlen(name);
@@ -102,10 +88,6 @@ static bool is_char_sep(const char c)
return ELEM(c, '.', ' ', '-', '_');
}
-/**
- * based on `BLI_split_dirfile()` / `os.path.splitext()`,
- * `"a.b.c"` -> (`"a.b"`, `".c"`).
- */
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
{
size_t len = BLI_strnlen(string, str_len);
@@ -124,9 +106,6 @@ void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, cons
memcpy(r_body, string, len + 1);
}
-/**
- * `"a.b.c"` -> (`"a."`, `"b.c"`)
- */
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
{
size_t len = BLI_strnlen(string, str_len);
@@ -146,17 +125,6 @@ void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, cons
BLI_strncpy(r_body, string, len);
}
-/**
- * Finds the best possible flipped (left/right) name.
- * For renaming; check for unique names afterwards.
- *
- * \param r_name: flipped name,
- * assumed to be a pointer to a string of at least \a name_len size.
- * \param from_name: original name,
- * assumed to be a pointer to a string of at least \a name_len size.
- * \param strip_number: If set, remove number extensions.
- * \return The number of bytes written into \a r_name.
- */
size_t BLI_string_flip_side_name(char *r_name,
const char *from_name,
const bool strip_number,
@@ -278,18 +246,6 @@ size_t BLI_string_flip_side_name(char *r_name,
/* Unique name utils. */
-/**
- * Ensures name is unique (according to criteria specified by caller in unique_check callback),
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param unique_check: Return true if name is not unique
- * \param arg: Additional arg to unique_check--meaning is up to caller
- * \param defname: To initialize name if latter is empty
- * \param delim: Delimits numeric suffix in name
- * \param name: Name to be ensured unique
- * \param name_len: Maximum length of name area
- * \return true if there if the name was changed
- */
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
void *arg,
const char *defname,
@@ -366,17 +322,6 @@ static bool uniquename_unique_check(void *arg, const char *name)
return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset);
}
-/**
- * Ensures that the specified block has a unique name within the containing list,
- * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
- *
- * \param list: List containing the block
- * \param vlink: The block to check the name for
- * \param defname: To initialize block name if latter is empty
- * \param delim: Delimits numeric suffix in name
- * \param name_offset: Offset of name within block structure
- * \param name_len: Maximum length of name area
- */
bool BLI_uniquename(
ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len)
{
@@ -432,9 +377,6 @@ char *BLI_string_join_array(char *result,
return c;
}
-/**
- * A version of #BLI_string_join that takes a separator which can be any character including '\0'.
- */
char *BLI_string_join_array_by_sep_char(
char *result, size_t result_len, char sep, const char *strings[], uint strings_len)
{
@@ -455,9 +397,6 @@ char *BLI_string_join_array_by_sep_char(
return c;
}
-/**
- * Join an array of strings into a newly allocated, null terminated string.
- */
char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
{
uint total_len = 1;
@@ -474,9 +413,6 @@ char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
return result;
}
-/**
- * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
- */
char *BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint strings_len)
{
uint total_len = 0;
@@ -501,10 +437,6 @@ char *BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint s
return result;
}
-/**
- * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
- * The new location of each string is written into this array.
- */
char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
char *table[],
const char *strings[],
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 66d0b44cfb3..e64d53467e4 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -73,9 +73,6 @@ int BLI_cpu_support_sse2(void)
/* Windows stack-walk lives in system_win32.c */
#if !defined(_MSC_VER)
-/**
- * Write a backtrace into a file for systems which support it.
- */
void BLI_system_backtrace(FILE *fp)
{
/* ------------- */
diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c
index f65234b656b..b2360cf743f 100644
--- a/source/blender/blenlib/intern/system_win32.c
+++ b/source/blender/blenlib/intern/system_win32.c
@@ -373,6 +373,9 @@ static void bli_load_symbols()
}
}
+/**
+ * Write a backtrace into a file for systems which support it.
+ */
void BLI_system_backtrace(FILE *fp)
{
SymInitialize(GetCurrentProcess(), NULL, TRUE);
diff --git a/source/blender/blenlib/intern/task_iterator.c b/source/blender/blenlib/intern/task_iterator.c
index 6378d88e2b1..49666eb3082 100644
--- a/source/blender/blenlib/intern/task_iterator.c
+++ b/source/blender/blenlib/intern/task_iterator.c
@@ -274,21 +274,6 @@ static void task_parallel_iterator_do(const TaskParallelSettings *settings,
state->iter_shared.spin_lock = NULL;
}
-/**
- * This function allows to parallelize for loops using a generic iterator.
- *
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param iter_func: Callback function used to generate chunks of items.
- * \param init_item: The initial item, if necessary (may be NULL if unused).
- * \param init_index: The initial index.
- * \param tot_items: The total amount of items to iterate over
- * (if unknown, set it to a negative number).
- * \param func: Callback function.
- * \param settings: See public API doc of TaskParallelSettings for description of all settings.
- *
- * \note Static scheduling is only available when \a tot_items is >= 0.
- */
-
void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorIterFunc iter_func,
void *init_item,
@@ -332,17 +317,6 @@ static void task_parallel_listbase_get(void *__restrict UNUSED(userdata),
(*r_next_index)++;
}
-/**
- * This function allows to parallelize for loops over ListBase items.
- *
- * \param listbase: The double linked list to loop over.
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param func: Callback function.
- * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
- *
- * \note There is no static scheduling here,
- * since it would need another full loop over items to count them.
- */
void BLI_task_parallel_listbase(ListBase *listbase,
void *userdata,
TaskParallelIteratorFunc func,
@@ -388,16 +362,6 @@ static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata)
}
}
-/**
- * This function allows to parallelize for loops over Mempool items.
- *
- * \param mempool: The iterable BLI_mempool to loop over.
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param func: Callback function.
- * \param settings: See public API doc of TaskParallelSettings for description of all settings.
- *
- * \note There is no static scheduling here.
- */
void BLI_task_parallel_mempool(BLI_mempool *mempool,
void *userdata,
TaskParallelMempoolFunc func,
diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc
index 35097013439..3589c952409 100644
--- a/source/blender/blenlib/intern/threads.cc
+++ b/source/blender/blenlib/intern/threads.cc
@@ -140,7 +140,7 @@ struct ThreadSlot {
int avail;
};
-void BLI_threadapi_init(void)
+void BLI_threadapi_init()
{
mainid = pthread_self();
if (numaAPI_Initialize() == NUMAAPI_SUCCESS) {
@@ -148,14 +148,10 @@ void BLI_threadapi_init(void)
}
}
-void BLI_threadapi_exit(void)
+void BLI_threadapi_exit()
{
}
-/* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
- * problem otherwise: scene render will kill of the mutex!
- */
-
void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int tot)
{
int a;
@@ -189,7 +185,6 @@ void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int t
}
}
-/* amount of available threads */
int BLI_available_threads(ListBase *threadbase)
{
int counter = 0;
@@ -203,7 +198,6 @@ int BLI_available_threads(ListBase *threadbase)
return counter;
}
-/* returns thread number, for sample patterns or threadsafe tables */
int BLI_threadpool_available_thread_index(ListBase *threadbase)
{
int counter = 0;
@@ -231,7 +225,7 @@ static void *tslot_thread_start(void *tslot_p)
return tslot->do_thread(tslot->callerdata);
}
-int BLI_thread_is_main(void)
+int BLI_thread_is_main()
{
return pthread_equal(pthread_self(), mainid);
}
@@ -305,8 +299,7 @@ void BLI_threadpool_end(ListBase *threadbase)
/* System Information */
-/* how many threads are native on this system? */
-int BLI_system_thread_count(void)
+int BLI_system_thread_count()
{
static int t = -1;
@@ -347,7 +340,7 @@ void BLI_system_num_threads_override_set(int num)
num_threads_override = num;
}
-int BLI_system_num_threads_override_get(void)
+int BLI_system_num_threads_override_get()
{
return num_threads_override;
}
@@ -418,7 +411,7 @@ void BLI_mutex_end(ThreadMutex *mutex)
pthread_mutex_destroy(mutex);
}
-ThreadMutex *BLI_mutex_alloc(void)
+ThreadMutex *BLI_mutex_alloc()
{
ThreadMutex *mutex = static_cast<ThreadMutex *>(MEM_callocN(sizeof(ThreadMutex), "ThreadMutex"));
BLI_mutex_init(mutex);
@@ -533,7 +526,7 @@ void BLI_rw_mutex_end(ThreadRWMutex *mutex)
pthread_rwlock_destroy(mutex);
}
-ThreadRWMutex *BLI_rw_mutex_alloc(void)
+ThreadRWMutex *BLI_rw_mutex_alloc()
{
ThreadRWMutex *mutex = static_cast<ThreadRWMutex *>(
MEM_callocN(sizeof(ThreadRWMutex), "ThreadRWMutex"));
@@ -555,7 +548,7 @@ struct TicketMutex {
unsigned int queue_head, queue_tail;
};
-TicketMutex *BLI_ticket_mutex_alloc(void)
+TicketMutex *BLI_ticket_mutex_alloc()
{
TicketMutex *ticket = static_cast<TicketMutex *>(
MEM_callocN(sizeof(TicketMutex), "TicketMutex"));
@@ -640,7 +633,7 @@ struct ThreadQueue {
volatile int canceled;
};
-ThreadQueue *BLI_thread_queue_init(void)
+ThreadQueue *BLI_thread_queue_init()
{
ThreadQueue *queue;
@@ -818,8 +811,7 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue)
/* **** Special functions to help performance on crazy NUMA setups. **** */
#if 0 /* UNUSED */
-static bool check_is_threadripper2_alike_topology(void)
-{
+static bool check_is_threadripper2_alike_topology(){
/* NOTE: We hope operating system does not support CPU hot-swap to
* a different brand. And that SMP of different types is also not
* encouraged by the system. */
@@ -860,8 +852,7 @@ static bool check_is_threadripper2_alike_topology(void)
return is_threadripper2;
}
-static void threadripper_put_process_on_fast_node(void)
-{
+static void threadripper_put_process_on_fast_node(){
if (!is_numa_available) {
return;
}
@@ -880,8 +871,7 @@ static void threadripper_put_process_on_fast_node(void)
numaAPI_RunProcessOnNode(0);
}
-static void threadripper_put_thread_on_fast_node(void)
-{
+static void threadripper_put_thread_on_fast_node(){
if (!is_numa_available) {
return;
}
@@ -899,7 +889,7 @@ static void threadripper_put_thread_on_fast_node(void)
}
#endif /* UNUSED */
-void BLI_thread_put_process_on_fast_node(void)
+void BLI_thread_put_process_on_fast_node()
{
/* Disabled for now since this causes only 16 threads to be used on a
* thread-ripper for computations like sculpting and fluid sim. The problem
@@ -915,7 +905,7 @@ void BLI_thread_put_process_on_fast_node(void)
#endif
}
-void BLI_thread_put_thread_on_fast_node(void)
+void BLI_thread_put_thread_on_fast_node()
{
/* Disabled for now, see comment above. */
#if 0
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 13f95ddf264..55131fa639d 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -35,19 +35,6 @@
#include "BLI_strict_flags.h"
-/**
- * Generate time-code/frame number string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param brevity_level: special setting for #View2D grid drawing,
- * used to specify how detailed we need to be
- * \param time_seconds: time total time in seconds
- * \param fps: frames per second, typically from the #FPS macro
- * \param timecode_style: enum from #eTimecodeStyles
- * \return length of \a str
- */
-
size_t BLI_timecode_string_from_time(char *str,
const size_t maxncpy,
const int brevity_level,
@@ -195,14 +182,6 @@ size_t BLI_timecode_string_from_time(char *str,
return rlen;
}
-/**
- * Generate time string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param time_seconds: time total time in seconds
- * \return length of \a str
- */
size_t BLI_timecode_string_from_time_simple(char *str,
const size_t maxncpy,
const double time_seconds)
@@ -225,18 +204,6 @@ size_t BLI_timecode_string_from_time_simple(char *str,
return rlen;
}
-/**
- * Generate time string and store in \a str
- *
- * \param str: destination string
- * \param maxncpy: maximum number of characters to copy `sizeof(str)`
- * \param brevity_level: special setting for #View2D grid drawing,
- * used to specify how detailed we need to be
- * \param time_seconds: time total time in seconds
- * \return length of \a str
- *
- * \note in some cases this is used to print non-seconds values.
- */
size_t BLI_timecode_string_from_time_seconds(char *str,
const size_t maxncpy,
const int brevity_level,
diff --git a/source/blender/blenlib/intern/uuid.cc b/source/blender/blenlib/intern/uuid.cc
index de4602bf3ed..e2578ffa7c7 100644
--- a/source/blender/blenlib/intern/uuid.cc
+++ b/source/blender/blenlib/intern/uuid.cc
@@ -81,7 +81,7 @@ bUUID BLI_uuid_generate_random()
return uuid;
}
-bUUID BLI_uuid_nil(void)
+bUUID BLI_uuid_nil()
{
const bUUID nil = {0, 0, 0, 0, 0, {0}};
return nil;
diff --git a/source/blender/blenlib/intern/uvproject.c b/source/blender/blenlib/intern/uvproject.c
index 093d08e643d..dbab0162eba 100644
--- a/source/blender/blenlib/intern/uvproject.c
+++ b/source/blender/blenlib/intern/uvproject.c
@@ -90,7 +90,6 @@ void BLI_uvproject_from_camera(float target[2], float source[3], ProjCameraInfo
target[1] += uci->shifty;
}
-/* could rv3d->persmat */
void BLI_uvproject_from_view(float target[2],
float source[3],
float persmat[4][4],
@@ -132,8 +131,6 @@ void BLI_uvproject_from_view(float target[2],
target[1] = (y + target[1]) / winy;
}
-/* 'rotmat' can be `obedit->obmat` when uv project is used.
- * 'winx' and 'winy' can be from `scene->r.xsch/ysch` */
ProjCameraInfo *BLI_uvproject_camera_info(Object *ob, float rotmat[4][4], float winx, float winy)
{
ProjCameraInfo uci;
diff --git a/source/blender/blenlib/intern/voxel.c b/source/blender/blenlib/intern/voxel.c
index c0c895654e3..a2b29ce1185 100644
--- a/source/blender/blenlib/intern/voxel.c
+++ b/source/blender/blenlib/intern/voxel.c
@@ -35,7 +35,7 @@ BLI_INLINE float D(const float *data, const int res[3], int x, int y, int z)
}
/* *** nearest neighbor *** */
-/* input coordinates must be in bounding box 0.0 - 1.0 */
+
float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3])
{
int xi, yi, zi;
diff --git a/source/blender/blenlib/tests/BLI_color_test.cc b/source/blender/blenlib/tests/BLI_color_test.cc
index a91c743b133..5194d8048bf 100644
--- a/source/blender/blenlib/tests/BLI_color_test.cc
+++ b/source/blender/blenlib/tests/BLI_color_test.cc
@@ -6,8 +6,8 @@
namespace blender::tests {
-/**
- * \name Conversions
+/* -------------------------------------------------------------------- */
+/** \name Conversions
* \{ */
TEST(color, ThemeByteToFloat)
diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
index 7a548e7c434..62b7b383831 100644
--- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
@@ -170,7 +170,7 @@ TEST(virtual_array, MutableToImmutable)
EXPECT_TRUE(varray.is_span());
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[1], 2);
- EXPECT_EQ(mutable_varray.size(), 0);
+ EXPECT_EQ(mutable_varray.size(), 0); /* NOLINT: bugprone-use-after-move */
}
{
VArray<int> varray = VMutableArray<int>::ForSpan(array);
diff --git a/source/blender/blenloader/BLO_blend_validate.h b/source/blender/blenloader/BLO_blend_validate.h
index cdbf4bdd952..3a192284661 100644
--- a/source/blender/blenloader/BLO_blend_validate.h
+++ b/source/blender/blenloader/BLO_blend_validate.h
@@ -28,5 +28,12 @@
struct Main;
struct ReportList;
+/**
+ * Check (but do *not* fix) that all linked data-blocks are still valid
+ * (i.e. pointing to the right library).
+ */
bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports);
+/**
+ * * Check (and fix if needed) that shape key's 'from' pointer is valid.
+ */
bool BLO_main_validate_shapekeys(struct Main *bmain, struct ReportList *reports);
diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h
index ca7ea6d8f09..fe8173e335a 100644
--- a/source/blender/blenloader/BLO_read_write.h
+++ b/source/blender/blenloader/BLO_read_write.h
@@ -58,8 +58,8 @@ struct BlendFileReadReport;
struct Main;
struct ReportList;
-/* Blend Write API
- * ===============
+/* -------------------------------------------------------------------- */
+/** \name Blend Write API
*
* Most functions fall into one of two categories. Either they write a DNA struct or a raw memory
* buffer to the .blend file.
@@ -91,19 +91,25 @@ struct ReportList;
* The code that reads this data might have to correct its byte-order. For the common cases
* there are convenience functions that write and read arrays of simple types such as `int32`.
* Those will correct endianness automatically.
- */
+ * \{ */
-/* Mapping between names and ids. */
+/**
+ * Mapping between names and ids.
+ */
int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name);
#define BLO_get_struct_id(writer, struct_name) SDNA_TYPE_FROM_STRUCT(struct_name)
-/* Write single struct. */
+/**
+ * Write single struct.
+ */
void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr);
void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr);
#define BLO_write_struct(writer, struct_name, data_ptr) \
BLO_write_struct_by_id(writer, BLO_get_struct_id(writer, struct_name), data_ptr)
-/* Write single struct at address. */
+/**
+ * Write single struct at address.
+ */
void BLO_write_struct_at_address_by_id(BlendWriter *writer,
int struct_id,
const void *address,
@@ -112,7 +118,9 @@ void BLO_write_struct_at_address_by_id(BlendWriter *writer,
BLO_write_struct_at_address_by_id( \
writer, BLO_get_struct_id(writer, struct_name), address, data_ptr)
-/* Write single struct at address and specify a filecode. */
+/**
+ * Write single struct at address and specify a file-code.
+ */
void BLO_write_struct_at_address_by_id_with_filecode(
BlendWriter *writer, int filecode, int struct_id, const void *address, const void *data_ptr);
#define BLO_write_struct_at_address_with_filecode( \
@@ -120,7 +128,9 @@ void BLO_write_struct_at_address_by_id_with_filecode(
BLO_write_struct_at_address_by_id_with_filecode( \
writer, filecode, BLO_get_struct_id(writer, struct_name), address, data_ptr)
-/* Write struct array. */
+/**
+ * Write struct array.
+ */
void BLO_write_struct_array_by_name(BlendWriter *writer,
const char *struct_name,
int array_size,
@@ -133,14 +143,18 @@ void BLO_write_struct_array_by_id(BlendWriter *writer,
BLO_write_struct_array_by_id( \
writer, BLO_get_struct_id(writer, struct_name), array_size, data_ptr)
-/* Write struct array at address. */
+/**
+ * Write struct array at address.
+ */
void BLO_write_struct_array_at_address_by_id(
BlendWriter *writer, int struct_id, int array_size, const void *address, const void *data_ptr);
#define BLO_write_struct_array_at_address(writer, struct_name, array_size, address, data_ptr) \
BLO_write_struct_array_at_address_by_id( \
writer, BLO_get_struct_id(writer, struct_name), array_size, address, data_ptr)
-/* Write struct list. */
+/**
+ * Write struct list.
+ */
void BLO_write_struct_list_by_name(BlendWriter *writer,
const char *struct_name,
struct ListBase *list);
@@ -148,7 +162,9 @@ void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, struct List
#define BLO_write_struct_list(writer, struct_name, list_ptr) \
BLO_write_struct_list_by_id(writer, BLO_get_struct_id(writer, struct_name), list_ptr)
-/* Write id struct. */
+/**
+ * Write id struct.
+ */
void blo_write_id_struct(BlendWriter *writer,
int struct_id,
const void *id_address,
@@ -156,7 +172,9 @@ void blo_write_id_struct(BlendWriter *writer,
#define BLO_write_id_struct(writer, struct_name, id_address, id) \
blo_write_id_struct(writer, BLO_get_struct_id(writer, struct_name), id_address, id)
-/* Write raw data. */
+/**
+ * Write raw data.
+ */
void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr);
void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr);
void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr);
@@ -164,13 +182,23 @@ void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr)
void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr);
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr);
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr);
+/**
+ * Write a null terminated string.
+ */
void BLO_write_string(BlendWriter *writer, const char *data_ptr);
/* Misc. */
+
+/**
+ * Sometimes different data is written depending on whether the file is saved to disk or used for
+ * undo. This function returns true when the current file-writing is done for undo.
+ */
bool BLO_write_is_undo(BlendWriter *writer);
-/* Blend Read Data API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Read Data API
*
* Generally, for every BLO_write_* call there should be a corresponding BLO_read_* call.
*
@@ -181,15 +209,18 @@ bool BLO_write_is_undo(BlendWriter *writer);
* updated to be NULL. When it was pointing to NULL before, it will stay that way.
*
* Examples of matching calls:
- * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
- * BLO_read_data_address(reader, &clmd->sim_parms);
*
- * BLO_write_struct_list(writer, TimeMarker, &action->markers);
- * BLO_read_list(reader, &action->markers);
+ * \code{.c}
+ * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
+ * BLO_read_data_address(reader, &clmd->sim_parms);
*
- * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar);
- * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar);
- */
+ * BLO_write_struct_list(writer, TimeMarker, &action->markers);
+ * BLO_read_list(reader, &action->markers);
+ *
+ * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar);
+ * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar);
+ * \endcode
+ * \{ */
void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address);
void *BLO_read_get_new_data_address_no_us(BlendDataReader *reader, const void *old_address);
@@ -201,10 +232,16 @@ void *BLO_read_get_new_packed_address(BlendDataReader *reader, const void *old_a
*((void **)ptr_p) = BLO_read_get_new_packed_address((reader), *(ptr_p))
typedef void (*BlendReadListFn)(BlendDataReader *reader, void *data);
+/**
+ * Updates all ->prev and ->next pointers of the list elements.
+ * Updates the list->first and list->last pointers.
+ * When not NULL, calls the callback on every element.
+ */
void BLO_read_list_cb(BlendDataReader *reader, struct ListBase *list, BlendReadListFn callback);
void BLO_read_list(BlendDataReader *reader, struct ListBase *list);
/* Update data pointers and correct byte-order if necessary. */
+
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p);
void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p);
void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p);
@@ -213,18 +250,21 @@ void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr
void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p);
/* Misc. */
+
bool BLO_read_requires_endian_switch(BlendDataReader *reader);
bool BLO_read_data_is_undo(BlendDataReader *reader);
void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr);
void BLO_read_glob_list(BlendDataReader *reader, struct ListBase *list);
struct BlendFileReadReport *BLO_read_data_reports(BlendDataReader *reader);
-/* Blend Read Lib API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Read Lib API
*
- * This API does almost the same as the Blend Read Data API. However, now only pointers to ID data
- * blocks are updated.
- */
+ * This API does almost the same as the Blend Read Data API.
+ * However, now only pointers to ID data blocks are updated.
+ * \{ */
ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, struct ID *id);
@@ -232,30 +272,44 @@ ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, str
*((void **)id_ptr_p) = (void *)BLO_read_get_new_id_address((reader), (lib), (ID *)*(id_ptr_p))
/* Misc. */
+
bool BLO_read_lib_is_undo(BlendLibReader *reader);
struct Main *BLO_read_lib_get_main(BlendLibReader *reader);
struct BlendFileReadReport *BLO_read_lib_reports(BlendLibReader *reader);
-/* Blend Expand API
- * ===================
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Expand API
*
* BLO_expand has to be called for every data block that should be loaded. If the data block is in
- * a separate .blend file, it will be pulled from there.
- */
+ * a separate `.blend` file, it will be pulled from there.
+ * \{ */
void BLO_expand_id(BlendExpander *expander, struct ID *id);
#define BLO_expand(expander, id) BLO_expand_id(expander, (struct ID *)id)
-/* Report API
- * ===================
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Report API
+ * \{ */
+/**
+ * This function ensures that reports are printed,
+ * in the case of library linking errors this is important!
+ *
+ * bit kludge but better than doubling up on prints,
+ * we could alternatively have a versions of a report function which forces printing - campbell
+ */
void BLO_reportf_wrap(struct BlendFileReadReport *reports,
eReportType type,
const char *format,
...) ATTR_PRINTF_FORMAT(3, 4);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 22182edd070..567886e4d54 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -74,7 +74,7 @@ typedef struct BlendFileData {
int fileflags;
int globalf;
- char filename[1024]; /* 1024 = FILE_MAX */
+ char filepath[1024]; /* 1024 = FILE_MAX */
struct bScreen *curscreen; /* TODO: think this isn't needed anymore? */
struct Scene *curscene;
@@ -144,19 +144,50 @@ typedef enum eBLOReadSkip {
} eBLOReadSkip;
#define BLO_READ_SKIP_ALL (BLO_READ_SKIP_USERDEF | BLO_READ_SKIP_DATA)
+/**
+ * Open a blender file from a pathname. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param filepath: The path of the file to open.
+ * \param reports: If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
struct BlendFileReadReport *reports);
+/**
+ * Open a blender file from memory. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param mem: The file data.
+ * \param memsize: The length of \a mem.
+ * \param reports: If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_memory(const void *mem,
int memsize,
eBLOReadSkip skip_flags,
struct ReportList *reports);
+/**
+ * Used for undo/redo, skips part of libraries reading
+ * (assuming their data are already loaded & valid).
+ *
+ * \param oldmain: old main,
+ * from which we will keep libraries and other data-blocks that should not have changed.
+ * \param filename: current file, only for retrieving library data.
+ */
BlendFileData *BLO_read_from_memfile(struct Main *oldmain,
const char *filename,
struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct ReportList *reports);
+/**
+ * Frees a BlendFileData structure and *all* the data associated with it
+ * (the userdef data, and the main libblock data).
+ *
+ * \param bfd: The structure to free.
+ */
void BLO_blendfiledata_free(BlendFileData *bfd);
/** \} */
@@ -170,24 +201,89 @@ typedef struct BLODataBlockInfo {
struct AssetMetaData *asset_data;
} BLODataBlockInfo;
+/**
+ * Open a blendhandle from a file path.
+ *
+ * \param filepath: The file path to open.
+ * \param reports: Report errors in opening the file (can be NULL).
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct BlendFileReadReport *reports);
+/**
+ * Open a blendhandle from memory.
+ *
+ * \param mem: The data to load from.
+ * \param memsize: The size of the data.
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_memory(const void *mem,
int memsize,
struct BlendFileReadReport *reports);
+/**
+ * Gets the names of all the data-blocks in a file of a certain type
+ * (e.g. all the scene names in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param use_assets_only: Only list IDs marked as assets.
+ * \param r_tot_names: The length of the returned list.
+ * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
+ */
struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
int ofblocktype,
const bool use_assets_only,
int *r_tot_names);
+/**
+ * Gets the names and asset-data (if ID is an asset) of data-blocks in a file of a certain type.
+ * The data-blocks can be limited to assets.
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param use_assets_only: Limit the result to assets only.
+ * \param r_tot_info_items: The length of the returned list.
+ * \return A BLI_linklist of `BLODataBlockInfo *`.
+ * The links and #BLODataBlockInfo.asset_data should be freed with MEM_freeN.
+ */
struct LinkNode * /*BLODataBlockInfo */ BLO_blendhandle_get_datablock_info(
BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_info_items);
+/**
+ * Gets the previews of all the data-blocks in a file of a certain type
+ * (e.g. all the scene previews in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param r_tot_prev: The length of the returned list.
+ * \return A BLI_linklist of #PreviewImage. The #PreviewImage links should be freed with malloc.
+ */
struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev);
+/**
+ * Get the PreviewImage of a single data block in a file.
+ * (e.g. all the scene previews in a file).
+ *
+ * \param bh: The blendhandle to access.
+ * \param ofblocktype: The type of names to get.
+ * \param name: Name of the block without the ID_ prefix, to read the preview image from.
+ * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned
+ */
struct PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
int ofblocktype,
const char *name);
+/**
+ * Gets the names of all the linkable data-block types available in a file.
+ * (e.g. "Scene", "Mesh", "Light", etc.).
+ *
+ * \param bh: The blendhandle to access.
+ * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
+ */
struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh);
+/**
+ * Close and free a blendhandle. The handle becomes invalid after this call.
+ *
+ * \param bh: The handle to close.
+ */
void BLO_blendhandle_close(BlendHandle *bh);
/** \} */
@@ -195,7 +291,25 @@ void BLO_blendhandle_close(BlendHandle *bh);
#define BLO_GROUP_MAX 32
#define BLO_EMBEDDED_STARTUP_BLEND "<startup.blend>"
+/**
+ * Check whether given path ends with a blend file compatible extension
+ * (`.blend`, `.ble` or `.blend.gz`).
+ *
+ * \param str: The path to check.
+ * \return true is this path ends with a blender file extension.
+ */
bool BLO_has_bfile_extension(const char *str);
+/**
+ * Try to explode given path into its 'library components'
+ * (i.e. a .blend file, id type/group, and data-block itself).
+ *
+ * \param path: the full path to explode.
+ * \param r_dir: the string that'll contain path up to blend file itself ('library' path).
+ * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
+ * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL.
+ * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL.
+ * \return true if path contains a blend file.
+ */
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name);
/* -------------------------------------------------------------------- */
@@ -212,14 +326,6 @@ typedef enum eBLOLibLinkFlags {
BLO_LIBLINK_USE_PLACEHOLDERS = 1 << 16,
/** Force loaded ID to be tagged as #LIB_TAG_INDIRECT (used in reload context only). */
BLO_LIBLINK_FORCE_INDIRECT = 1 << 17,
- /**
- * When set, tag ID types that pass the internal check #library_link_idcode_needs_tag_check
- *
- * Currently this is only used to instantiate objects in the scene.
- * Set this from #BLO_library_link_params_init_with_context so callers
- * don't need to remember to set this flag.
- */
- BLO_LIBLINK_NEEDS_ID_TAG_DOIT = 1 << 18,
/** Set fake user on appended IDs. */
BLO_LIBLINK_APPEND_SET_FAKEUSER = 1 << 19,
/** Append (make local) also indirect dependencies of appended IDs coming from other libraries.
@@ -241,7 +347,7 @@ typedef enum eBLOLibLinkFlags {
* #BLO_library_link_begin, #BLO_library_link_named_part & #BLO_library_link_end.
* Wrap these in parameters since it's important both functions receive matching values.
*/
-struct LibraryLink_Params {
+typedef struct LibraryLink_Params {
/** The current main database, e.g. #G_MAIN or `CTX_data_main(C)`. */
struct Main *bmain;
/** Options for linking, used for instantiating. */
@@ -257,7 +363,7 @@ struct LibraryLink_Params {
/** The active 3D viewport (only used to define local-view). */
const struct View3D *v3d;
} context;
-};
+} LibraryLink_Params;
void BLO_library_link_params_init(struct LibraryLink_Params *params,
struct Main *bmain,
@@ -271,20 +377,45 @@ void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params
struct ViewLayer *view_layer,
const struct View3D *v3d);
+/**
+ * Initialize the #BlendHandle for linking library data.
+ *
+ * \param bh: A blender file handle as returned by
+ * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory.
+ * \param filepath: Used for relative linking, copied to the `lib->filepath`.
+ * \param params: Settings for linking that don't change from beginning to end of linking.
+ * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl.
+ */
struct Main *BLO_library_link_begin(BlendHandle **bh,
const char *filepath,
const struct LibraryLink_Params *params);
+/**
+ * Link a named data-block from an external blend file.
+ *
+ * \param mainl: The main database to link from (not the active one).
+ * \param bh: The blender file handle.
+ * \param idcode: The kind of data-block to link.
+ * \param name: The name of the data-block (without the 2 char ID prefix).
+ * \return the linked ID when found.
+ */
struct ID *BLO_library_link_named_part(struct Main *mainl,
BlendHandle **bh,
const short idcode,
const char *name,
const struct LibraryLink_Params *params);
+/**
+ * Finalize linking from a given .blend file (library).
+ * Optionally instance the indirect object/collection in the scene when the flags are set.
+ * \note Do not use \a bh after calling this function, it may frees it.
+ *
+ * \param mainl: The main database to link from (not the active one).
+ * \param bh: The blender file handle (WARNING! may be freed by this function!).
+ * \param params: Settings for linking that don't change from beginning to end of linking.
+ */
void BLO_library_link_end(struct Main *mainl,
BlendHandle **bh,
const struct LibraryLink_Params *params);
-int BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh, const uint64_t id_types_mask);
-
/**
* Struct for temporarily loading datablocks from a blend file.
*/
@@ -314,6 +445,10 @@ void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx);
void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname);
/* internal function but we need to expose it */
+/**
+ * Used to link a file (without UI) to the current UI.
+ * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
+ */
void blo_lib_link_restore(struct Main *oldmain,
struct Main *newmain,
struct wmWindowManager *curwm,
@@ -322,29 +457,50 @@ void blo_lib_link_restore(struct Main *oldmain,
typedef void (*BLOExpandDoitCallback)(void *fdhandle, struct Main *mainvar, void *idv);
+/**
+ * Set the callback func used over all ID data found by \a BLO_expand_main func.
+ *
+ * \param expand_doit_func: Called for each ID block it finds.
+ */
void BLO_main_expander(BLOExpandDoitCallback expand_doit_func);
+/**
+ * Loop over all ID data in Main to mark relations.
+ * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
+ *
+ * \param fdhandle: usually filedata, or own handle.
+ * \param mainvar: the Main database to expand.
+ */
void BLO_expand_main(void *fdhandle, struct Main *mainvar);
/**
* Update defaults in startup.blend, without having to save and embed it.
* \note defaults for preferences are stored in `userdef_default.c` and can be updated there.
*/
+/**
+ * Update defaults in startup.blend, without having to save and embed the file.
+ * This function can be emptied each time the startup.blend is updated.
+ *
+ * \note Screen data may be cleared at this point, this will happen in the case
+ * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled.
+ * Versioning the screen data can be safely skipped without "Load UI" since the screen data
+ * will have been versioned when it was first loaded.
+ */
void BLO_update_defaults_startup_blend(struct Main *bmain, const char *app_template);
void BLO_update_defaults_workspace(struct WorkSpace *workspace, const char *app_template);
/* Disable unwanted experimental feature settings on startup. */
void BLO_sanitize_experimental_features_userpref_blend(struct UserDef *userdef);
+/**
+ * Does a very light reading of given .blend file to extract its stored thumbnail.
+ *
+ * \param filepath: The path of the file to extract thumbnail from.
+ * \return The raw thumbnail
+ * (MEM-allocated, as stored in file, use #BKE_main_thumbnail_to_imbuf()
+ * to convert it to ImBuf image).
+ */
struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath);
-void BLO_object_instantiate_object_base_instance_init(struct Main *bmain,
- struct Collection *collection,
- struct Object *ob,
- struct ViewLayer *view_layer,
- const struct View3D *v3d,
- const int flag,
- bool set_active);
-
/* datafiles (generated theme) */
extern const struct bTheme U_theme_default;
extern const struct UserDef U_default;
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
index 4e240e2462b..0e2c22d7e4d 100644
--- a/source/blender/blenloader/BLO_undofile.h
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -77,7 +77,7 @@ typedef struct {
bool memchunk_identical;
} UndoReader;
-/* actually only used writefile.c */
+/* Actually only used `writefile.c`. */
void BLO_memfile_write_init(MemFileWriteData *mem_data,
MemFile *written_memfile,
@@ -87,14 +87,31 @@ void BLO_memfile_write_finalize(MemFileWriteData *mem_data);
void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, size_t size);
/* exports */
+
+/**
+ * Not memfile itself.
+ */
extern void BLO_memfile_free(MemFile *memfile);
+/**
+ * Result is that 'first' is being freed.
+ * to keep list of memfiles consistent, 'first' is always first in list.
+ */
extern void BLO_memfile_merge(MemFile *first, MemFile *second);
+/**
+ * Clear is_identical_future before adding next memfile.
+ */
extern void BLO_memfile_clear_future(MemFile *memfile);
-/* utilities */
+/* Utilities. */
+
extern struct Main *BLO_memfile_main_get(struct MemFile *memfile,
struct Main *bmain,
struct Scene **r_scene);
+/**
+ * Saves .blend using undo buffer.
+ *
+ * \return success.
+ */
extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename);
FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction);
diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h
index 746c663926d..9bc3714ff38 100644
--- a/source/blender/blenloader/BLO_writefile.h
+++ b/source/blender/blenloader/BLO_writefile.h
@@ -21,9 +21,13 @@
/** \file
* \ingroup blenloader
- * \brief external writefile function prototypes.
+ * \brief external `writefile.c` function prototypes.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BlendThumbnail;
struct Main;
struct MemFile;
@@ -60,15 +64,25 @@ struct BlendFileWriteParams {
const struct BlendThumbnail *thumb;
};
+/**
+ * \return Success.
+ */
extern bool BLO_write_file(struct Main *mainvar,
const char *filepath,
const int write_flags,
const struct BlendFileWriteParams *params,
struct ReportList *reports);
+/**
+ * \return Success.
+ */
extern bool BLO_write_file_mem(struct Main *mainvar,
struct MemFile *compare,
struct MemFile *current,
int write_flags);
/** \} */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index b3df5c8aa67..05f74bfa834 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -34,7 +34,6 @@ set(INC
../sequencer
../windowmanager
../../../intern/clog
- ../../../intern/ghost
../../../intern/guardedalloc
# for writefile.c: dna_type_offsets.h
@@ -114,6 +113,7 @@ if(WITH_GTESTS)
tests/blendfile_loading_base_test.h
)
set(TEST_INC
+ ../../../intern/ghost
)
set(TEST_LIB
bf_blenloader
diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c
index 7d641d976e3..333f6e341c6 100644
--- a/source/blender/blenloader/intern/blend_validate.c
+++ b/source/blender/blenloader/intern/blend_validate.c
@@ -47,10 +47,6 @@
#include "readfile.h"
-/**
- * Check (but do *not* fix) that all linked data-blocks are still valid
- * (i.e. pointing to the right library).
- */
bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
{
ListBase mainlist;
@@ -165,7 +161,6 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
return is_valid;
}
-/** Check (and fix if needed) that shape key's 'from' pointer is valid. */
bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports)
{
ListBase *lb;
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index c0fdfa86907..f3c92aec338 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -61,13 +61,6 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp);
/* Access routines used by filesel. */
-/**
- * Open a blendhandle from a file path.
- *
- * \param filepath: The file path to open.
- * \param reports: Report errors in opening the file (can be NULL).
- * \return A handle on success, or NULL on failure.
- */
BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
{
BlendHandle *bh;
@@ -77,13 +70,6 @@ BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport
return bh;
}
-/**
- * Open a blendhandle from memory.
- *
- * \param mem: The data to load from.
- * \param memsize: The size of the data.
- * \return A handle on success, or NULL on failure.
- */
BlendHandle *BLO_blendhandle_from_memory(const void *mem,
int memsize,
BlendFileReadReport *reports)
@@ -130,16 +116,6 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
fprintf(fp, "]\n");
}
-/**
- * Gets the names of all the data-blocks in a file of a certain type
- * (e.g. all the scene names in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param tot_names: The length of the returned list.
- * \param use_assets_only: Only list IDs marked as assets.
- * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
- */
LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
int ofblocktype,
const bool use_assets_only,
@@ -169,17 +145,6 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
return names;
}
-/**
- * Gets the names and asset-data (if ID is an asset) of data-blocks in a file of a certain type.
- * The data-blocks can be limited to assets.
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param use_assets_only: Limit the result to assets only.
- * \param tot_info_items: The length of the returned list.
- * \return A BLI_linklist of BLODataBlockInfo *. The links and #BLODataBlockInfo.asset_data should
- * be freed with MEM_freeN.
- */
LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh,
int ofblocktype,
const bool use_assets_only,
@@ -267,15 +232,6 @@ static BHead *blo_blendhandle_read_preview_rects(FileData *fd,
return bhead;
}
-/**
- * Get the PreviewImage of a single data block in a file.
- * (e.g. all the scene previews in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param name: Name of the block without the ID_ prefix, to read the preview image from.
- * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned
- */
PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
int ofblocktype,
const char *name)
@@ -315,15 +271,6 @@ PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
return NULL;
}
-/**
- * Gets the previews of all the data-blocks in a file of a certain type
- * (e.g. all the scene previews in a file).
- *
- * \param bh: The blendhandle to access.
- * \param ofblocktype: The type of names to get.
- * \param r_tot_prev: The length of the returned list.
- * \return A BLI_linklist of PreviewImage. The PreviewImage links should be freed with malloc.
- */
LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev)
{
FileData *fd = (FileData *)bh;
@@ -384,13 +331,6 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_
return previews;
}
-/**
- * Gets the names of all the linkable data-block types available in a file.
- * (e.g. "Scene", "Mesh", "Light", etc.).
- *
- * \param bh: The blendhandle to access.
- * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN().
- */
LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
{
FileData *fd = (FileData *)bh;
@@ -418,11 +358,6 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
return names;
}
-/**
- * Close and free a blendhandle. The handle becomes invalid after this call.
- *
- * \param bh: The handle to close.
- */
void BLO_blendhandle_close(BlendHandle *bh)
{
FileData *fd = (FileData *)bh;
@@ -432,14 +367,6 @@ void BLO_blendhandle_close(BlendHandle *bh)
/**********/
-/**
- * Open a blender file from a pathname. The function returns NULL
- * and sets a report in the list if it cannot open the file.
- *
- * \param filepath: The path of the file to open.
- * \param reports: If the return value is NULL, errors indicating the cause of the failure.
- * \return The data of the file.
- */
BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
BlendFileReadReport *reports)
@@ -457,15 +384,6 @@ BlendFileData *BLO_read_from_file(const char *filepath,
return bfd;
}
-/**
- * Open a blender file from memory. The function returns NULL
- * and sets a report in the list if it cannot open the file.
- *
- * \param mem: The file data.
- * \param memsize: The length of \a mem.
- * \param reports: If the return value is NULL, errors indicating the cause of the failure.
- * \return The data of the file.
- */
BlendFileData *BLO_read_from_memory(const void *mem,
int memsize,
eBLOReadSkip skip_flags,
@@ -485,14 +403,6 @@ BlendFileData *BLO_read_from_memory(const void *mem,
return bfd;
}
-/**
- * Used for undo/redo, skips part of libraries reading
- * (assuming their data are already loaded & valid).
- *
- * \param oldmain: old main,
- * from which we will keep libraries and other data-blocks that should not have changed.
- * \param filename: current file, only for retrieving library data.
- */
BlendFileData *BLO_read_from_memfile(Main *oldmain,
const char *filename,
MemFile *memfile,
@@ -548,12 +458,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
return bfd;
}
-/**
- * Frees a BlendFileData structure and *all* the data associated with it
- * (the userdef data, and the main libblock data).
- *
- * \param bfd: The structure to free.
- */
void BLO_blendfiledata_free(BlendFileData *bfd)
{
if (bfd->main) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index e4fe3e8da00..56047bb7f4f 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -195,7 +195,6 @@ static void read_libraries(FileData *basefd, ListBase *mainlist);
static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
-static bool library_link_idcode_needs_tag_check(const short idcode, const int flag);
typedef struct BHeadN {
struct BHeadN *next, *prev;
@@ -215,13 +214,6 @@ typedef struct BHeadN {
* because ID names are used in lookup tables. */
#define BHEAD_USE_READ_ON_DEMAND(bhead) ((bhead)->code == DATA)
-/**
- * This function ensures that reports are printed,
- * in the case of library linking errors this is important!
- *
- * bit kludge but better than doubling up on prints,
- * we could alternatively have a versions of a report function which forces printing - campbell
- */
void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format, ...)
{
char fixed_buf[1024]; /* should be long enough */
@@ -639,7 +631,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
// printf("blo_find_main: converted to %s\n", name1);
for (m = mainlist->first; m; m = m->next) {
- const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->name;
+ const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->filepath;
if (BLI_path_cmp(name1, libname) == 0) {
if (G.debug & G_DEBUG) {
@@ -998,13 +990,11 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock)
}
#endif /* USE_BHEAD_READ_ON_DEMAND */
-/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead)
{
return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset);
}
-/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */
AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead)
{
BLI_assert(blo_bhead_is_id_valid_type(bhead));
@@ -1149,6 +1139,10 @@ static int *read_file_thumbnail(FileData *fd)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name File Data API
+ * \{ */
+
static FileData *filedata_new(BlendFileReadReport *reports)
{
BLI_assert(reports != NULL);
@@ -1270,8 +1264,6 @@ static FileData *blo_filedata_from_file_open(const char *filepath, BlendFileRead
return blo_filedata_from_file_descriptor(filepath, reports, file);
}
-/* cannot be called with relative paths anymore! */
-/* on each new library added, it now checks for the current FileData and expands relativeness */
FileData *blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports)
{
FileData *fd = blo_filedata_from_file_open(filepath, reports);
@@ -1412,30 +1404,12 @@ void blo_filedata_free(FileData *fd)
/** \name Public Utilities
* \{ */
-/**
- * Check whether given path ends with a blend file compatible extension
- * (`.blend`, `.ble` or `.blend.gz`).
- *
- * \param str: The path to check.
- * \return true is this path ends with a blender file extension.
- */
bool BLO_has_bfile_extension(const char *str)
{
const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL};
return BLI_path_extension_check_array(str, ext_test);
}
-/**
- * Try to explode given path into its 'library components'
- * (i.e. a .blend file, id type/group, and data-block itself).
- *
- * \param path: the full path to explode.
- * \param r_dir: the string that'll contain path up to blend file itself ('library' path).
- * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
- * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL.
- * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL.
- * \return true if path contains a blend file.
- */
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
{
/* We might get some data names with slashes,
@@ -1496,14 +1470,6 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha
return true;
}
-/**
- * Does a very light reading of given .blend file to extract its stored thumbnail.
- *
- * \param filepath: The path of the file to extract thumbnail from.
- * \return The raw thumbnail
- * (MEM-allocated, as stored in file, use #BKE_main_thumbnail_to_imbuf()
- * to convert it to ImBuf image).
- */
BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
{
FileData *fd;
@@ -1552,7 +1518,6 @@ static void *newdataadr_no_us(FileData *fd, const void *adr)
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
}
-/* Direct datablocks with global linking. */
void *blo_read_get_new_globaldata_address(FileData *fd, const void *adr)
{
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
@@ -1574,7 +1539,6 @@ static void *newlibadr(FileData *fd, const void *lib, const void *adr)
return oldnewmap_liblookup(fd->libmap, adr, lib);
}
-/* only lib data */
void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr)
{
return newlibadr(fd, lib, adr);
@@ -1616,12 +1580,6 @@ static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist,
}
}
-/* lib linked proxy objects point to our local data, we need
- * to clear that pointer before reading the undo memfile since
- * the object might be removed, it is set again in reading
- * if the local object still exists.
- * This is only valid for local proxy objects though, linked ones should not be affected here.
- */
void blo_clear_proxy_pointers_from_lib(Main *oldmain)
{
LISTBASE_FOREACH (Object *, ob, &oldmain->objects) {
@@ -1681,8 +1639,6 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
}
}
-/* set old main packed data to zero if it has been restored */
-/* this works because freeing old main only happens after this call */
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
{
OldNew *entry = fd->packedmap->entries;
@@ -1719,7 +1675,6 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
}
}
-/* undo file support: add all library pointers in lookup */
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -1736,8 +1691,6 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
fd->old_mainlist = old_mainlist;
}
-/* Build a GSet of old main (we only care about local data here, so we can do that after
- * split_main() call. */
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
{
if (fd->old_idmap != NULL) {
@@ -2771,10 +2724,6 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
}
}
-/**
- * Used to link a file (without UI) to the current UI.
- * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
- */
void blo_lib_link_restore(Main *oldmain,
Main *newmain,
wmWindowManager *curwm,
@@ -2903,7 +2852,7 @@ static void lib_link_library(BlendLibReader *UNUSED(reader), Library *UNUSED(lib
* in relation to the blend file. */
static void fix_relpaths_library(const char *basepath, Main *main)
{
- /* BLO_read_from_memory uses a blank filename */
+ /* #BLO_read_from_memory uses a blank file-path. */
if (basepath == NULL || basepath[0] == '\0') {
LISTBASE_FOREACH (Library *, lib, &main->libraries) {
/* when loading a linked lib into a file which has not been saved,
@@ -3557,25 +3506,25 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
bfd->fileflags = fg->fileflags;
bfd->globalf = fg->globalf;
- BLI_strncpy(bfd->filename, fg->filename, sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, fg->filepath);
- /* Error in 2.65 and older: main->name was not set if you save from startup
+ /* Error in 2.65 and older: `main->filepath` was not set if you save from startup
* (not after loading file). */
- if (bfd->filename[0] == 0) {
+ if (bfd->filepath[0] == 0) {
if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1)) {
if ((G.fileflags & G_FILE_RECOVER_READ) == 0) {
- BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, BKE_main_blendfile_path(bfd->main));
}
}
- /* early 2.50 version patch - filename not in FileGlobal struct at all */
+ /* early 2.50 version patch - filepath not in FileGlobal struct at all */
if (fd->fileversion <= 250) {
- BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
+ STRNCPY(bfd->filepath, BKE_main_blendfile_path(bfd->main));
}
}
if (G.fileflags & G_FILE_RECOVER_READ) {
- BLI_strncpy(fd->relabase, fg->filename, sizeof(fd->relabase));
+ BLI_strncpy(fd->relabase, fg->filepath, sizeof(fd->relabase));
}
bfd->curscreen = fg->curscreen;
@@ -3671,7 +3620,7 @@ static void do_versions_after_linking(Main *main, ReportList *reports)
CLOG_INFO(&LOG,
2,
"Processing %s (%s), %d.%d",
- main->curlib ? main->curlib->filepath : main->name,
+ main->curlib ? main->curlib->filepath : main->filepath,
main->curlib ? "LIB" : "MAIN",
main->versionfile,
main->subversionfile);
@@ -3909,7 +3858,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) {
BLI_addtail(&mainlist, bfd->main);
fd->mainlist = &mainlist;
- BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name));
+ STRNCPY(bfd->main->filepath, filepath);
}
if (G.background) {
@@ -4384,23 +4333,11 @@ static void expand_id(BlendExpander *expander, ID *id)
expand_id_embedded_id(expander, id);
}
-/**
- * Set the callback func used over all ID data found by \a BLO_expand_main func.
- *
- * \param expand_doit_func: Called for each ID block it finds.
- */
void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
{
expand_doit = expand_doit_func;
}
-/**
- * Loop over all ID data in Main to mark relations.
- * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
- *
- * \param fdhandle: usually filedata, or own handle.
- * \param mainvar: the Main database to expand.
- */
void BLO_expand_main(void *fdhandle, Main *mainvar)
{
ListBase *lbarray[INDEX_ID_MAX];
@@ -4441,290 +4378,6 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
/** \name Library Linking (helper functions)
* \{ */
-static bool object_in_any_scene(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- if (BKE_scene_object_find(sce, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool object_in_any_collection(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- if (BKE_collection_has_object(collection, ob)) {
- return true;
- }
- }
-
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- if (scene->master_collection != NULL &&
- BKE_collection_has_object(scene->master_collection, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Shared operations to perform on the object's base after adding it to the scene.
- */
-static void object_base_instance_init(
- Object *ob, ViewLayer *view_layer, const View3D *v3d, const int flag, bool set_active)
-{
- Base *base = BKE_view_layer_base_find(view_layer, ob);
-
- if (v3d != NULL) {
- base->local_view_bits |= v3d->local_view_uuid;
- }
-
- if (flag & FILE_AUTOSELECT) {
- /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */
- BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK));
- if (base->flag & BASE_SELECTABLE) {
- base->flag |= BASE_SELECTED;
- }
- }
-
- if (set_active) {
- view_layer->basact = base;
- }
-
- BKE_scene_object_base_flag_sync_from_base(base);
-}
-
-/**
- * Exported for link/append to create objects as well.
- */
-void BLO_object_instantiate_object_base_instance_init(Main *bmain,
- Collection *collection,
- Object *ob,
- ViewLayer *view_layer,
- const View3D *v3d,
- const int flag,
- bool set_active)
-{
- /* Auto-select and appending. */
- if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) {
- /* While in general the object should not be manipulated,
- * when the user requests the object to be selected, ensure it's visible and selectable. */
- ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT);
- }
-
- BKE_collection_object_add(bmain, collection, ob);
-
- object_base_instance_init(ob, view_layer, v3d, flag, set_active);
-}
-
-static void add_loose_objects_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- Library *lib,
- const int flag)
-{
- Collection *active_collection = NULL;
- const bool do_append = (flag & FILE_LINK) == 0;
-
- BLI_assert(scene);
-
- /* Give all objects which are LIB_TAG_INDIRECT a base,
- * or for a collection when *lib has been set. */
- LISTBASE_FOREACH (Object *, ob, &mainvar->objects) {
- /* NOTE: Even if this is a directly linked object and is tagged for instantiation, it might
- * have already been instantiated through one of its owner collections, in which case we do not
- * want to re-instantiate it in the active collection here. */
- bool do_it = (ob->id.tag & LIB_TAG_DOIT) != 0 && !BKE_scene_object_find(scene, ob);
- if (do_it ||
- ((ob->id.tag & LIB_TAG_INDIRECT) != 0 && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0)) {
- if (do_append) {
- if (ob->id.us == 0) {
- do_it = true;
- }
- else if ((ob->id.lib == lib) && !object_in_any_collection(bmain, ob)) {
- /* When appending, make sure any indirectly loaded object gets a base,
- * when they are not part of any collection yet. */
- do_it = true;
- }
- }
-
- if (do_it) {
- /* Find or add collection as needed. */
- if (active_collection == NULL) {
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
- else {
- active_collection = BKE_collection_add(bmain, scene->master_collection, NULL);
- }
- }
-
- CLAMP_MIN(ob->id.us, 0);
- ob->mode = OB_MODE_OBJECT;
-
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- const bool set_active = false;
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, flag, set_active);
-
- ob->id.tag &= ~LIB_TAG_INDIRECT;
- ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
- ob->id.tag |= LIB_TAG_EXTERN;
- }
- }
- }
-}
-
-static void add_loose_object_data_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- const int flag)
-{
- if ((flag & BLO_LIBLINK_OBDATA_INSTANCE) == 0) {
- return;
- }
-
- Collection *active_collection = scene->master_collection;
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
-
- /* Do not re-instantiate obdata IDs that are already instantiated by an object. */
- LISTBASE_FOREACH (Object *, ob, &mainvar->objects) {
- if ((ob->id.tag & LIB_TAG_PRE_EXISTING) == 0 && ob->data != NULL) {
- ID *obdata = ob->data;
- BLI_assert(ID_REAL_USERS(obdata) > 0);
- if ((obdata->tag & LIB_TAG_PRE_EXISTING) == 0) {
- obdata->tag &= ~LIB_TAG_DOIT;
- }
- }
- }
-
- /* Loop over all ID types, instancing object-data for ID types that have support for it. */
- ListBase *lbarray[INDEX_ID_MAX];
- int i = set_listbasepointers(mainvar, lbarray);
- while (i--) {
- const short idcode = BKE_idtype_idcode_from_index(i);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
-
- LISTBASE_FOREACH (ID *, id, lbarray[i]) {
- if (id->tag & LIB_TAG_DOIT) {
- const int type = BKE_object_obdata_to_type(id);
- BLI_assert(type != -1);
- Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
- ob->data = id;
- id_us_plus(id);
- BKE_object_materials_test(bmain, ob, ob->data);
-
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- bool set_active = false;
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, flag, set_active);
-
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- }
- }
-}
-
-static void add_collections_to_scene(Main *mainvar,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d,
- Library *lib,
- const int flag)
-{
- Collection *active_collection = scene->master_collection;
- if (flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- active_collection = lc->collection;
- }
-
- /* Give all objects which are tagged a base. */
- LISTBASE_FOREACH (Collection *, collection, &mainvar->collections) {
- if ((flag & BLO_LIBLINK_COLLECTION_INSTANCE) && (collection->id.tag & LIB_TAG_DOIT)) {
- /* Any indirect collection should not have been tagged. */
- BLI_assert((collection->id.tag & LIB_TAG_INDIRECT) == 0);
-
- /* BKE_object_add(...) messes with the selection. */
- Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
- ob->type = OB_EMPTY;
- ob->empty_drawsize = U.collection_instance_empty_size;
-
- const bool set_selected = (flag & FILE_AUTOSELECT) != 0;
- /* TODO: why is it OK to make this active here but not in other situations?
- * See other callers of #object_base_instance_init */
- const bool set_active = set_selected;
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, flag, set_active);
-
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
-
- /* Assign the collection. */
- ob->instance_collection = collection;
- id_us_plus(&collection->id);
- ob->transflag |= OB_DUPLICOLLECTION;
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- /* We do not want to force instantiation of indirectly linked collections,
- * not even when appending. Users can now easily instantiate collections (and their objects)
- * as needed by themselves. See T67032. */
- else if ((collection->id.tag & LIB_TAG_INDIRECT) == 0) {
- bool do_add_collection = (collection->id.tag & LIB_TAG_DOIT) != 0;
- if (!do_add_collection) {
- /* We need to check that objects in that collections are already instantiated in a scene.
- * Otherwise, it's better to add the collection to the scene's active collection, than to
- * instantiate its objects in active scene's collection directly. See T61141.
- * Note that we only check object directly into that collection,
- * not recursively into its children.
- */
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- if ((ob->id.tag & (LIB_TAG_PRE_EXISTING | LIB_TAG_DOIT | LIB_TAG_INDIRECT)) == 0 &&
- (ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == false)) {
- do_add_collection = true;
- break;
- }
- }
- }
- if (do_add_collection) {
- /* Add collection as child of active collection. */
- BKE_collection_child_add(bmain, active_collection, collection);
-
- if (flag & FILE_AUTOSELECT) {
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base) {
- base->flag |= BASE_SELECTED;
- BKE_scene_object_base_flag_sync_from_base(base);
- }
- }
- }
-
- /* Those are kept for safety and consistency, but should not be needed anymore? */
- collection->id.tag &= ~LIB_TAG_INDIRECT;
- collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK;
- collection->id.tag |= LIB_TAG_EXTERN;
- }
- }
- }
-}
-
/* returns true if the item was found
* but it may already have already been appended/linked */
static ID *link_named_part(
@@ -4774,75 +4427,9 @@ static ID *link_named_part(
/* if we found the id but the id is NULL, this is really bad */
BLI_assert(!((bhead != NULL) && (id == NULL)));
- /* Tag as loose object (or data associated with objects)
- * needing to be instantiated in #LibraryLink_Params.scene. */
- if ((id != NULL) && (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) {
- if (library_link_idcode_needs_tag_check(idcode, flag)) {
- id->tag |= LIB_TAG_DOIT;
- }
- }
-
return id;
}
-/**
- * Simple reader for copy/paste buffers.
- */
-int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const uint64_t id_types_mask)
-{
- FileData *fd = (FileData *)(bh);
- BHead *bhead;
- int num_directly_linked = 0;
-
- for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
- ID *id = NULL;
-
- if (bhead->code == ENDB) {
- break;
- }
-
- if (blo_bhead_is_id_valid_type(bhead) && BKE_idtype_idcode_is_linkable((short)bhead->code) &&
- (id_types_mask == 0 ||
- (BKE_idtype_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) {
- read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_EXTERN, false, &id);
- num_directly_linked++;
- }
-
- if (id) {
- /* sort by name in list */
- ListBase *lb = which_libbase(mainl, GS(id->name));
- id_sort_by_name(lb, id, NULL);
-
- /* Tag as loose object (or data associated with objects)
- * needing to be instantiated (see also #link_named_part and its usage of
- * #BLO_LIBLINK_NEEDS_ID_TAG_DOIT above). */
- if (library_link_idcode_needs_tag_check(GS(id->name), BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) {
- id->tag |= LIB_TAG_DOIT;
- }
-
- if (bhead->code == ID_OB) {
- /* Instead of instancing Base's directly, postpone until after collections are loaded
- * otherwise the base's flag is set incorrectly when collections are used */
- Object *ob = (Object *)id;
- ob->mode = OB_MODE_OBJECT;
- /* ensure add_loose_objects_to_scene runs on this object */
- BLI_assert(id->us == 0);
- }
- }
- }
-
- return num_directly_linked;
-}
-
-/**
- * Link a named data-block from an external blend file.
- *
- * \param mainl: The main database to link from (not the active one).
- * \param bh: The blender file handle.
- * \param idcode: The kind of data-block to link.
- * \param name: The name of the data-block (without the 2 char ID prefix).
- * \return the linked ID when found.
- */
ID *BLO_library_link_named_part(Main *mainl,
BlendHandle **bh,
const short idcode,
@@ -4855,41 +4442,10 @@ ID *BLO_library_link_named_part(Main *mainl,
/* common routine to append/link something from a library */
-/**
- * Checks if the \a idcode needs to be tagged with #LIB_TAG_DOIT when linking/appending.
- */
-static bool library_link_idcode_needs_tag_check(const short idcode, const int flag)
-{
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Always true because of #add_loose_objects_to_scene & #add_collections_to_scene. */
- if (ELEM(idcode, ID_OB, ID_GR)) {
- return true;
- }
- if (flag & BLO_LIBLINK_OBDATA_INSTANCE) {
- if (OB_DATA_SUPPORT_ID(idcode)) {
- return true;
- }
- }
- }
- return false;
-}
-
-/**
- * Clears #LIB_TAG_DOIT based on the result of #library_link_idcode_needs_tag_check.
- */
-static void library_link_clear_tag(Main *mainvar, const int flag)
-{
- for (int i = 0; i < INDEX_ID_MAX; i++) {
- const short idcode = BKE_idtype_idcode_from_index(i);
- BLI_assert(idcode != -1);
- if (library_link_idcode_needs_tag_check(idcode, flag)) {
- BKE_main_id_tag_idcode(mainvar, idcode, LIB_TAG_DOIT, false);
- }
- }
-}
-
-static Main *library_link_begin(
- Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra)
+static Main *library_link_begin(Main *mainvar,
+ FileData **fd,
+ const char *filepath,
+ const int id_tag_extra)
{
Main *mainl;
@@ -4902,11 +4458,6 @@ static Main *library_link_begin(
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Clear for objects and collections instantiating tag. */
- library_link_clear_tag(mainvar, flag);
- }
-
/* make mains */
blo_split_main((*fd)->mainlist, mainvar);
@@ -4945,30 +4496,18 @@ void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params
{
BLO_library_link_params_init(params, bmain, flag, id_tag_extra);
if (scene != NULL) {
- /* Tagging is needed for instancing. */
- params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
-
params->context.scene = scene;
params->context.view_layer = view_layer;
params->context.v3d = v3d;
}
}
-/**
- * Initialize the #BlendHandle for linking library data.
- *
- * \param bh: A blender file handle as returned by
- * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory.
- * \param filepath: Used for relative linking, copied to the `lib->filepath`.
- * \param params: Settings for linking that don't change from beginning to end of linking.
- * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl.
- */
Main *BLO_library_link_begin(BlendHandle **bh,
const char *filepath,
const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra);
+ return library_link_begin(params->bmain, &fd, filepath, params->id_tag_extra);
}
static void split_main_newid(Main *mainptr, Main *main_newid)
@@ -4976,7 +4515,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
/* We only copy the necessary subset of data in this temp main. */
main_newid->versionfile = mainptr->versionfile;
main_newid->subversionfile = mainptr->subversionfile;
- BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name));
+ STRNCPY(main_newid->filepath, mainptr->filepath);
main_newid->curlib = mainptr->curlib;
ListBase *lbarray[INDEX_ID_MAX];
@@ -4995,19 +4534,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
}
}
-/**
- * \param scene: The scene in which to instantiate objects/collections
- * (if NULL, no instantiation is done).
- * \param v3d: The active 3D viewport.
- * (only to define active layers for instantiated objects & collections, can be NULL).
- */
-static void library_link_end(Main *mainl,
- FileData **fd,
- Main *bmain,
- const int flag,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
+static void library_link_end(Main *mainl, FileData **fd, const int flag)
{
Main *mainvar;
Library *curlib;
@@ -5092,22 +4619,6 @@ static void library_link_end(Main *mainl,
/* Make all relative paths, relative to the open blend file. */
fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar);
- /* Give a base to loose objects and collections.
- * Only directly linked objects & collections are instantiated by
- * #BLO_library_link_named_part & co,
- * here we handle indirect ones and other possible edge-cases. */
- if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) {
- /* Should always be true. */
- if (scene != NULL) {
- add_collections_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
- add_loose_objects_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag);
- add_loose_object_data_to_scene(mainvar, bmain, scene, view_layer, v3d, flag);
- }
-
- /* Clear objects and collections instantiating tag. */
- library_link_clear_tag(mainvar, flag);
- }
-
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
blo_filedata_free(*fd);
@@ -5115,25 +4626,10 @@ static void library_link_end(Main *mainl,
}
}
-/**
- * Finalize linking from a given .blend file (library).
- * Optionally instance the indirect object/collection in the scene when the flags are set.
- * \note Do not use \a bh after calling this function, it may frees it.
- *
- * \param mainl: The main database to link from (not the active one).
- * \param bh: The blender file handle (WARNING! may be freed by this function!).
- * \param params: Settings for linking that don't change from beginning to end of linking.
- */
void BLO_library_link_end(Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params)
{
FileData *fd = (FileData *)(*bh);
- library_link_end(mainl,
- &fd,
- params->bmain,
- params->flag,
- params->context.scene,
- params->context.view_layer,
- params->context.v3d);
+ library_link_end(mainl, &fd, params->flag);
*bh = (BlendHandle *)fd;
}
@@ -5485,11 +4981,6 @@ bool BLO_read_requires_endian_switch(BlendDataReader *reader)
return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
}
-/**
- * Updates all ->prev and ->next pointers of the list elements.
- * Updates the list->first and list->last pointers.
- * When not NULL, calls the callback on every element.
- */
void BLO_read_list_cb(BlendDataReader *reader, ListBase *list, BlendReadListFn callback)
{
if (BLI_listbase_is_empty(list)) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 75152a05063..3b5be3dd013 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -131,6 +131,11 @@ void blo_split_main(ListBase *mainlist, struct Main *main);
BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath);
+/**
+ * On each new library added, it now checks for the current #FileData and expands relativeness
+ *
+ * cannot be called with relative paths anymore!
+ */
FileData *blo_filedata_from_file(const char *filepath, struct BlendFileReadReport *reports);
FileData *blo_filedata_from_memory(const void *mem,
int memsize,
@@ -139,10 +144,28 @@ FileData *blo_filedata_from_memfile(struct MemFile *memfile,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports);
+/**
+ * Lib linked proxy objects point to our local data, we need
+ * to clear that pointer before reading the undo memfile since
+ * the object might be removed, it is set again in reading
+ * if the local object still exists.
+ * This is only valid for local proxy objects though, linked ones should not be affected here.
+ */
void blo_clear_proxy_pointers_from_lib(struct Main *oldmain);
void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain);
+/**
+ * Set old main packed data to zero if it has been restored
+ * this works because freeing old main only happens after this call.
+ */
void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain);
+/**
+ * Undo file support: add all library pointers in lookup.
+ */
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd);
+/**
+ * Build a #GSet of old main (we only care about local data here,
+ * so we can do that after #blo_split_main() call.
+ */
void blo_make_old_idmap_from_main(FileData *fd, struct Main *bmain);
BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, struct AssetMetaData **r_asset_data);
@@ -157,23 +180,48 @@ BHead *blo_bhead_first(FileData *fd);
BHead *blo_bhead_next(FileData *fd, BHead *thisblock);
BHead *blo_bhead_prev(FileData *fd, BHead *thisblock);
+/**
+ * Warning! Caller's responsibility to ensure given bhead **is** an ID one!
+ */
const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead);
+/**
+ * Warning! Caller's responsibility to ensure given bhead **is** an ID one!
+ */
struct AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead);
/* do versions stuff */
+/**
+ * Manipulates SDNA before calling #DNA_struct_get_compareflags,
+ * allowing us to rename structs and struct members.
+ *
+ * - This means older versions of Blender won't have access to this data **USE WITH CARE**.
+ * - These changes are applied on file load (run-time), similar to versioning for compatibility.
+ *
+ * \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT.
+ */
void blo_do_versions_dna(struct SDNA *sdna, const int versionfile, const int subversionfile);
void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm,
const void *oldaddr,
void *newaddr,
int nr);
+/**
+ * Only library data.
+ */
void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr);
void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr);
+/**
+ * \note this version patch is intended for versions < 2.52.2,
+ * but was initially introduced in 2.27 already.
+ */
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
void blo_do_versions_key_uidgen(struct Key *key);
+/**
+ * Patching #UserDef struct and Themes.
+ */
void blo_do_versions_userdef(struct UserDef *userdef);
void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *bmain);
@@ -193,6 +241,10 @@ void do_versions_after_linking_290(struct Main *bmain, struct ReportList *report
void do_versions_after_linking_300(struct Main *bmain, struct ReportList *reports);
void do_versions_after_linking_cycles(struct Main *bmain);
-/* This is rather unfortunate to have to expose this here, but better use that nasty hack in
- * do_version than readfile itself. */
+/**
+ * Direct data-blocks with global linking.
+ *
+ * \note This is rather unfortunate to have to expose this here,
+ * but better use that nasty hack in do_version than readfile itself.
+ */
void *blo_read_get_new_globaldata_address(struct FileData *fd, const void *adr);
diff --git a/source/blender/blenloader/intern/readfile_tempload.c b/source/blender/blenloader/intern/readfile_tempload.c
index 1b1cbb29ef5..311732adf99 100644
--- a/source/blender/blenloader/intern/readfile_tempload.c
+++ b/source/blender/blenloader/intern/readfile_tempload.c
@@ -39,7 +39,7 @@ TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
temp_lib_ctx->bf_reports.reports = reports;
/* Copy the file path so any path remapping is performed properly. */
- STRNCPY(temp_lib_ctx->bmain_base->name, real_main->name);
+ STRNCPY(temp_lib_ctx->bmain_base->filepath, real_main->filepath);
temp_lib_ctx->blendhandle = BLO_blendhandle_from_file(blend_file_path,
&temp_lib_ctx->bf_reports);
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index 62072cf7df5..dfa6135dac9 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -55,7 +55,6 @@
/* **************** support for memory-write, for undo buffers *************** */
-/* not memfile itself */
void BLO_memfile_free(MemFile *memfile)
{
MemFileChunk *chunk;
@@ -69,8 +68,6 @@ void BLO_memfile_free(MemFile *memfile)
memfile->size = 0;
}
-/* to keep list of memfiles consistent, 'first' is always first in list */
-/* result is that 'first' is being freed */
void BLO_memfile_merge(MemFile *first, MemFile *second)
{
/* We use this mapping to store the memory buffers from second memfile chunks which are not owned
@@ -106,7 +103,6 @@ void BLO_memfile_merge(MemFile *first, MemFile *second)
BLO_memfile_free(first);
}
-/* Clear is_identical_future before adding next memfile. */
void BLO_memfile_clear_future(MemFile *memfile)
{
LISTBASE_FOREACH (MemFileChunk *, chunk, &memfile->chunks) {
@@ -216,11 +212,6 @@ struct Main *BLO_memfile_main_get(struct MemFile *memfile,
return bmain_undo;
}
-/**
- * Saves .blend using undo buffer.
- *
- * \return success.
- */
bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename)
{
MemFileChunk *chunk;
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index c4d04392cba..8a22fd07c24 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -1892,7 +1892,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (cu = bmain->curves.first; cu; cu = cu->id.next) {
if (cu->flag & (CU_FRONT | CU_BACK)) {
- if (cu->ext1 != 0.0f || cu->ext2 != 0.0f) {
+ if (cu->extrude != 0.0f || cu->bevel_radius != 0.0f) {
Nurb *nu;
for (nu = cu->nurb.first; nu; nu = nu->next) {
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 125f3be0dd1..7a7f12a7e58 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -1321,13 +1321,16 @@ static void version_liboverride_rnacollections_insertion_object_constraints(
opop->subitem_local_name,
offsetof(bConstraint, name),
opop->subitem_local_index);
- if (constraint_anchor == NULL || constraint_anchor->next == NULL) {
+ bConstraint *constraint_src = constraint_anchor != NULL ? constraint_anchor->next :
+ constraints->first;
+
+ if (constraint_src == NULL) {
/* Invalid case, just remove that override property operation. */
- CLOG_ERROR(&LOG, "Could not find anchor or source constraints in stored override data");
+ CLOG_ERROR(&LOG, "Could not find source constraint in stored override data");
BKE_lib_override_library_property_operation_delete(op, opop);
continue;
}
- bConstraint *constraint_src = constraint_anchor->next;
+
opop->subitem_reference_name = opop->subitem_local_name;
opop->subitem_local_name = BLI_strdup(constraint_src->name);
opop->subitem_reference_index = opop->subitem_local_index;
@@ -1350,13 +1353,15 @@ static void version_liboverride_rnacollections_insertion_object(Object *object)
opop->subitem_local_name,
offsetof(ModifierData, name),
opop->subitem_local_index);
- if (mod_anchor == NULL || mod_anchor->next == NULL) {
+ ModifierData *mod_src = mod_anchor != NULL ? mod_anchor->next : object->modifiers.first;
+
+ if (mod_src == NULL) {
/* Invalid case, just remove that override property operation. */
- CLOG_ERROR(&LOG, "Could not find anchor or source modifiers in stored override data");
+ CLOG_ERROR(&LOG, "Could not find source modifier in stored override data");
BKE_lib_override_library_property_operation_delete(op, opop);
continue;
}
- ModifierData *mod_src = mod_anchor->next;
+
opop->subitem_reference_name = opop->subitem_local_name;
opop->subitem_local_name = BLI_strdup(mod_src->name);
opop->subitem_reference_index = opop->subitem_local_index;
@@ -1375,13 +1380,17 @@ static void version_liboverride_rnacollections_insertion_object(Object *object)
opop->subitem_local_name,
offsetof(GpencilModifierData, name),
opop->subitem_local_index);
- if (gp_mod_anchor == NULL || gp_mod_anchor->next == NULL) {
+ GpencilModifierData *gp_mod_src = gp_mod_anchor != NULL ?
+ gp_mod_anchor->next :
+ object->greasepencil_modifiers.first;
+
+ if (gp_mod_src == NULL) {
/* Invalid case, just remove that override property operation. */
- CLOG_ERROR(&LOG, "Could not find anchor GP modifier in stored override data");
+ CLOG_ERROR(&LOG, "Could not find source GP modifier in stored override data");
BKE_lib_override_library_property_operation_delete(op, opop);
continue;
}
- GpencilModifierData *gp_mod_src = gp_mod_anchor->next;
+
opop->subitem_reference_name = opop->subitem_local_name;
opop->subitem_local_name = BLI_strdup(gp_mod_src->name);
opop->subitem_reference_index = opop->subitem_local_index;
@@ -2182,7 +2191,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (ntree->type != NTREE_GEOMETRY) {
continue;
}
- version_node_id(ntree, FN_NODE_COMPARE_FLOATS, "FunctionNodeCompareFloats");
+ version_node_id(ntree, FN_NODE_COMPARE, "FunctionNodeCompareFloats");
version_node_id(ntree, GEO_NODE_CAPTURE_ATTRIBUTE, "GeometryNodeCaptureAttribute");
version_node_id(ntree, GEO_NODE_MESH_BOOLEAN, "GeometryNodeMeshBoolean");
version_node_id(ntree, GEO_NODE_FILL_CURVE, "GeometryNodeFillCurve");
@@ -2367,8 +2376,8 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Special case to handle older in-dev 3.1 files, before change from 3.0 branch gets merged in
- * master. */
+ /* Special case to handle older in-development 3.1 files, before change from 3.0 branch gets
+ * merged in master. */
if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) ||
(bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) {
/* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers,
@@ -2385,6 +2394,60 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_MAIN_ID_END;
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 4)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ version_node_id(ntree, GEO_NODE_CURVE_SPLINE_PARAMETER, "GeometryNodeSplineParameter");
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_CURVE_SPLINE_PARAMETER) {
+ version_node_add_socket_if_not_exist(
+ ntree, node, SOCK_OUT, SOCK_INT, PROP_NONE, "Index", "Index");
+ }
+
+ /* Convert float compare into a more general compare node. */
+ if (node->type == FN_NODE_COMPARE) {
+ if (node->storage == NULL) {
+ NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(
+ sizeof(NodeFunctionCompare), __func__);
+ data->data_type = SOCK_FLOAT;
+ data->operation = node->custom1;
+ strcpy(node->idname, "FunctionNodeCompare");
+ node->update = NODE_UPDATE;
+ node->storage = data;
+ }
+ }
+ }
+ }
+
+ /* Add a toggle for the breadcrumbs overlay in the node editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)space;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_PATH;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type != NTREE_GEOMETRY) {
+ continue;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type != GEO_NODE_REALIZE_INSTANCES) {
+ continue;
+ }
+ node->custom1 |= GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -2396,5 +2459,21 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Add node storage for map range node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MAP_RANGE) {
+ if (node->storage == NULL) {
+ NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
+ data->clamp = node->custom1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = node->custom2;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
index af765be619f..3deaaa040d6 100644
--- a/source/blender/blenloader/intern/versioning_common.cc
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -61,11 +61,6 @@ ARegion *do_versions_add_region_if_not_found(ListBase *regionbase,
return new_region;
}
-/**
- * Rename if the ID doesn't exist.
- *
- * \return the ID (if found).
- */
ID *do_versions_rename_id(Main *bmain,
const short id_type,
const char *name_src,
@@ -104,9 +99,6 @@ static void change_node_socket_name(ListBase *sockets, const char *old_name, con
}
}
-/**
- * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used.
- */
void version_node_socket_id_delim(bNodeSocket *socket)
{
StringRef name = socket->name;
@@ -165,9 +157,21 @@ void version_node_output_socket_name(bNodeTree *ntree,
}
}
-/**
- * Replace the ID name of all nodes in the tree with the given type with the new name.
- */
+bNodeSocket *version_node_add_socket_if_not_exist(bNodeTree *ntree,
+ bNode *node,
+ eNodeSocketInOut in_out,
+ int type,
+ int subtype,
+ const char *identifier,
+ const char *name)
+{
+ bNodeSocket *sock = nodeFindSocket(node, in_out, identifier);
+ if (sock != nullptr) {
+ return sock;
+ }
+ return nodeAddStaticSocket(ntree, node, in_out, type, subtype, identifier, name);
+}
+
void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -179,23 +183,6 @@ void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name
}
}
-/**
- * Adjust animation data for newly added node sockets.
- *
- * Node sockets are addressed by their index (in their RNA path, and thus FCurves/drivers), and
- * thus when a new node is added in the middle of the list, existing animation data needs to be
- * adjusted.
- *
- * Since this is about animation data, it only concerns input sockets.
- *
- * \param node_tree_type node tree type that has these nodes, for example NTREE_SHADER.
- * \param node_type node type to adjust, for example SH_NODE_BSDF_PRINCIPLED.
- * \param socket_index_orig the original index of the moved socket; when socket 4 moved to 6,
- * pass 4 here.
- * \param socket_index_offset the offset of the nodes, so when socket 4 moved to 6,
- * pass 2 here.
- * \param total_number_of_sockets the total number of sockets in the node.
- */
void version_node_socket_index_animdata(Main *bmain,
const int node_tree_type,
const int node_type,
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
index 7f179800ddd..0613484b754 100644
--- a/source/blender/blenloader/intern/versioning_common.h
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -34,6 +34,11 @@ struct ARegion *do_versions_add_region_if_not_found(struct ListBase *regionbase,
const char *name,
int link_after_region_type);
+/**
+ * Rename if the ID doesn't exist.
+ *
+ * \return the ID (if found).
+ */
ID *do_versions_rename_id(Main *bmain,
const short id_type,
const char *name_src,
@@ -52,6 +57,23 @@ void version_node_output_socket_name(struct bNodeTree *ntree,
const char *old_name,
const char *new_name);
+/**
+ * Adjust animation data for newly added node sockets.
+ *
+ * Node sockets are addressed by their index (in their RNA path, and thus FCurves/drivers), and
+ * thus when a new node is added in the middle of the list, existing animation data needs to be
+ * adjusted.
+ *
+ * Since this is about animation data, it only concerns input sockets.
+ *
+ * \param node_tree_type: Node tree type that has these nodes, for example #NTREE_SHADER.
+ * \param node_type: Node type to adjust, for example #SH_NODE_BSDF_PRINCIPLED.
+ * \param socket_index_orig: The original index of the moved socket; when socket 4 moved to 6,
+ * pass 4 here.
+ * \param socket_index_offset: The offset of the nodes, so when socket 4 moved to 6,
+ * pass 2 here.
+ * \param total_number_of_sockets: The total number of sockets in the node.
+ */
void version_node_socket_index_animdata(
Main *bmain,
int node_tree_type, /* NTREE_....., e.g. NTREE_SHADER */
@@ -60,10 +82,24 @@ void version_node_socket_index_animdata(
int socket_index_offset,
int total_number_of_sockets);
+/**
+ * Replace the ID name of all nodes in the tree with the given type with the new name.
+ */
void version_node_id(struct bNodeTree *ntree, const int node_type, const char *new_name);
+/**
+ * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used.
+ */
void version_node_socket_id_delim(bNodeSocket *socket);
+struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree,
+ struct bNode *node,
+ eNodeSocketInOut in_out,
+ int type,
+ int subtype,
+ const char *identifier,
+ const char *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index fa61b1ca6cd..a5c44ea711b 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -367,15 +367,6 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
}
}
-/**
- * Update defaults in startup.blend, without having to save and embed the file.
- * This function can be emptied each time the startup.blend is updated.
- *
- * \note Screen data may be cleared at this point, this will happen in the case
- * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled.
- * Versioning the screen data can be safely skipped without "Load UI" since the screen data
- * will have been versioned when it was first loaded.
- */
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* For all app templates. */
diff --git a/source/blender/blenloader/intern/versioning_dna.c b/source/blender/blenloader/intern/versioning_dna.c
index aee54b94833..0a97eedb993 100644
--- a/source/blender/blenloader/intern/versioning_dna.c
+++ b/source/blender/blenloader/intern/versioning_dna.c
@@ -29,16 +29,6 @@
#include "BLO_readfile.h"
#include "readfile.h"
-/**
- * Manipulates SDNA before calling #DNA_struct_get_compareflags,
- * allowing us to rename structs and struct members.
- *
- * - This means older versions of Blender won't have access to this data **USE WITH CARE**.
- *
- * - These changes are applied on file load (run-time), similar to versioning for compatibility.
- *
- * \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT.
- */
void blo_do_versions_dna(SDNA *sdna, const int versionfile, const int subversionfile)
{
#define DNA_VERSION_ATLEAST(ver, subver) \
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 37bf4898cb3..2fceb42262e 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -461,8 +461,6 @@ static void do_version_constraints_245(ListBase *lb)
}
}
-/* NOTE: this version patch is intended for versions < 2.52.2,
- * but was initially introduced in 2.27 already. */
void blo_do_version_old_trackto_to_constraints(Object *ob)
{
/* create new trackto constraint from the relationship */
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 0e5e0b76f43..3338d2f658c 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -399,7 +399,6 @@ static bool keymap_item_has_invalid_wm_context_data_path(wmKeyMapItem *kmi,
return false;
}
-/* patching UserDef struct and Themes */
void blo_do_versions_userdef(UserDef *userdef)
{
/* #UserDef & #Main happen to have the same struct member. */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 56ff7151cb1..aa3eef4b475 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -50,7 +50,7 @@
* Almost all data in Blender are structures. Each struct saved
* gets a BHead header. With BHead the struct can be linked again
* and compared with #StructDNA.
-
+ *
* WRITE
* =====
*
@@ -1028,7 +1028,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
/* prevent mem checkers from complaining */
memset(fg._pad, 0, sizeof(fg._pad));
- memset(fg.filename, 0, sizeof(fg.filename));
+ memset(fg.filepath, 0, sizeof(fg.filepath));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
fg._pad1 = NULL;
@@ -1045,7 +1045,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
fg.globalf = G.f;
/* Write information needed for recovery. */
if (fileflags & G_FILE_RECOVER_WRITE) {
- BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
+ STRNCPY(fg.filepath, mainvar->filepath);
}
sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION);
memcpy(fg.subvstr, subvstr, 4);
@@ -1312,15 +1312,15 @@ static bool do_history(const char *name, ReportList *reports)
/** \name File Writing (Public)
* \{ */
-/**
- * \return Success.
- */
bool BLO_write_file(Main *mainvar,
const char *filepath,
const int write_flags,
const struct BlendFileWriteParams *params,
ReportList *reports)
{
+ BLI_assert(!BLI_path_is_rel(filepath));
+ BLI_assert(BLI_path_is_abs_from_cwd(filepath));
+
char tempname[FILE_MAX + 1];
WriteWrap ww;
@@ -1329,10 +1329,12 @@ bool BLO_write_file(Main *mainvar,
const bool use_save_as_copy = params->use_save_as_copy;
const bool use_userdef = params->use_userdef;
const BlendThumbnail *thumb = params->thumb;
+ const bool relbase_valid = (mainvar->filepath[0] != '\0');
/* path backup/restore */
void *path_list_backup = NULL;
- const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+ const eBPathForeachFlag path_list_flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED |
+ BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk");
@@ -1351,35 +1353,47 @@ bool BLO_write_file(Main *mainvar,
return 0;
}
+ if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) {
+ /* Paths will already be absolute, no remapping to do. */
+ if (relbase_valid == false) {
+ remap_mode = BLO_WRITE_PATH_REMAP_NONE;
+ }
+ }
+
/* Remapping of relative paths to new file location. */
if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) {
if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
- /* Make all relative as none of the existing paths can be relative in an unsaved document.
- */
- if (G.relbase_valid == false) {
+ /* Make all relative as none of the existing paths can be relative in an unsaved document. */
+ if (relbase_valid == false) {
remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE_ALL;
}
}
+ /* The source path only makes sense to set if the file was saved (`relbase_valid`). */
char dir_src[FILE_MAX];
char dir_dst[FILE_MAX];
- BLI_split_dir_part(mainvar->name, dir_src, sizeof(dir_src));
- BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
- /* Just in case there is some subtle difference. */
- BLI_path_normalize(mainvar->name, dir_dst);
- BLI_path_normalize(mainvar->name, dir_src);
+ /* Normalize the paths in case there is some subtle difference (so they can be compared). */
+ if (relbase_valid) {
+ BLI_split_dir_part(mainvar->filepath, dir_src, sizeof(dir_src));
+ BLI_path_normalize(NULL, dir_src);
+ }
+ else {
+ dir_src[0] = '\0';
+ }
+ BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
+ BLI_path_normalize(NULL, dir_dst);
/* Only for relative, not relative-all, as this means making existing paths relative. */
if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) {
- if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
+ if (relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
/* Saved to same path. Nothing to do. */
remap_mode = BLO_WRITE_PATH_REMAP_NONE;
}
}
else if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) {
- if (G.relbase_valid == false) {
+ if (relbase_valid == false) {
/* Unsaved, all paths are absolute.Even if the user manages to set a relative path,
* there is no base-path that can be used to make it absolute. */
remap_mode = BLO_WRITE_PATH_REMAP_NONE;
@@ -1395,6 +1409,7 @@ bool BLO_write_file(Main *mainvar,
switch (remap_mode) {
case BLO_WRITE_PATH_REMAP_RELATIVE:
/* Saved, make relative paths relative to new location (if possible). */
+ BLI_assert(relbase_valid);
BKE_bpath_relative_rebase(mainvar, dir_src, dir_dst, NULL);
break;
case BLO_WRITE_PATH_REMAP_RELATIVE_ALL:
@@ -1403,6 +1418,7 @@ bool BLO_write_file(Main *mainvar,
break;
case BLO_WRITE_PATH_REMAP_ABSOLUTE:
/* Make all absolute (when requested or unsaved). */
+ BLI_assert(relbase_valid);
BKE_bpath_absolute_convert(mainvar, dir_src, NULL);
break;
case BLO_WRITE_PATH_REMAP_NONE:
@@ -1452,9 +1468,6 @@ bool BLO_write_file(Main *mainvar,
return 1;
}
-/**
- * \return Success.
- */
bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
{
bool use_userdef = false;
@@ -1577,9 +1590,6 @@ void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr
BLO_write_raw(writer, sizeof(float[3]) * (size_t)num, data_ptr);
}
-/**
- * Write a null terminated string.
- */
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
{
if (data_ptr != NULL) {
@@ -1587,10 +1597,6 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr)
}
}
-/**
- * Sometimes different data is written depending on whether the file is saved to disk or used for
- * undo. This function returns true when the current file-writing is done for undo.
- */
bool BLO_write_is_undo(BlendWriter *writer)
{
return writer->wd->use_memfile;
diff --git a/source/blender/blentranslation/BLT_lang.h b/source/blender/blentranslation/BLT_lang.h
index dcd4de10416..1a0981613a1 100644
--- a/source/blender/blentranslation/BLT_lang.h
+++ b/source/blender/blentranslation/BLT_lang.h
@@ -46,6 +46,15 @@ const char *BLT_lang_get(void);
* Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
* NOTE: Always available, even in non-WITH_INTERNATIONAL builds.
*/
+/**
+ * Get locale's elements (if relevant pointer is not NULL and element actually exists, e.g.
+ * if there is no variant,
+ * *variant and *language_variant will always be NULL).
+ * Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
+ *
+ * \note Keep that one always available, you never know,
+ * may become useful even in no #WITH_INTERNATIONAL context.
+ */
void BLT_lang_locale_explode(const char *locale,
char **language,
char **country,
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 341e648443e..21296143226 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -44,6 +44,11 @@ const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid);
const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid);
+/**
+ * Note that "lang" here is the _output_ display language. We used to restrict
+ * IME for keyboard _input_ language because our multilingual font was only used
+ * when some output languages were selected. That font is used all the time now.
+ */
bool BLT_lang_is_ime_supported(void);
/* The "translation-marker" macro. */
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index 91e8a81aec0..01f7574bd34 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -282,7 +282,6 @@ void BLT_lang_set(const char *str)
IMB_thumb_clear_translations();
}
-/* Get the current locale (short code, e.g. es_ES). */
const char *BLT_lang_get(void)
{
#ifdef WITH_INTERNATIONAL
@@ -303,15 +302,6 @@ const char *BLT_lang_get(void)
#undef LOCALE
#undef ULANGUAGE
-/**
- * Get locale's elements (if relevant pointer is not NULL and element actually exists, e.g.
- * if there is no variant,
- * *variant and *language_variant will always be NULL).
- * Non-null elements are always MEM_mallocN'ed, it's the caller's responsibility to free them.
- *
- * \note Keep that one always available, you never know,
- * may become useful even in no #WITH_INTERNATIONAL context.
- */
void BLT_lang_locale_explode(const char *locale,
char **language,
char **country,
@@ -372,9 +362,6 @@ void BLT_lang_locale_explode(const char *locale,
}
}
-/* Note that "lang" here is the _output_ display language. We used to restrict
- * IME for keyboard _input_ language because our multilingual font was only used
- * when some output languages were selected. That font is used all the time now. */
bool BLT_lang_is_ime_supported(void)
{
#ifdef WITH_INPUT_IME
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index a10a911b06c..5a9d1ba7bc4 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -39,11 +39,6 @@
#define SELECT 1
-/**
- * Fill in a vertex array from an edge array.
- *
- * \returns false if any verts aren't found.
- */
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
{
int i, i_prev = len - 1;
@@ -57,11 +52,6 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
return true;
}
-/**
- * Fill in an edge array from a vertex array (connected polygon loop).
- *
- * \returns false if any edges aren't found.
- */
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
{
int i, i_prev = len - 1;
@@ -75,10 +65,6 @@ bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
return true;
}
-/**
- * Fill in an edge array from a vertex array (connected polygon loop).
- * Creating edges as-needed.
- */
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
{
int i, i_prev = len - 1;
@@ -93,20 +79,6 @@ void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr,
static void bm_loop_attrs_copy(
BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude);
-/**
- * \brief Make Quad/Triangle
- *
- * Creates a new quad or triangle from a list of 3 or 4 vertices.
- * If \a no_double is true, then a check is done to see if a face
- * with these vertices already exists and returns it instead.
- *
- * If a pointer to an example face is provided, its custom data
- * and properties will be copied to the new face.
- *
- * \note The winding of the face is determined by the order
- * of the vertices in the vertex array.
- */
-
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -119,16 +91,6 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true);
}
-/**
- * \brief copies face loop data from shared adjacent faces.
- *
- * \param filter_fn: A function that filters the source loops before copying
- * (don't always want to copy all).
- *
- * \note when a matching edge is found, both loops of that edge are copied
- * this is done since the face may not be completely surrounded by faces,
- * this way: a quad with 2 connected quads on either side will still get all 4 loops updated
- */
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
{
BMLoop *l_first;
@@ -260,20 +222,6 @@ error:
return false;
}
-/**
- * \brief Make NGon
- *
- * Makes an ngon from an unordered list of edges.
- * Verts \a v1 and \a v2 define the winding of the new face.
- *
- * \a edges are not required to be ordered, simply to form
- * a single closed loop as a whole.
- *
- * \note While this function will work fine when the edges
- * are already sorted, if the edges are always going to be sorted,
- * #BM_face_create should be considered over this function as it
- * avoids some unnecessary work.
- */
BMFace *BM_face_create_ngon(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -294,14 +242,6 @@ BMFace *BM_face_create_ngon(BMesh *bm,
return NULL;
}
-/**
- * Create an ngon from an array of sorted verts
- *
- * Special features this has over other functions.
- * - Optionally calculate winding based on surrounding edges.
- * - Optionally create edges between vertices.
- * - Uses verts so no need to find edges (handy when you only have verts)
- */
BMFace *BM_face_create_ngon_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -367,22 +307,6 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm,
bm, v_winding[winding[0]], v_winding[winding[1]], edge_arr, len, f_example, create_flag);
}
-/**
- * Makes an NGon from an un-ordered set of verts
- *
- * assumes...
- * - that verts are only once in the list.
- * - that the verts have roughly planer bounds
- * - that the verts are roughly circular
- * there can be concave areas but overlapping folds from the center point will fail.
- *
- * a brief explanation of the method used
- * - find the center point
- * - find the normal of the vcloud
- * - order the verts around the face based on their angle to the normal vector at the center point.
- *
- * \note Since this is a vcloud there is no direction.
- */
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
{
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
@@ -467,13 +391,6 @@ static void bm_face_attrs_copy(
f_dst->mat_nr = f_src->mat_nr;
}
-/* BMESH_TODO: Special handling for hide flags? */
-/* BMESH_TODO: swap src/dst args, everywhere else in bmesh does other way round */
-
-/**
- * Copies attributes, e.g. customdata, header flags, etc, from one element
- * to another of the same type.
- */
void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
@@ -481,6 +398,9 @@ void BM_elem_attrs_copy_ex(BMesh *bm_src,
const char hflag_mask,
const uint64_t cd_mask_exclude)
{
+ /* TODO: Special handling for hide flags? */
+ /* TODO: swap src/dst args, everywhere else in bmesh does other way round. */
+
const BMHeader *ele_src = ele_src_v;
BMHeader *ele_dst = ele_dst_v;
@@ -626,15 +546,6 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
}
-/**
- * Similar to #BM_mesh_copy_init_customdata but copies all layers ignoring
- * flags like #CD_FLAG_NOCOPY.
- *
- * \param bm_dst: BMesh whose custom-data layers will be added.
- * \param bm_src: BMesh whose custom-data layers will be copied.
- * \param htype: Specifies which custom-data layers will be initiated.
- * \param allocsize: Initialize the memory-pool before use (may be an estimate).
- */
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
BMesh *bm_src,
const char htype,
@@ -786,7 +697,6 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
return bm_new;
}
-/* ME -> BM */
char BM_vert_flag_from_mflag(const char mflag)
{
return (((mflag & SELECT) ? BM_ELEM_SELECT : 0) | ((mflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0));
@@ -804,7 +714,6 @@ char BM_face_flag_from_mflag(const char mflag)
((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0) | ((mflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0));
}
-/* BM -> ME */
char BM_vert_flag_to_mflag(BMVert *v)
{
const char hflag = v->head.hflag;
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index f2b5e2b4daa..692f3b403b5 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -25,14 +25,57 @@
struct BMAllocTemplate;
struct Mesh;
+/**
+ * Fill in a vertex array from an edge array.
+ *
+ * \returns false if any verts aren't found.
+ */
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ *
+ * \returns false if any edges aren't found.
+ */
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ * Creating edges as-needed.
+ */
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
-/* sort before creation */
+/**
+ * Makes an NGon from an un-ordered set of verts.
+ *
+ * Assumes:
+ * - that verts are only once in the list.
+ * - that the verts have roughly planer bounds
+ * - that the verts are roughly circular
+ *
+ * There can be concave areas but overlapping folds from the center point will fail.
+ *
+ * A brief explanation of the method used
+ * - find the center point
+ * - find the normal of the vertex-cloud
+ * - order the verts around the face based on their angle to the normal vector at the center point.
+ *
+ * \note Since this is a vertex-cloud there is no direction.
+ */
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len);
+/**
+ * \brief Make Quad/Triangle
+ *
+ * Creates a new quad or triangle from a list of 3 or 4 vertices.
+ * If \a no_double is true, then a check is done to see if a face
+ * with these vertices already exists and returns it instead.
+ *
+ * If a pointer to an example face is provided, its custom data
+ * and properties will be copied to the new face.
+ *
+ * \note The winding of the face is determined by the order
+ * of the vertices in the vertex array.
+ */
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -41,8 +84,32 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
const BMFace *f_example,
const eBMCreateFlag create_flag);
+/**
+ * \brief copies face loop data from shared adjacent faces.
+ *
+ * \param filter_fn: A function that filters the source loops before copying
+ * (don't always want to copy all).
+ *
+ * \note when a matching edge is found, both loops of that edge are copied
+ * this is done since the face may not be completely surrounded by faces,
+ * this way: a quad with 2 connected quads on either side will still get all 4 loops updated
+ */
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data);
+/**
+ * \brief Make NGon
+ *
+ * Makes an ngon from an unordered list of edges.
+ * Verts \a v1 and \a v2 define the winding of the new face.
+ *
+ * \a edges are not required to be ordered, simply to form
+ * a single closed loop as a whole.
+ *
+ * \note While this function will work fine when the edges
+ * are already sorted, if the edges are always going to be sorted,
+ * #BM_face_create should be considered over this function as it
+ * avoids some unnecessary work.
+ */
BMFace *BM_face_create_ngon(BMesh *bm,
BMVert *v1,
BMVert *v2,
@@ -50,6 +117,14 @@ BMFace *BM_face_create_ngon(BMesh *bm,
const int len,
const BMFace *f_example,
const eBMCreateFlag create_flag);
+/**
+ * Create an ngon from an array of sorted verts
+ *
+ * Special features this has over other functions.
+ * - Optionally calculate winding based on surrounding edges.
+ * - Optionally create edges between vertices.
+ * - Uses verts so no need to find edges (handy when you only have verts)
+ */
BMFace *BM_face_create_ngon_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -58,6 +133,10 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm,
const bool calc_winding,
const bool create_edges);
+/**
+ * Copies attributes, e.g. customdata, header flags, etc, from one element
+ * to another of the same type.
+ */
void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
@@ -73,6 +152,15 @@ void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
void BM_mesh_copy_init_customdata(BMesh *bm_dst,
BMesh *bm_src,
const struct BMAllocTemplate *allocsize);
+/**
+ * Similar to #BM_mesh_copy_init_customdata but copies all layers ignoring
+ * flags like #CD_FLAG_NOCOPY.
+ *
+ * \param bm_dst: BMesh whose custom-data layers will be added.
+ * \param bm_src: BMesh whose custom-data layers will be copied.
+ * \param htype: Specifies which custom-data layers will be initiated.
+ * \param allocsize: Initialize the memory-pool before use (may be an estimate).
+ */
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
BMesh *bm_src,
const char htype,
@@ -81,7 +169,9 @@ BMesh *BM_mesh_copy(BMesh *bm_old);
char BM_face_flag_from_mflag(const char mflag);
char BM_edge_flag_from_mflag(const short mflag);
+/* ME -> BM */
char BM_vert_flag_from_mflag(const char mflag);
char BM_face_flag_to_mflag(BMFace *f);
short BM_edge_flag_to_mflag(BMEdge *e);
+/* BM -> ME */
char BM_vert_flag_to_mflag(BMVert *v);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index e72c689ddfb..1d7d10de96f 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -52,9 +52,6 @@
#endif
-/**
- * \brief Main function for creating a new vertex.
- */
BMVert *BM_vert_create(BMesh *bm,
const float co[3],
const BMVert *v_example,
@@ -137,13 +134,6 @@ BMVert *BM_vert_create(BMesh *bm,
return v;
}
-/**
- * \brief Main function for creating a new edge.
- *
- * \note Duplicate edges are supported by the API however users should _never_ see them.
- * so unless you need a unique edge or know the edge won't exist,
- * you should call with \a no_double = true.
- */
BMEdge *BM_edge_create(
BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
{
@@ -416,15 +406,6 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
return f;
}
-/**
- * Main face creation function
- *
- * \param bm: The mesh
- * \param verts: A sorted array of verts size of len
- * \param edges: A sorted array of edges size of len
- * \param len: Length of the face
- * \param create_flag: Options for creating the face
- */
BMFace *BM_face_create(BMesh *bm,
BMVert **verts,
BMEdge **edges,
@@ -494,9 +475,6 @@ BMFace *BM_face_create(BMesh *bm,
return f;
}
-/**
- * Wrapper for #BM_face_create when you don't have an edge array
- */
BMFace *BM_face_create_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -520,12 +498,6 @@ BMFace *BM_face_create_verts(BMesh *bm,
#ifndef NDEBUG
-/**
- * Check the element is valid.
- *
- * BMESH_TODO, when this raises an error the output is incredibly confusing.
- * need to have some nice way to print/debug what the heck's going on.
- */
int bmesh_elem_check(void *element, const char htype)
{
BMHeader *head = element;
@@ -833,10 +805,6 @@ static void bm_kill_only_loop(BMesh *bm, BMLoop *l)
BLI_mempool_free(bm->lpool, l);
}
-/**
- * kills all edges associated with \a f, along with any other faces containing
- * those edges
- */
void BM_face_edges_kill(BMesh *bm, BMFace *f)
{
BMEdge **edges = BLI_array_alloca(edges, f->len);
@@ -854,10 +822,6 @@ void BM_face_edges_kill(BMesh *bm, BMFace *f)
}
}
-/**
- * kills all verts associated with \a f, along with any other faces containing
- * those vertices
- */
void BM_face_verts_kill(BMesh *bm, BMFace *f)
{
BMVert **verts = BLI_array_alloca(verts, f->len);
@@ -875,9 +839,6 @@ void BM_face_verts_kill(BMesh *bm, BMFace *f)
}
}
-/**
- * Kills \a f and its loops.
- */
void BM_face_kill(BMesh *bm, BMFace *f)
{
#ifdef USE_BMESH_HOLES
@@ -922,10 +883,6 @@ void BM_face_kill(BMesh *bm, BMFace *f)
bm_kill_only_face(bm, f);
}
-/**
- * A version of #BM_face_kill which removes edges and verts
- * which have no remaining connected geometry.
- */
void BM_face_kill_loose(BMesh *bm, BMFace *f)
{
#ifdef USE_BMESH_HOLES
@@ -981,9 +938,6 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f)
bm_kill_only_face(bm, f);
}
-/**
- * kills \a e and all faces that use it.
- */
void BM_edge_kill(BMesh *bm, BMEdge *e)
{
while (e->l) {
@@ -996,9 +950,6 @@ void BM_edge_kill(BMesh *bm, BMEdge *e)
bm_kill_only_edge(bm, e);
}
-/**
- * kills \a v and all edges that use it.
- */
void BM_vert_kill(BMesh *bm, BMVert *v)
{
while (v->e) {
@@ -1025,15 +976,6 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
return i;
}
-/**
- * \brief Loop Reverse
- *
- * Changes the winding order of a face from CW to CCW or vice versa.
- *
- * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
- * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
- * (use when flipping normals, disable when mirroring, eg: symmetrize).
- */
void bmesh_kernel_loop_reverse(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
@@ -1192,20 +1134,6 @@ static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag)
/* Mid-level Topology Manipulation Functions */
-/**
- * \brief Join Connected Faces
- *
- * Joins a collected group of faces into one. Only restriction on
- * the input data is that the faces must be connected to each other.
- *
- * \return The newly created combine BMFace.
- *
- * \note If a pair of faces share multiple edges,
- * the pair of faces will be joined at every edge.
- *
- * \note this is a generic, flexible join faces function,
- * almost everything uses this, including #BM_faces_join_pair
- */
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
{
BMFace *f, *f_new;
@@ -1422,44 +1350,6 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example)
return f;
}
-/**
- * \brief Split Face Make Edge (SFME)
- *
- * \warning this is a low level function, most likely you want to use #BM_face_split()
- *
- * Takes as input two vertices in a single face.
- * An edge is created which divides the original face into two distinct regions.
- * One of the regions is assigned to the original face and it is closed off.
- * The second region has a new face assigned to it.
- *
- * \par Examples:
- * <pre>
- * Before: After:
- * +--------+ +--------+
- * | | | |
- * | | | f1 |
- * v1 f1 v2 v1======v2
- * | | | f2 |
- * | | | |
- * +--------+ +--------+
- * </pre>
- *
- * \note the input vertices can be part of the same edge. This will
- * result in a two edged face. This is desirable for advanced construction
- * tools and particularly essential for edge bevel. Because of this it is
- * up to the caller to decide what to do with the extra edge.
- *
- * \note If \a holes is NULL, then both faces will lose
- * all holes from the original face. Also, you cannot split between
- * a hole vert and a boundary vert; that case is handled by higher-
- * level wrapping functions (when holes are fully implemented, anyway).
- *
- * \note that holes represents which holes goes to the new face, and of
- * course this requires removing them from the existing face first, since
- * you cannot have linked list links inside multiple lists.
- *
- * \return A BMFace pointer
- */
BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
BMFace *f,
BMLoop *l_v1,
@@ -1599,24 +1489,6 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
return f2;
}
-/**
- * \brief Split Edge Make Vert (SEMV)
- *
- * Takes \a e edge and splits it into two, creating a new vert.
- * \a tv should be one end of \a e : the newly created edge
- * will be attached to that end and is returned in \a r_e.
- *
- * \par Examples:
- *
- * <pre>
- * E
- * Before: OV-------------TV
- * E RE
- * After: OV------NV-----TV
- * </pre>
- *
- * \return The newly created BMVert pointer.
- */
BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
{
BMLoop *l_next;
@@ -1770,36 +1642,6 @@ BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEd
return v_new;
}
-/**
- * \brief Join Edge Kill Vert (JEKV)
- *
- * Takes an edge \a e_kill and pointer to one of its vertices \a v_kill
- * and collapses the edge on that vertex.
- *
- * \par Examples:
- *
- * <pre>
- * Before: e_old e_kill
- * +-------+-------+
- * | | |
- * v_old v_kill v_target
- *
- * After: e_old
- * +---------------+
- * | |
- * v_old v_target
- * </pre>
- *
- * \par Restrictions:
- * KV is a vertex that must have a valance of exactly two. Furthermore
- * both edges in KV's disk cycle (OE and KE) must be unique (no double edges).
- *
- * \return The resulting edge, NULL for failure.
- *
- * \note This euler has the possibility of creating
- * faces with just 2 edges. It is up to the caller to decide what to do with
- * these faces.
- */
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -1967,24 +1809,6 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
return NULL;
}
-/**
- * \brief Join Vert Kill Edge (JVKE)
- *
- * Collapse an edge, merging surrounding data.
- *
- * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert
- * which only handle 2 valence verts,
- * this can handle any number of connected edges/faces.
- *
- * <pre>
- * Before: -> After:
- * +-+-+-+ +-+-+-+
- * | | | | | \ / |
- * +-+-+-+ +--+--+
- * | | | | | / \ |
- * +-+-+-+ +-+-+-+
- * </pre>
- */
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -2068,37 +1892,6 @@ BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
return v_target;
}
-/**
- * \brief Join Face Kill Edge (JFKE)
- *
- * Takes two faces joined by a single 2-manifold edge and fuses them together.
- * The edge shared by the faces must not be connected to any other edges which have
- * Both faces in its radial cycle
- *
- * \par Examples:
- * <pre>
- * A B
- * +--------+ +--------+
- * | | | |
- * | f1 | | f1 |
- * v1========v2 = Ok! v1==V2==v3 == Wrong!
- * | f2 | | f2 |
- * | | | |
- * +--------+ +--------+
- * </pre>
- *
- * In the example A, faces \a f1 and \a f2 are joined by a single edge,
- * and the euler can safely be used.
- * In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
- * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
- * before attempting to fuse \a f1 and \a f2.
- *
- * \note The order of arguments decides whether or not certain per-face attributes are present
- * in the resultant face. For instance vertex winding, material index, smooth flags,
- * etc are inherited from \a f1, not \a f2.
- *
- * \return A BMFace pointer
- */
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
{
BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL;
@@ -2221,11 +2014,6 @@ BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEd
return f1;
}
-/**
- * Check if splicing vertices would create any double edges.
- *
- * \note assume caller will handle case where verts share an edge.
- */
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
{
bool is_double = false;
@@ -2269,18 +2057,6 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
return is_double;
}
-/**
- * \brief Splice Vert
- *
- * Merges two verts into one
- * (\a v_src into \a v_dst, removing \a v_src).
- *
- * \return Success
- *
- * \warning This doesn't work for collapsing edges,
- * where \a v and \a vtarget are connected by an edge
- * (assert checks for this case).
- */
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
{
BMEdge *e;
@@ -2317,17 +2093,6 @@ BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
return (e->l && e->l->radial_next != e->l);
}
-/**
- * \brief Separate Vert
- *
- * Separates all disjoint fans that meet at a vertex, making a unique
- * vertex for each region. returns an array of all resulting vertices.
- *
- * \note this is a low level function, bm_edge_separate needs to run on edges first
- * or, the faces sharing verts must not be sharing edges for them to split at least.
- *
- * \return Success
- */
void bmesh_kernel_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
{
@@ -2480,9 +2245,6 @@ static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separ
} while ((edges_separate = edges_separate->next));
}
-/**
- * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
- */
void BM_vert_separate(BMesh *bm,
BMVert *v,
BMEdge **e_in,
@@ -2516,9 +2278,6 @@ void BM_vert_separate(BMesh *bm,
}
}
-/**
- * A version of #BM_vert_separate which takes a flag.
- */
void BM_vert_separate_hflag(BMesh *bm,
BMVert *v,
const char hflag,
@@ -2584,16 +2343,6 @@ void BM_vert_separate_tested_edges(BMesh *UNUSED(bm),
/** \} */
-/**
- * \brief Splice Edge
- *
- * Splice two unique edges which share the same two vertices into one edge.
- * (\a e_src into \a e_dst, removing e_src).
- *
- * \return Success
- *
- * \note Edges must already have the same vertices.
- */
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
{
BMLoop *l;
@@ -2627,17 +2376,6 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
return true;
}
-/**
- * \brief Separate Edge
- *
- * Separates a single edge into two edge: the original edge and
- * a new edge that has only \a l_sep in its radial.
- *
- * \return Success
- *
- * \note Does nothing if \a l_sep is already the only loop in the
- * edge radial.
- */
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
{
BMEdge *e_new;
@@ -2673,15 +2411,6 @@ void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool
BM_CHECK_ELEMENT(e);
}
-/**
- * \brief Un-glue Region Make Vert (URMV)
- *
- * Disconnects a face from its vertex fan at loop \a l_sep
- *
- * \return The newly created BMVert
- *
- * \note Will be a no-op and return original vertex if only two edges at that vertex.
- */
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = NULL;
@@ -2744,13 +2473,6 @@ BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep)
return v_new;
}
-/**
- * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
- * The loops must all share the same vertex, can be in any order
- * and are all moved to use a single new vertex - which is returned.
- *
- * This function handles the details of finding fans boundaries.
- */
BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len)
{
BMVert *v_sep = larr[0]->v;
@@ -2931,10 +2653,6 @@ static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_
} while ((l_iter = l_iter->radial_next) != l_first);
}
-/**
- * This function assumes l_sep is a part of a larger fan which has already been
- * isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
- */
BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep)
{
BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
@@ -2944,11 +2662,6 @@ BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l
return v_new;
}
-/**
- * Avoid calling this where possible,
- * low level function so both face pointers remain intact but point to swapped data.
- * \note must be from the same bmesh.
- */
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter, *l_first;
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index 8f7580714ae..cd0e1754cd1 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -25,26 +25,50 @@ BMFace *BM_face_copy(
typedef enum eBMCreateFlag {
BM_CREATE_NOP = 0,
- /* faces and edges only */
+ /** Faces and edges only. */
BM_CREATE_NO_DOUBLE = (1 << 1),
- /* Skip CustomData - for all element types data,
- * use if we immediately write customdata into the element so this skips copying from 'example'
- * args or setting defaults, speeds up conversion when data is converted all at once. */
+ /**
+ * Skip custom-data - for all element types data,
+ * use if we immediately write custom-data into the element so this skips copying from 'example'
+ * arguments or setting defaults, speeds up conversion when data is converted all at once.
+ */
BM_CREATE_SKIP_CD = (1 << 2),
} eBMCreateFlag;
+/**
+ * \brief Main function for creating a new vertex.
+ */
BMVert *BM_vert_create(BMesh *bm,
const float co[3],
const BMVert *v_example,
const eBMCreateFlag create_flag);
+/**
+ * \brief Main function for creating a new edge.
+ *
+ * \note Duplicate edges are supported by the API however users should _never_ see them.
+ * so unless you need a unique edge or know the edge won't exist,
+ * you should call with \a no_double = true.
+ */
BMEdge *BM_edge_create(
BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag);
+/**
+ * Main face creation function
+ *
+ * \param bm: The mesh
+ * \param verts: A sorted array of verts size of len
+ * \param edges: A sorted array of edges size of len
+ * \param len: Length of the face
+ * \param create_flag: Options for creating the face
+ */
BMFace *BM_face_create(BMesh *bm,
BMVert **verts,
BMEdge **edges,
const int len,
const BMFace *f_example,
const eBMCreateFlag create_flag);
+/**
+ * Wrapper for #BM_face_create when you don't have an edge array
+ */
BMFace *BM_face_create_verts(BMesh *bm,
BMVert **vert_arr,
const int len,
@@ -52,27 +76,105 @@ BMFace *BM_face_create_verts(BMesh *bm,
const eBMCreateFlag create_flag,
const bool create_edges);
+/**
+ * Kills all edges associated with \a f, along with any other faces containing those edges.
+ */
void BM_face_edges_kill(BMesh *bm, BMFace *f);
+/**
+ * kills all verts associated with \a f, along with any other faces containing
+ * those vertices
+ */
void BM_face_verts_kill(BMesh *bm, BMFace *f);
+/**
+ * A version of #BM_face_kill which removes edges and verts
+ * which have no remaining connected geometry.
+ */
void BM_face_kill_loose(BMesh *bm, BMFace *f);
+/**
+ * Kills \a f and its loops.
+ */
void BM_face_kill(BMesh *bm, BMFace *f);
+/**
+ * Kills \a e and all faces that use it.
+ */
void BM_edge_kill(BMesh *bm, BMEdge *e);
+/**
+ * Kills \a v and all edges that use it.
+ */
void BM_vert_kill(BMesh *bm, BMVert *v);
+/**
+ * \brief Splice Edge
+ *
+ * Splice two unique edges which share the same two vertices into one edge.
+ * (\a e_src into \a e_dst, removing e_src).
+ *
+ * \return Success
+ *
+ * \note Edges must already have the same vertices.
+ */
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src);
+/**
+ * \brief Splice Vert
+ *
+ * Merges two verts into one
+ * (\a v_src into \a v_dst, removing \a v_src).
+ *
+ * \return Success
+ *
+ * \warning This doesn't work for collapsing edges,
+ * where \a v and \a vtarget are connected by an edge
+ * (assert checks for this case).
+ */
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src);
+/**
+ * Check if splicing vertices would create any double edges.
+ *
+ * \note assume caller will handle case where verts share an edge.
+ */
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b);
+/**
+ * \brief Loop Reverse
+ *
+ * Changes the winding order of a face from CW to CCW or vice versa.
+ *
+ * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
+ * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
+ * (use when flipping normals, disable when mirroring, eg: symmetrize).
+ */
void bmesh_kernel_loop_reverse(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
const bool use_loop_mdisp_flip);
+/**
+ * Avoid calling this where possible,
+ * low level function so both face pointers remain intact but point to swapped data.
+ * \note must be from the same bmesh.
+ */
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
+/**
+ * \brief Join Connected Faces
+ *
+ * Joins a collected group of faces into one. Only restriction on
+ * the input data is that the faces must be connected to each other.
+ *
+ * \return The newly created combine BMFace.
+ *
+ * \note If a pair of faces share multiple edges,
+ * the pair of faces will be joined at every edge.
+ *
+ * \note this is a generic, flexible join faces function,
+ * almost everything uses this, including #BM_faces_join_pair
+ */
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
+/**
+ * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
+ */
void BM_vert_separate(BMesh *bm,
BMVert *v,
BMEdge **e_in,
@@ -80,6 +182,9 @@ void BM_vert_separate(BMesh *bm,
const bool copy_select,
BMVert ***r_vout,
int *r_vout_len);
+/**
+ * A version of #BM_vert_separate which takes a flag.
+ */
void BM_vert_separate_hflag(BMesh *bm,
BMVert *v,
const char hflag,
@@ -94,10 +199,70 @@ void BM_vert_separate_tested_edges(
*
* Names are on the verbose side but these are only for low-level access.
*/
+/**
+ * \brief Separate Vert
+ *
+ * Separates all disjoint fans that meet at a vertex, making a unique
+ * vertex for each region. returns an array of all resulting vertices.
+ *
+ * \note this is a low level function, bm_edge_separate needs to run on edges first
+ * or, the faces sharing verts must not be sharing edges for them to split at least.
+ *
+ * \return Success
+ */
void bmesh_kernel_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select);
+/**
+ * \brief Separate Edge
+ *
+ * Separates a single edge into two edge: the original edge and
+ * a new edge that has only \a l_sep in its radial.
+ *
+ * \return Success
+ *
+ * \note Does nothing if \a l_sep is already the only loop in the
+ * edge radial.
+ */
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select);
+/**
+ * \brief Split Face Make Edge (SFME)
+ *
+ * \warning this is a low level function, most likely you want to use #BM_face_split()
+ *
+ * Takes as input two vertices in a single face.
+ * An edge is created which divides the original face into two distinct regions.
+ * One of the regions is assigned to the original face and it is closed off.
+ * The second region has a new face assigned to it.
+ *
+ * \par Examples:
+ * <pre>
+ * Before: After:
+ * +--------+ +--------+
+ * | | | |
+ * | | | f1 |
+ * v1 f1 v2 v1======v2
+ * | | | f2 |
+ * | | | |
+ * +--------+ +--------+
+ * </pre>
+ *
+ * \note the input vertices can be part of the same edge. This will
+ * result in a two edged face. This is desirable for advanced construction
+ * tools and particularly essential for edge bevel. Because of this it is
+ * up to the caller to decide what to do with the extra edge.
+ *
+ * \note If \a holes is NULL, then both faces will lose
+ * all holes from the original face. Also, you cannot split between
+ * a hole vert and a boundary vert; that case is handled by higher-
+ * level wrapping functions (when holes are fully implemented, anyway).
+ *
+ * \note that holes represents which holes goes to the new face, and of
+ * course this requires removing them from the existing face first, since
+ * you cannot have linked list links inside multiple lists.
+ *
+ * \return A BMFace pointer
+ */
BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
BMFace *f,
BMLoop *l_v1,
@@ -109,7 +274,55 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
BMEdge *example,
const bool no_double);
+/**
+ * \brief Split Edge Make Vert (SEMV)
+ *
+ * Takes \a e edge and splits it into two, creating a new vert.
+ * \a tv should be one end of \a e : the newly created edge
+ * will be attached to that end and is returned in \a r_e.
+ *
+ * \par Examples:
+ *
+ * <pre>
+ * E
+ * Before: OV-------------TV
+ * E RE
+ * After: OV------NV-----TV
+ * </pre>
+ *
+ * \return The newly created BMVert pointer.
+ */
BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
+/**
+ * \brief Join Edge Kill Vert (JEKV)
+ *
+ * Takes an edge \a e_kill and pointer to one of its vertices \a v_kill
+ * and collapses the edge on that vertex.
+ *
+ * \par Examples:
+ *
+ * <pre>
+ * Before: e_old e_kill
+ * +-------+-------+
+ * | | |
+ * v_old v_kill v_target
+ *
+ * After: e_old
+ * +---------------+
+ * | |
+ * v_old v_target
+ * </pre>
+ *
+ * \par Restrictions:
+ * KV is a vertex that must have a valance of exactly two. Furthermore
+ * both edges in KV's disk cycle (OE and KE) must be unique (no double edges).
+ *
+ * \return The resulting edge, NULL for failure.
+ *
+ * \note This euler has the possibility of creating
+ * faces with just 2 edges. It is up to the caller to decide what to do with
+ * these faces.
+ */
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -117,14 +330,83 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
const bool check_edge_exists,
const bool kill_degenerate_faces,
const bool kill_duplicate_faces);
+/**
+ * \brief Join Vert Kill Edge (JVKE)
+ *
+ * Collapse an edge, merging surrounding data.
+ *
+ * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert
+ * which only handle 2 valence verts,
+ * this can handle any number of connected edges/faces.
+ *
+ * <pre>
+ * Before: -> After:
+ * +-+-+-+ +-+-+-+
+ * | | | | | \ / |
+ * +-+-+-+ +--+--+
+ * | | | | | / \ |
+ * +-+-+-+ +-+-+-+
+ * </pre>
+ */
BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
const bool do_del,
const bool check_edge_exists,
const bool kill_degenerate_faces);
+/**
+ * \brief Join Face Kill Edge (JFKE)
+ *
+ * Takes two faces joined by a single 2-manifold edge and fuses them together.
+ * The edge shared by the faces must not be connected to any other edges which have
+ * Both faces in its radial cycle
+ *
+ * \par Examples:
+ * <pre>
+ * A B
+ * +--------+ +--------+
+ * | | | |
+ * | f1 | | f1 |
+ * v1========v2 = Ok! v1==V2==v3 == Wrong!
+ * | f2 | | f2 |
+ * | | | |
+ * +--------+ +--------+
+ * </pre>
+ *
+ * In the example A, faces \a f1 and \a f2 are joined by a single edge,
+ * and the euler can safely be used.
+ * In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error.
+ * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges
+ * before attempting to fuse \a f1 and \a f2.
+ *
+ * \note The order of arguments decides whether or not certain per-face attributes are present
+ * in the resultant face. For instance vertex winding, material index, smooth flags,
+ * etc are inherited from \a f1, not \a f2.
+ *
+ * \return A BMFace pointer
+ */
BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
+/**
+ * \brief Un-glue Region Make Vert (URMV)
+ *
+ * Disconnects a face from its vertex fan at loop \a l_sep
+ *
+ * \return The newly created BMVert
+ *
+ * \note Will be a no-op and return original vertex if only two edges at that vertex.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep);
+/**
+ * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once.
+ * The loops must all share the same vertex, can be in any order
+ * and are all moved to use a single new vertex - which is returned.
+ *
+ * This function handles the details of finding fans boundaries.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len);
+/**
+ * This function assumes l_sep is a part of a larger fan which has already been
+ * isolated by calling #bmesh_kernel_edge_separate to segregate it radially.
+ */
BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep);
diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c
index 9f2fb1370bb..ae93795d51c 100644
--- a/source/blender/bmesh/intern/bmesh_delete.c
+++ b/source/blender/bmesh/intern/bmesh_delete.c
@@ -99,10 +99,6 @@ void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype
}
}
-/**
- * \warning oflag applies to different types in some contexts,
- * not just the type being removed.
- */
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
{
BMEdge *e;
@@ -275,10 +271,6 @@ void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype)
}
}
-/**
- * \warning oflag applies to different types in some contexts,
- * not just the type being removed.
- */
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
{
BMEdge *e;
diff --git a/source/blender/bmesh/intern/bmesh_delete.h b/source/blender/bmesh/intern/bmesh_delete.h
index fcbcb8a90fc..18e278a99fd 100644
--- a/source/blender/bmesh/intern/bmesh_delete.h
+++ b/source/blender/bmesh/intern/bmesh_delete.h
@@ -23,5 +23,13 @@
void BMO_mesh_delete_oflag_tagged(BMesh *bm, const short oflag, const char htype);
void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype);
+/**
+ * \warning oflag applies to different types in some contexts,
+ * not just the type being removed.
+ */
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type);
+/**
+ * \warning oflag applies to different types in some contexts,
+ * not just the type being removed.
+ */
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index ab14ec23fad..3c79d2bce04 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -121,9 +121,6 @@ static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v,
return true;
}
-/**
- * \return listbase of listbases, each linking to a vertex.
- */
int BM_mesh_edgeloops_find(BMesh *bm,
ListBase *r_eloops,
bool (*test_fn)(BMEdge *, void *user_data),
@@ -506,7 +503,6 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo
/* -------------------------------------------------------------------- */
/* BM_edgeloop_*** functions */
-/* return new edgeloops */
BMEdgeLoopStore *BM_edgeloop_copy(BMEdgeLoopStore *el_store)
{
BMEdgeLoopStore *el_store_copy = MEM_mallocN(sizeof(*el_store), __func__);
@@ -565,9 +561,6 @@ const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
#define NODE_AS_V(n) ((BMVert *)((LinkData *)n)->data)
#define NODE_AS_CO(n) ((BMVert *)((LinkData *)n)->data)->co
-/**
- * edges are assigned to one vert -> the next.
- */
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
{
LinkData *node;
@@ -653,12 +646,6 @@ bool BM_edgeloop_calc_normal(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
return true;
}
-/**
- * For open loops that are straight lines,
- * calculating the normal as if it were a polygon is meaningless.
- *
- * Instead use an alignment vector and calculate the normal based on that.
- */
bool BM_edgeloop_calc_normal_aligned(BMesh *UNUSED(bm),
BMEdgeLoopStore *el_store,
const float no_align[3])
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h
index 34fc4c0ccc1..58b0d92fb72 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.h
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.h
@@ -28,6 +28,9 @@ struct GSet;
struct ListBase;
/* multiple edgeloops (ListBase) */
+/**
+ * \return listbase of listbases, each linking to a vertex.
+ */
int BM_mesh_edgeloops_find(BMesh *bm,
struct ListBase *r_eloops,
bool (*test_fn)(BMEdge *, void *user_data),
@@ -47,7 +50,10 @@ void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm,
const float no_align[3]);
void BM_mesh_edgeloops_calc_order(BMesh *bm, ListBase *eloops, const bool use_normals);
-/* single edgeloop */
+/**
+ * Copy a single edge-loop.
+ * \return new edge-loops.
+ */
struct BMEdgeLoopStore *BM_edgeloop_copy(struct BMEdgeLoopStore *el_store);
struct BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr,
const int v_arr_tot,
@@ -59,9 +65,18 @@ int BM_edgeloop_length_get(struct BMEdgeLoopStore *el_store);
struct ListBase *BM_edgeloop_verts_get(struct BMEdgeLoopStore *el_store);
const float *BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store);
const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store);
+/**
+ * Edges are assigned to one vert -> the next.
+ */
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr);
void BM_edgeloop_calc_center(BMesh *bm, struct BMEdgeLoopStore *el_store);
bool BM_edgeloop_calc_normal(BMesh *bm, struct BMEdgeLoopStore *el_store);
+/**
+ * For open loops that are straight lines,
+ * calculating the normal as if it were a polygon is meaningless.
+ *
+ * Instead use an alignment vector and calculate the normal based on that.
+ */
bool BM_edgeloop_calc_normal_aligned(BMesh *bm,
struct BMEdgeLoopStore *el_store,
const float no_align[3]);
diff --git a/source/blender/bmesh/intern/bmesh_error.h b/source/blender/bmesh/intern/bmesh_error.h
index 7694d4dbfb6..68ec3fe3ee8 100644
--- a/source/blender/bmesh/intern/bmesh_error.h
+++ b/source/blender/bmesh/intern/bmesh_error.h
@@ -48,13 +48,17 @@ typedef enum eBMOpErrorLevel {
BMO_ERROR_FATAL = 2,
} eBMOpErrorLevel;
-/* Pushes an error onto the bmesh error stack.
- * if msg is null, then the default message for the `errcode` is used. */
+/**
+ * Pushes an error onto the bmesh error stack.
+ * if msg is null, then the default message for the `errcode` is used.
+ */
void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg)
ATTR_NONNULL(1, 2, 4);
-/* Gets the topmost error from the stack.
- * returns error code or 0 if no error. */
+/**
+ * Gets the topmost error from the stack.
+ * returns error code or 0 if no error.
+ */
bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level);
bool BMO_error_get_at_level(BMesh *bm,
eBMOpErrorLevel level,
@@ -83,8 +87,10 @@ void BMO_error_clear(BMesh *bm);
# define _BMESH_DUMMY_ABORT() (void)0
#endif
-/* This is meant to be higher level than BLI_assert(),
- * its enabled even when in Release mode. */
+/**
+ * This is meant to be higher level than BLI_assert(),
+ * its enabled even when in Release mode.
+ */
#define BMESH_ASSERT(a) \
(void)((!(a)) ? ((fprintf(stderr, \
"BMESH_ASSERT failed: %s, %s(), %d at \'%s\'\n", \
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 288c5fa8158..a1bcd8e6258 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -81,13 +81,6 @@ static void bm_data_interp_from_elem(CustomData *data_layer,
}
}
-/**
- * \brief Data, Interp From Verts
- *
- * Interpolates per-vertex data from two sources to \a v_dst
- *
- * \note This is an exact match to #BM_data_interp_from_edges
- */
void BM_data_interp_from_verts(
BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
{
@@ -95,13 +88,6 @@ void BM_data_interp_from_verts(
&bm->vdata, (const BMElem *)v_src_1, (const BMElem *)v_src_2, (BMElem *)v_dst, fac);
}
-/**
- * \brief Data, Interp From Edges
- *
- * Interpolates per-edge data from two sources to \a e_dst.
- *
- * \note This is an exact match to #BM_data_interp_from_verts
- */
void BM_data_interp_from_edges(
BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac)
{
@@ -120,12 +106,6 @@ static void UNUSED_FUNCTION(BM_Data_Vert_Average)(BMesh *UNUSED(bm), BMFace *UNU
// BMIter iter;
}
-/**
- * \brief Data Face-Vert Edge Interp
- *
- * Walks around the faces of \a e and interpolates
- * the loop data between two sources.
- */
void BM_data_interp_face_vert_edge(BMesh *bm,
const BMVert *v_src_1,
const BMVert *UNUSED(v_src_2),
@@ -169,14 +149,6 @@ void BM_data_interp_face_vert_edge(BMesh *bm,
} while ((l_iter = l_iter->radial_next) != e->l);
}
-/**
- * \brief Data Interp From Face
- *
- * projects target onto source, and pulls interpolated customdata from
- * source.
- *
- * \note Only handles loop customdata. multires is handled.
- */
void BM_face_interp_from_face_ex(BMesh *bm,
BMFace *f_dst,
const BMFace *f_src,
@@ -570,9 +542,6 @@ void BM_loop_interp_multires_ex(BMesh *UNUSED(bm),
BLI_task_parallel_range(0, res, &data, loop_interp_multires_cb, &settings);
}
-/**
- * project the multires grid in target onto f_src's set of multires grids
- */
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
{
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -618,10 +587,6 @@ void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src)
}
}
-/**
- * smooths boundaries between multires grids,
- * including some borders in adjacent faces
- */
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
{
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -730,10 +695,6 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
}
}
-/**
- * projects a single loop, target, onto f_src for customdata interpolation. multires is handled.
- * if do_vertex is true, target's vert data will also get interpolated.
- */
void BM_loop_interp_from_face(
BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
{
@@ -1246,9 +1207,6 @@ static void bm_vert_loop_groups_data_layer_merge_weights__single(
}
}
-/**
- * Take existing custom data and merge each fan's data.
- */
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int layer_n)
{
const int type = bm->ldata.layers[layer_n].type;
@@ -1260,10 +1218,6 @@ void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int
} while ((groups = groups->next));
}
-/**
- * A version of #BM_vert_loop_groups_data_layer_merge
- * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator)
- */
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
LinkNode *groups,
const int layer_n,
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index c77281bd798..d1a73509a4a 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -29,6 +29,9 @@ void BM_loop_interp_multires_ex(BMesh *bm,
const float f_dst_center[3],
const float f_src_center[3],
const int cd_loop_mdisp_offset);
+/**
+ * Project the multi-resolution grid in target onto f_src's set of multi-resolution grids.
+ */
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src);
void BM_face_interp_multires_ex(BMesh *bm,
@@ -41,10 +44,30 @@ void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src);
void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src);
+/**
+ * \brief Data, Interpolate From Verts
+ *
+ * Interpolates per-vertex data from two sources to \a v_dst
+ *
+ * \note This is an exact match to #BM_data_interp_from_edges.
+ */
void BM_data_interp_from_verts(
BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac);
+/**
+ * \brief Data, Interpolate From Edges
+ *
+ * Interpolates per-edge data from two sources to \a e_dst.
+ *
+ * \note This is an exact match to #BM_data_interp_from_verts.
+ */
void BM_data_interp_from_edges(
BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac);
+/**
+ * \brief Data Face-Vert Edge Interpolate
+ *
+ * Walks around the faces of \a e and interpolates
+ * the loop data between two sources.
+ */
void BM_data_interp_face_vert_edge(BMesh *bm,
const BMVert *v_src_1,
const BMVert *v_src_2,
@@ -60,6 +83,13 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int ds
float BM_elem_float_data_get(CustomData *cd, void *element, int type);
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val);
+/**
+ * \brief Data Interpolate From Face
+ *
+ * Projects target onto source, and pulls interpolated custom-data from source.
+ *
+ * \note Only handles loop custom-data. multi-res is handled.
+ */
void BM_face_interp_from_face_ex(BMesh *bm,
BMFace *f_dst,
const BMFace *f_src,
@@ -69,14 +99,30 @@ void BM_face_interp_from_face_ex(BMesh *bm,
float (*cos_2d)[2],
float axis_mat[3][3]);
void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex);
+/**
+ * Projects a single loop, target, onto f_src for custom-data interpolation.
+ * multi-resolution is handled.
+ * \param do_vertex: When true the target's vert data will also get interpolated.
+ */
void BM_loop_interp_from_face(
BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires);
+/**
+ * Smooths boundaries between multi-res grids,
+ * including some borders in adjacent faces.
+ */
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f);
struct LinkNode *BM_vert_loop_groups_data_layer_create(
BMesh *bm, BMVert *v, const int layer_n, const float *loop_weights, struct MemArena *arena);
+/**
+ * Take existing custom data and merge each fan's data.
+ */
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, const int layer_n);
+/**
+ * A version of #BM_vert_loop_groups_data_layer_merge
+ * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator).
+ */
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm,
struct LinkNode *groups,
const int layer_n,
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index bd28022de4b..6a27e54c6a6 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -47,9 +47,6 @@ const char bm_iter_itype_htype_map[BM_ITYPE_MAX] = {
BM_LOOP, /* BM_LOOPS_OF_EDGE */
};
-/**
- * Utility function.
- */
int BM_iter_mesh_count(const char itype, BMesh *bm)
{
int count;
@@ -73,9 +70,6 @@ int BM_iter_mesh_count(const char itype, BMesh *bm)
return count;
}
-/**
- * \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
- */
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
{
BMIter iter;
@@ -98,12 +92,6 @@ void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
return val;
}
-/**
- * \brief Iterator as Array
- *
- * Sometimes its convenient to get the iterator as an array
- * to avoid multiple calls to #BM_iter_at_index.
- */
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
{
int i = 0;
@@ -124,11 +112,6 @@ int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, cons
return i;
}
-/**
- * \brief Operator Iterator as Array
- *
- * Sometimes its convenient to get the iterator as an array.
- */
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char restrictmask,
@@ -155,16 +138,6 @@ int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
return i;
}
-/**
- * \brief Iterator as Array
- *
- * Allocates a new array, has the advantage that you don't need to know the size ahead of time.
- *
- * Takes advantage of less common iterator usage to avoid counting twice,
- * which you might end up doing when #BM_iter_as_array is used.
- *
- * Caller needs to free the array.
- */
void *BM_iter_as_arrayN(BMesh *bm,
const char itype,
void *data,
@@ -272,9 +245,6 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
return bitmap_enabled;
}
-/**
- * Needed when we want to check faces, but return a loop aligned array.
- */
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
BLI_bitmap *bitmap,
bool (*test_fn)(BMFace *, void *user_data),
@@ -305,11 +275,6 @@ int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
return bitmap_enabled;
}
-/**
- * \brief Elem Iter Flag Count
- *
- * Counts how many flagged / unflagged items are found in this element.
- */
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
{
BMIter iter;
@@ -325,11 +290,6 @@ int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, cons
return count;
}
-/**
- * \brief Elem Iter Tool Flag Count
- *
- * Counts how many flagged / unflagged items are found in this element.
- */
int BMO_iter_elem_count_flag(
BMesh *bm, const char itype, void *data, const short oflag, const bool value)
{
@@ -371,11 +331,6 @@ int BMO_iter_elem_count_flag(
return count;
}
-/**
- * \brief Mesh Iter Flag Count
- *
- * Counts how many flagged / unflagged items are found in this mesh.
- */
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
{
BMIter iter;
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index ab4427e6968..12b3581b0a1 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -34,13 +34,6 @@
#include "BLI_compiler_attrs.h"
#include "BLI_mempool.h"
-/* Defines for passing to BM_iter_new.
- *
- * "OF" can be substituted for "around"
- * so BM_VERTS_OF_FACE means "vertices
- * around a face."
- */
-
/* these iterator over all elements of a specific
* type in the mesh.
*
@@ -75,6 +68,12 @@ typedef enum BMIterType {
/* the iterator htype for each iterator */
extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
+/* -------------------------------------------------------------------- */
+/** \name Defines for passing to #BM_iter_new.
+ *
+ * "OF" can be substituted for "around" so #BM_VERTS_OF_FACE means "vertices* around a face."
+ * \{ */
+
#define BM_ITER_MESH(ele, iter, bm, itype) \
for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, bm, itype, NULL); ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter))
@@ -108,6 +107,8 @@ extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_new(iter, NULL, itype, data), indexvar = 0; ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++)
+/** \} */
+
/* iterator type structs */
struct BMIter__elem_of_mesh {
BLI_mempool_iter pooliter;
@@ -184,14 +185,38 @@ typedef struct BMIter {
char itype;
} BMIter;
+/**
+ * \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays.
+ */
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \brief Iterator as Array
+ *
+ * Sometimes its convenient to get the iterator as an array
+ * to avoid multiple calls to #BM_iter_at_index.
+ */
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len);
+/**
+ * \brief Iterator as Array
+ *
+ * Allocates a new array, has the advantage that you don't need to know the size ahead of time.
+ *
+ * Takes advantage of less common iterator usage to avoid counting twice,
+ * which you might end up doing when #BM_iter_as_array is used.
+ *
+ * Caller needs to free the array.
+ */
void *BM_iter_as_arrayN(BMesh *bm,
const char itype,
void *data,
int *r_len,
void **stack_array,
int stack_array_size) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \brief Operator Iterator as Array
+ *
+ * Sometimes its convenient to get the iterator as an array.
+ */
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char restrictmask,
@@ -210,15 +235,36 @@ int BM_iter_mesh_bitmap_from_filter(const char itype,
uint *bitmap,
bool (*test_fn)(BMElem *, void *user_data),
void *user_data);
+/**
+ * Needed when we want to check faces, but return a loop aligned array.
+ */
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
uint *bitmap,
bool (*test_fn)(BMFace *, void *user_data),
void *user_data);
+/**
+ * \brief Elem Iter Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this element.
+ */
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value);
+/**
+ * \brief Elem Iter Tool Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this element.
+ */
int BMO_iter_elem_count_flag(
BMesh *bm, const char itype, void *data, const short oflag, const bool value);
+/**
+ * Utility function.
+ */
int BM_iter_mesh_count(const char itype, BMesh *bm);
+/**
+ * \brief Mesh Iter Flag Count
+ *
+ * Counts how many flagged / unflagged items are found in this mesh.
+ */
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value);
/* private for bmesh_iterators_inline.c */
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 9033e43374b..e667505caca 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -468,7 +468,6 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
/***************************** Public API *****************************/
-/* Allocate, initialize, and assign a new BMLog */
BMLog *BM_log_create(BMesh *bm)
{
BMLog *log = MEM_callocN(sizeof(*log), __func__);
@@ -506,14 +505,6 @@ void BM_log_cleanup_entry(BMLogEntry *entry)
}
}
-/* Allocate and initialize a new BMLog using existing BMLogEntries
- *
- * The 'entry' should be the last entry in the BMLog. Its prev pointer
- * will be followed back to find the first entry.
- *
- * The unused IDs field of the log will be initialized by taking all
- * keys from all GHashes in the log entry.
- */
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
{
BMLog *log = BM_log_create(bm);
@@ -555,7 +546,6 @@ BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
return log;
}
-/* Free all the data in a BMLog including the log itself */
void BM_log_free(BMLog *log)
{
BMLogEntry *entry;
@@ -581,13 +571,11 @@ void BM_log_free(BMLog *log)
MEM_freeN(log);
}
-/* Get the number of log entries */
int BM_log_length(const BMLog *log)
{
return BLI_listbase_count(&log->entries);
}
-/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
{
uint *varr;
@@ -639,16 +627,6 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
MEM_freeN(farr);
}
-/* Start a new log entry and update the log entry list
- *
- * If the log entry list is empty, or if the current log entry is the
- * last entry, the new entry is simply appended to the end.
- *
- * Otherwise, the new entry is added after the current entry and all
- * following entries are deleted.
- *
- * In either case, the new entry is set as the current log entry.
- */
BMLogEntry *BM_log_entry_add(BMLog *log)
{
/* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
@@ -676,15 +654,6 @@ BMLogEntry *BM_log_entry_add(BMLog *log)
return entry;
}
-/* Remove an entry from the log
- *
- * Uses entry->log as the log. If the log is NULL, the entry will be
- * free'd but not removed from any list, nor shall its IDs be
- * released.
- *
- * This operation is only valid on the first and last entries in the
- * log. Deleting from the middle will assert.
- */
void BM_log_entry_drop(BMLogEntry *entry)
{
BMLog *log = entry->log;
@@ -751,9 +720,6 @@ void BM_log_entry_drop(BMLogEntry *entry)
BLI_freelinkN(&log->entries, entry);
}
-/* Undo one BMLogEntry
- *
- * Has no effect if there's nothing left to undo */
void BM_log_undo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
@@ -775,9 +741,6 @@ void BM_log_undo(BMesh *bm, BMLog *log)
}
}
-/* Redo one BMLogEntry
- *
- * Has no effect if there's nothing left to redo */
void BM_log_redo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
@@ -812,29 +775,6 @@ void BM_log_redo(BMesh *bm, BMLog *log)
}
}
-/* Log a vertex before it is modified
- *
- * Before modifying vertex coordinates, masks, or hflags, call this
- * function to log its current values. This is better than logging
- * after the coordinates have been modified, because only those
- * vertices that are modified need to have their original values
- * stored.
- *
- * Handles two separate cases:
- *
- * If the vertex was added in the current log entry, update the
- * vertex in the map of added vertices.
- *
- * If the vertex already existed prior to the current log entry, a
- * separate key/value map of modified vertices is used (using the
- * vertex's ID as the key). The values stored in that case are
- * the vertex's original state so that an undo can restore the
- * previous state.
- *
- * On undo, the current vertex state will be swapped with the stored
- * state so that a subsequent redo operation will restore the newer
- * vertex state.
- */
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
@@ -853,12 +793,6 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
}
}
-/* Log a new vertex as added to the BMesh
- *
- * The new vertex gets a unique ID assigned. It is then added to a map
- * of added vertices, with the key being its ID and the value
- * containing everything needed to reconstruct that vertex.
- */
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogVert *lv;
@@ -870,11 +804,6 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
BLI_ghash_insert(log->current_entry->added_verts, key, lv);
}
-/* Log a face before it is modified
- *
- * This is intended to handle only header flags and we always
- * assume face has been added before
- */
void BM_log_face_modified(BMLog *log, BMFace *f)
{
BMLogFace *lf;
@@ -885,12 +814,6 @@ void BM_log_face_modified(BMLog *log, BMFace *f)
BLI_ghash_insert(log->current_entry->modified_faces, key, lf);
}
-/* Log a new face as added to the BMesh
- *
- * The new face gets a unique ID assigned. It is then added to a map
- * of added faces, with the key being its ID and the value containing
- * everything needed to reconstruct that face.
- */
void BM_log_face_added(BMLog *log, BMFace *f)
{
BMLogFace *lf;
@@ -905,22 +828,6 @@ void BM_log_face_added(BMLog *log, BMFace *f)
BLI_ghash_insert(log->current_entry->added_faces, key, lf);
}
-/* Log a vertex as removed from the BMesh
- *
- * A couple things can happen here:
- *
- * If the vertex was added as part of the current log entry, then it's
- * deleted and forgotten about entirely. Its unique ID is returned to
- * the unused pool.
- *
- * If the vertex was already part of the BMesh before the current log
- * entry, it is added to a map of deleted vertices, with the key being
- * its ID and the value containing everything needed to reconstruct
- * that vertex.
- *
- * If there's a move record for the vertex, that's used as the
- * vertices original location, then the move record is deleted.
- */
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
@@ -949,19 +856,6 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
}
}
-/* Log a face as removed from the BMesh
- *
- * A couple things can happen here:
- *
- * If the face was added as part of the current log entry, then it's
- * deleted and forgotten about entirely. Its unique ID is returned to
- * the unused pool.
- *
- * If the face was already part of the BMesh before the current log
- * entry, it is added to a map of deleted faces, with the key being
- * its ID and the value containing everything needed to reconstruct
- * that face.
- */
void BM_log_face_removed(BMLog *log, BMFace *f)
{
BMLogEntry *entry = log->current_entry;
@@ -983,7 +877,6 @@ void BM_log_face_removed(BMLog *log, BMFace *f)
}
}
-/* Log all vertices/faces in the BMesh as added */
void BM_log_all_added(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@@ -1011,7 +904,6 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
}
}
-/* Log all vertices/faces in the BMesh as removed */
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@@ -1030,9 +922,6 @@ void BM_log_before_all_removed(BMesh *bm, BMLog *log)
}
}
-/* Get the logged coordinates of a vertex
- *
- * Does not modify the log or the vertex */
const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
@@ -1048,9 +937,6 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
return lv->co;
}
-/* Get the logged normal of a vertex
- *
- * Does not modify the log or the vertex */
const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
@@ -1066,9 +952,6 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
return lv->no;
}
-/* Get the logged mask of a vertex
- *
- * Does not modify the log or the vertex */
float BM_log_original_mask(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
@@ -1102,13 +985,11 @@ void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const
/************************ Debugging and Testing ***********************/
-/* For internal use only (unit testing) */
BMLogEntry *BM_log_current_entry(BMLog *log)
{
return log->current_entry;
}
-/* For internal use only (unit testing) */
RangeTreeUInt *BM_log_unused_ids(BMLog *log)
{
return log->unused_ids;
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 5c0ca78bddf..c6df87168ee 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -29,71 +29,190 @@ typedef struct BMLog BMLog;
typedef struct BMLogEntry BMLogEntry;
/* Allocate and initialize a new BMLog */
+/* Allocate, initialize, and assign a new BMLog */
BMLog *BM_log_create(BMesh *bm);
/* Allocate and initialize a new BMLog using existing BMLogEntries */
+/* Allocate and initialize a new BMLog using existing BMLogEntries
+ *
+ * The 'entry' should be the last entry in the BMLog. Its prev pointer
+ * will be followed back to find the first entry.
+ *
+ * The unused IDs field of the log will be initialized by taking all
+ * keys from all GHashes in the log entry.
+ */
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry);
/* Free all the data in a BMLog including the log itself */
+/* Free all the data in a BMLog including the log itself */
void BM_log_free(BMLog *log);
/* Get the number of log entries */
+/* Get the number of log entries */
int BM_log_length(const BMLog *log);
/* Apply a consistent ordering to BMesh vertices and faces */
+/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log);
/* Start a new log entry and update the log entry list */
+/* Start a new log entry and update the log entry list
+ *
+ * If the log entry list is empty, or if the current log entry is the
+ * last entry, the new entry is simply appended to the end.
+ *
+ * Otherwise, the new entry is added after the current entry and all
+ * following entries are deleted.
+ *
+ * In either case, the new entry is set as the current log entry.
+ */
BMLogEntry *BM_log_entry_add(BMLog *log);
/* Mark all used ids as unused for this node */
void BM_log_cleanup_entry(BMLogEntry *entry);
/* Remove an entry from the log */
+/* Remove an entry from the log
+ *
+ * Uses entry->log as the log. If the log is NULL, the entry will be
+ * free'd but not removed from any list, nor shall its IDs be
+ * released.
+ *
+ * This operation is only valid on the first and last entries in the
+ * log. Deleting from the middle will assert.
+ */
void BM_log_entry_drop(BMLogEntry *entry);
/* Undo one BMLogEntry */
+/* Undo one BMLogEntry
+ *
+ * Has no effect if there's nothing left to undo */
void BM_log_undo(BMesh *bm, BMLog *log);
/* Redo one BMLogEntry */
+/* Redo one BMLogEntry
+ *
+ * Has no effect if there's nothing left to redo */
void BM_log_redo(BMesh *bm, BMLog *log);
/* Log a vertex before it is modified */
+/* Log a vertex before it is modified
+ *
+ * Before modifying vertex coordinates, masks, or hflags, call this
+ * function to log its current values. This is better than logging
+ * after the coordinates have been modified, because only those
+ * vertices that are modified need to have their original values
+ * stored.
+ *
+ * Handles two separate cases:
+ *
+ * If the vertex was added in the current log entry, update the
+ * vertex in the map of added vertices.
+ *
+ * If the vertex already existed prior to the current log entry, a
+ * separate key/value map of modified vertices is used (using the
+ * vertex's ID as the key). The values stored in that case are
+ * the vertex's original state so that an undo can restore the
+ * previous state.
+ *
+ * On undo, the current vertex state will be swapped with the stored
+ * state so that a subsequent redo operation will restore the newer
+ * vertex state.
+ */
void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
/* Log a new vertex as added to the BMesh */
+/* Log a new vertex as added to the BMesh
+ *
+ * The new vertex gets a unique ID assigned. It is then added to a map
+ * of added vertices, with the key being its ID and the value
+ * containing everything needed to reconstruct that vertex.
+ */
void BM_log_vert_added(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
/* Log a face before it is modified */
+/* Log a face before it is modified
+ *
+ * This is intended to handle only header flags and we always
+ * assume face has been added before
+ */
void BM_log_face_modified(BMLog *log, struct BMFace *f);
/* Log a new face as added to the BMesh */
+/* Log a new face as added to the BMesh
+ *
+ * The new face gets a unique ID assigned. It is then added to a map
+ * of added faces, with the key being its ID and the value containing
+ * everything needed to reconstruct that face.
+ */
void BM_log_face_added(BMLog *log, struct BMFace *f);
/* Log a vertex as removed from the BMesh */
+/* Log a vertex as removed from the BMesh
+ *
+ * A couple things can happen here:
+ *
+ * If the vertex was added as part of the current log entry, then it's
+ * deleted and forgotten about entirely. Its unique ID is returned to
+ * the unused pool.
+ *
+ * If the vertex was already part of the BMesh before the current log
+ * entry, it is added to a map of deleted vertices, with the key being
+ * its ID and the value containing everything needed to reconstruct
+ * that vertex.
+ *
+ * If there's a move record for the vertex, that's used as the
+ * vertices original location, then the move record is deleted.
+ */
void BM_log_vert_removed(BMLog *log, struct BMVert *v, const int cd_vert_mask_offset);
/* Log a face as removed from the BMesh */
+/* Log a face as removed from the BMesh
+ *
+ * A couple things can happen here:
+ *
+ * If the face was added as part of the current log entry, then it's
+ * deleted and forgotten about entirely. Its unique ID is returned to
+ * the unused pool.
+ *
+ * If the face was already part of the BMesh before the current log
+ * entry, it is added to a map of deleted faces, with the key being
+ * its ID and the value containing everything needed to reconstruct
+ * that face.
+ */
void BM_log_face_removed(BMLog *log, struct BMFace *f);
/* Log all vertices/faces in the BMesh as added */
+/* Log all vertices/faces in the BMesh as added */
void BM_log_all_added(BMesh *bm, BMLog *log);
/* Log all vertices/faces in the BMesh as removed */
+/* Log all vertices/faces in the BMesh as removed */
void BM_log_before_all_removed(BMesh *bm, BMLog *log);
/* Get the logged coordinates of a vertex */
+/* Get the logged coordinates of a vertex
+ *
+ * Does not modify the log or the vertex */
const float *BM_log_original_vert_co(BMLog *log, BMVert *v);
/* Get the logged normal of a vertex */
+/* Get the logged normal of a vertex
+ *
+ * Does not modify the log or the vertex */
const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
/* Get the logged mask of a vertex */
+/* Get the logged mask of a vertex
+ *
+ * Does not modify the log or the vertex */
float BM_log_original_mask(BMLog *log, BMVert *v);
/* Get the logged data of a vertex (avoid multiple lookups) */
void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const short **r_no);
/* For internal use only (unit testing) */
+/* For internal use only (unit testing) */
BMLogEntry *BM_log_current_entry(BMLog *log);
+/* For internal use only (unit testing) */
struct RangeTreeUInt *BM_log_unused_ids(BMLog *log);
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index b70e26f51ea..b756aa25edd 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -251,14 +251,6 @@ static bool bm_edge_is_face_visible_any(const BMEdge *e)
/** \} */
-/**
- * \brief Select Mode Clean
- *
- * Remove isolated selected elements when in a mode doesn't support them.
- * eg: in edge-mode a selected vertex must be connected to a selected edge.
- *
- * \note this could be made a part of #BM_mesh_select_mode_flush_ex
- */
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
{
if (selectmode & SCE_SELECT_VERTEX) {
@@ -424,13 +416,6 @@ static void bm_mesh_select_mode_flush_edge_to_face(BMesh *bm)
bm->totfacesel += chunk_data.delta_selection_len;
}
-/**
- * \brief Select Mode Flush
- *
- * Makes sure to flush selections 'upwards'
- * (ie: all verts of an edge selects the edge and so on).
- * This should only be called by system and not tool authors.
- */
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
{
if (selectmode & SCE_SELECT_VERTEX) {
@@ -463,9 +448,6 @@ void BM_mesh_select_mode_flush(BMesh *bm)
/** \} */
-/**
- * mode independent flushing up/down
- */
void BM_mesh_deselect_flush(BMesh *bm)
{
BMIter eiter;
@@ -498,9 +480,6 @@ void BM_mesh_deselect_flush(BMesh *bm)
recount_totsels(bm);
}
-/**
- * mode independent flushing up/down
- */
void BM_mesh_select_flush(BMesh *bm)
{
BMEdge *e;
@@ -542,12 +521,6 @@ void BM_mesh_select_flush(BMesh *bm)
recount_totsels(bm);
}
-/**
- * \brief Select Vert
- *
- * Changes selection state of a single vertex
- * in a mesh
- */
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
{
BLI_assert(v->head.htype == BM_VERT);
@@ -570,11 +543,6 @@ void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
}
}
-/**
- * \brief Select Edge
- *
- * Changes selection state of a single edge in a mesh.
- */
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
{
BLI_assert(e->head.htype == BM_EDGE);
@@ -615,12 +583,6 @@ void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
}
}
-/**
- * \brief Select Face
- *
- * Changes selection state of a single
- * face in a mesh.
- */
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
{
BMLoop *l_iter;
@@ -746,12 +708,6 @@ void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
/** \} */
-/**
- * Select Mode Set
- *
- * Sets the selection mode for the bmesh,
- * updating the selection state.
- */
void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
{
BMIter iter;
@@ -867,10 +823,6 @@ int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
}
-/**
- * \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
- * \note by design, this will not touch the editselection history stuff
- */
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
{
switch (ele->head.htype) {
@@ -889,7 +841,6 @@ void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
}
}
-/* this replaces the active flag used in uv/face mode */
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
{
bm->act_face = f;
@@ -974,15 +925,6 @@ BMElem *BM_mesh_active_elem_get(BMesh *bm)
return NULL;
}
-/**
- * Generic way to get data from an EditSelection type
- * These functions were written to be used by the Modifier widget
- * when in Rotate about active mode, but can be used anywhere.
- *
- * - #BM_editselection_center
- * - #BM_editselection_normal
- * - #BM_editselection_plane
- */
void BM_editselection_center(BMEditSelection *ese, float r_center[3])
{
if (ese->htype == BM_VERT) {
@@ -1027,11 +969,6 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
}
}
-/**
- * Calculate a plane that is right angles to the edge/vert/faces normal
- * also make the plane run along an axis that is related to the geometry,
- * because this is used for the gizmos Y axis.
- */
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
{
if (ese->htype == BM_VERT) {
@@ -1098,6 +1035,7 @@ static BMEditSelection *bm_select_history_create(BMHeader *ele)
}
/* --- macro wrapped funcs --- */
+
bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
{
return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
@@ -1170,9 +1108,6 @@ void BM_select_history_validate(BMesh *bm)
}
}
-/**
- * Get the active mesh element (with active-face fallback).
- */
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
{
BMEditSelection *ese_last = bm->selected.last;
@@ -1209,9 +1144,6 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
return true;
}
-/**
- * Return a map from BMVert/Edge/Face -> BMEditSelection
- */
GHash *BM_select_history_map_create(BMesh *bm)
{
BMEditSelection *ese;
@@ -1230,9 +1162,6 @@ GHash *BM_select_history_map_create(BMesh *bm)
return map;
}
-/**
- * Map arguments may all be the same pointer.
- */
void BM_select_history_merge_from_targetmap(
BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
{
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 99feae1d66c..72b520cc72c 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -36,14 +36,20 @@ typedef enum eBMSelectionFlushFLags {
BM_SELECT_LEN_FLUSH_RECALC_FACE),
} eBMSelectionFlushFLags;
-/* geometry hiding code */
+/* Geometry hiding code. */
+
#define BM_elem_hide_set(bm, ele, hide) _bm_elem_hide_set(bm, &(ele)->head, hide)
void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide);
void BM_vert_hide_set(BMVert *v, const bool hide);
void BM_edge_hide_set(BMEdge *e, const bool hide);
void BM_face_hide_set(BMFace *f, const bool hide);
-/* Selection code */
+/* Selection code. */
+
+/**
+ * \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
+ * \note by design, this will not touch the editselection history stuff
+ */
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select);
void BM_mesh_elem_hflag_enable_test(BMesh *bm,
@@ -68,24 +74,70 @@ void BM_mesh_elem_hflag_disable_all(BMesh *bm,
const char hflag,
const bool respecthide);
-/* Individual element select functions, BM_elem_select_set is a shortcut for these
+/* Individual element select functions, #BM_elem_select_set is a shortcut for these
* that automatically detects which one to use. */
+
+/**
+ * \brief Select Vert
+ *
+ * Changes selection state of a single vertex
+ * in a mesh
+ */
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select);
+/**
+ * \brief Select Edge
+ *
+ * Changes selection state of a single edge in a mesh.
+ */
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select);
+/**
+ * \brief Select Face
+ *
+ * Changes selection state of a single
+ * face in a mesh.
+ */
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select);
-/* lower level functions which don't do flushing */
+/* Lower level functions which don't do flushing. */
+
void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select);
void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select);
+/**
+ * \brief Select Mode Clean
+ *
+ * Remove isolated selected elements when in a mode doesn't support them.
+ * eg: in edge-mode a selected vertex must be connected to a selected edge.
+ *
+ * \note this could be made a part of #BM_mesh_select_mode_flush_ex
+ */
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode);
void BM_mesh_select_mode_clean(BMesh *bm);
+/**
+ * Select Mode Set
+ *
+ * Sets the selection mode for the bmesh,
+ * updating the selection state.
+ */
void BM_mesh_select_mode_set(BMesh *bm, int selectmode);
+/**
+ * \brief Select Mode Flush
+ *
+ * Makes sure to flush selections 'upwards'
+ * (ie: all verts of an edge selects the edge and so on).
+ * This should only be called by system and not tool authors.
+ */
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags);
void BM_mesh_select_mode_flush(BMesh *bm);
+/**
+ * Mode independent de-selection flush (up/down).
+ */
void BM_mesh_deselect_flush(BMesh *bm);
+/**
+ * Mode independent selection flush (up/down).
+ */
void BM_mesh_select_flush(BMesh *bm);
int BM_mesh_elem_hflag_count_enabled(BMesh *bm,
@@ -97,15 +149,30 @@ int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
const char hflag,
const bool respecthide);
-/* edit selection stuff */
+/* Edit selection stuff. */
+
void BM_mesh_active_face_set(BMesh *bm, BMFace *f);
BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected);
BMEdge *BM_mesh_active_edge_get(BMesh *bm);
BMVert *BM_mesh_active_vert_get(BMesh *bm);
BMElem *BM_mesh_active_elem_get(BMesh *bm);
+/**
+ * Generic way to get data from an #BMEditSelection type
+ * These functions were written to be used by the Modifier widget
+ * when in Rotate about active mode, but can be used anywhere.
+ *
+ * - #BM_editselection_center
+ * - #BM_editselection_normal
+ * - #BM_editselection_plane
+ */
void BM_editselection_center(BMEditSelection *ese, float r_center[3]);
void BM_editselection_normal(BMEditSelection *ese, float r_normal[3]);
+/**
+ * Calculate a plane that is right angles to the edge/vert/faces normal
+ * also make the plane run along an axis that is related to the geometry,
+ * because this is used for the gizmos Y axis.
+ */
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]);
#define BM_select_history_check(bm, ele) _bm_select_history_check(bm, &(ele)->head)
@@ -131,9 +198,18 @@ void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref,
void BM_select_history_validate(BMesh *bm);
void BM_select_history_clear(BMesh *bm);
+/**
+ * Get the active mesh element (with active-face fallback).
+ */
bool BM_select_history_active_get(BMesh *bm, struct BMEditSelection *ese);
+/**
+ * Return a map from #BMVert/#BMEdge/#BMFace -> #BMEditSelection.
+ */
struct GHash *BM_select_history_map_create(BMesh *bm);
+/**
+ * Map arguments may all be the same pointer.
+ */
void BM_select_history_merge_from_targetmap(
BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain);
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index b2958a9e744..ad52daa4731 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -34,7 +34,6 @@
#include "bmesh.h"
-/* used as an extern, defined in bmesh.h */
const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
@@ -137,15 +136,6 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm)
}
}
-/**
- * \brief BMesh Make Mesh
- *
- * Allocates a new BMesh structure.
- *
- * \return The New bmesh
- *
- * \note ob is needed by multires
- */
BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
{
/* allocate the structure */
@@ -167,13 +157,6 @@ BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreate
return bm;
}
-/**
- * \brief BMesh Free Mesh Data
- *
- * Frees a BMesh structure.
- *
- * \note frees mesh, but not actual BMesh struct
- */
void BM_mesh_data_free(BMesh *bm)
{
BMVert *v;
@@ -265,11 +248,6 @@ void BM_mesh_data_free(BMesh *bm)
BMO_error_clear(bm);
}
-/**
- * \brief BMesh Clear Mesh
- *
- * Clear all data in bm
- */
void BM_mesh_clear(BMesh *bm)
{
const bool use_toolflags = bm->use_toolflags;
@@ -291,11 +269,6 @@ void BM_mesh_clear(BMesh *bm)
CustomData_reset(&bm->pdata);
}
-/**
- * \brief BMesh Free Mesh
- *
- * Frees a BMesh data and its structure.
- */
void BM_mesh_free(BMesh *bm)
{
BM_mesh_data_free(bm);
@@ -310,13 +283,6 @@ void BM_mesh_free(BMesh *bm)
MEM_freeN(bm);
}
-/**
- * \brief BMesh Begin Edit
- *
- * Functions for setting up a mesh for editing and cleaning up after
- * the editing operations are done. These are called by the tools/operator
- * API for each time a tool is executed.
- */
void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
{
/* Most operators seem to be using BMO_OPTYPE_FLAG_UNTAN_MULTIRES to change the MDisps to
@@ -337,9 +303,6 @@ void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
#endif
}
-/**
- * \brief BMesh End Edit
- */
void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
{
ListBase select_history;
@@ -499,18 +462,6 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BM_mesh_elem_index_ensure_ex(bm, htype, NULL);
}
-/**
- * Array checking/setting macros
- *
- * Currently vert/edge/loop/face index data is being abused, in a few areas of the code.
- *
- * To avoid correcting them afterwards, set 'bm->elem_index_dirty' however its possible
- * this flag is set incorrectly which could crash blender.
- *
- * Code that calls this functions may depend on dirty indices on being set.
- * Keep this function read-only.
- */
-
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b)
{
@@ -693,7 +644,6 @@ finally:
bm->elem_table_dirty &= ~htype_needed;
}
-/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
{
BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
@@ -754,11 +704,6 @@ BMLoop *BM_loop_at_index_find(BMesh *bm, const int index)
return NULL;
}
-/**
- * Use lookup table when available, else use slower find functions.
- *
- * \note Try to use #BM_mesh_elem_table_ensure instead.
- */
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index)
{
if ((bm->elem_table_dirty & BM_VERT) == 0) {
@@ -783,9 +728,6 @@ BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index)
return BM_face_at_index_find(bm, index);
}
-/**
- * Return the amount of element of type 'type' in a given bmesh.
- */
int BM_mesh_elem_count(BMesh *bm, const char htype)
{
BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
@@ -804,20 +746,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
}
}
-/**
- * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
- * (xxx_idx[org_index] = new_index).
- *
- * A NULL array means no changes.
- *
- * \note
- * - Does not mess with indices, just sets elem_index_dirty flag.
- * - For verts/edges/faces only (as loops must remain "ordered" and "aligned"
- * on a per-face basis...).
- *
- * \warning Be careful if you keep pointers to affected BM elements,
- * or arrays, when using this func!
- */
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
{
/* Mapping old to new pointers. */
@@ -1106,12 +1034,6 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
}
}
-/**
- * Use new memory pools for this mesh.
- *
- * \note needed for re-sizing elements (adding/removing tool flags)
- * but could also be used for packing fragmented bmeshes.
- */
void BM_mesh_rebuild(BMesh *bm,
const struct BMeshCreateParams *params,
BLI_mempool *vpool_dst,
@@ -1363,9 +1285,6 @@ void BM_mesh_rebuild(BMesh *bm,
}
}
-/**
- * Re-allocates mesh data with/without toolflags.
- */
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
{
if (bm->use_toolflags == use_toolflags) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index bd0504b038a..e00461ba571 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -34,28 +34,83 @@ struct BMeshCreateParams {
uint use_toolflags : 1;
};
+/**
+ * \brief BMesh Make Mesh
+ *
+ * Allocates a new BMesh structure.
+ *
+ * \return The New bmesh
+ *
+ * \note ob is needed by multires
+ */
BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize,
const struct BMeshCreateParams *params);
+/**
+ * \brief BMesh Free Mesh
+ *
+ * Frees a BMesh data and its structure.
+ */
void BM_mesh_free(BMesh *bm);
+/**
+ * \brief BMesh Free Mesh Data
+ *
+ * Frees a BMesh structure.
+ *
+ * \note frees mesh, but not actual BMesh struct
+ */
void BM_mesh_data_free(BMesh *bm);
+/**
+ * \brief BMesh Clear Mesh
+ *
+ * Clear all data in bm
+ */
void BM_mesh_clear(BMesh *bm);
+/**
+ * \brief BMesh Begin Edit
+ *
+ * Functions for setting up a mesh for editing and cleaning up after
+ * the editing operations are done. These are called by the tools/operator
+ * API for each time a tool is executed.
+ */
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
+/**
+ * \brief BMesh End Edit
+ */
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4]);
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype);
+/**
+ * Array checking/setting macros.
+ *
+ * Currently vert/edge/loop/face index data is being abused, in a few areas of the code.
+ *
+ * To avoid correcting them afterwards, set 'bm->elem_index_dirty' however its possible
+ * this flag is set incorrectly which could crash blender.
+ *
+ * Functions that calls this function may depend on dirty indices on being set.
+ *
+ * This is read-only, so it can be used for assertions that don't impact behavior.
+ */
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b);
-void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
-
#ifndef NDEBUG
+/**
+ * \see #BM_mesh_elem_index_validate the same rationale applies to this function.
+ */
bool BM_mesh_elem_table_check(BMesh *bm);
#endif
+/**
+ * Re-allocates mesh data with/without toolflags.
+ */
+void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
+
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype);
+/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
void BM_mesh_elem_table_init(BMesh *bm, const char htype);
void BM_mesh_elem_table_free(BMesh *bm, const char htype);
@@ -83,16 +138,44 @@ BMEdge *BM_edge_at_index_find(BMesh *bm, const int index);
BMFace *BM_face_at_index_find(BMesh *bm, const int index);
BMLoop *BM_loop_at_index_find(BMesh *bm, const int index);
+/**
+ * Use lookup table when available, else use slower find functions.
+ *
+ * \note Try to use #BM_mesh_elem_table_ensure instead.
+ */
BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index);
BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index);
BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index);
// XXX
+/**
+ * Return the amount of element of type 'type' in a given bmesh.
+ */
int BM_mesh_elem_count(BMesh *bm, const char htype);
+/**
+ * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
+ * (xxx_idx[org_index] = new_index).
+ *
+ * A NULL array means no changes.
+ *
+ * \note
+ * - Does not mess with indices, just sets elem_index_dirty flag.
+ * - For verts/edges/faces only (as loops must remain "ordered" and "aligned"
+ * on a per-face basis...).
+ *
+ * \warning Be careful if you keep pointers to affected BM elements,
+ * or arrays, when using this func!
+ */
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx);
+/**
+ * Use new memory pools for this mesh.
+ *
+ * \note needed for re-sizing elements (adding/removing tool flags)
+ * but could also be used for packing fragmented bmeshes.
+ */
void BM_mesh_rebuild(BMesh *bm,
const struct BMeshCreateParams *params,
struct BLI_mempool *vpool,
@@ -104,6 +187,7 @@ typedef struct BMAllocTemplate {
int totvert, totedge, totloop, totface;
} BMAllocTemplate;
+/* used as an extern, defined in bmesh.h */
extern const BMAllocTemplate bm_mesh_allocsize_default;
extern const BMAllocTemplate bm_mesh_chunksize_default;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c
index 9d29a90a7a4..544a81f7020 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c
@@ -176,16 +176,6 @@ static BMFace *bm_face_create_from_mpoly(
return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
}
-/**
- * \brief Mesh -> BMesh
- * \param bm: The mesh to write into, while this is typically a newly created BMesh,
- * merging into existing data is supported.
- * Note the custom-data layout isn't used.
- * If more comprehensive merging is needed we should move this into a separate function
- * since this should be kept fast for edit-mode switching and storing undo steps.
- *
- * \warning This function doesn't calculate face normals.
- */
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
{
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
@@ -582,10 +572,6 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
}
}
-/**
- *
- * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
- */
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
{
MEdge *med;
@@ -1005,23 +991,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BKE_mesh_runtime_clear_geometry(me);
}
-/**
- * A version of #BM_mesh_bm_to_me intended for getting the mesh
- * to pass to the modifier stack for evaluation,
- * instead of mode switching (where we make sure all data is kept
- * and do expensive lookups to maintain shape keys).
- *
- * Key differences:
- *
- * - Don't support merging with existing mesh.
- * - Ignore shape-keys.
- * - Ignore vertex-parents.
- * - Ignore selection history.
- * - Uses simpler method to calculate #ME_EDGEDRAW
- * - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
- *
- * \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
- */
void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra)
{
/* Must be an empty mesh. */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h
index 1b5d001d35d..ea114487285 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h
@@ -43,6 +43,16 @@ struct BMeshFromMeshParams {
int active_shapekey;
struct CustomData_MeshMasks cd_mask_extra;
};
+/**
+ * \brief Mesh -> BMesh
+ * \param bm: The mesh to write into, while this is typically a newly created BMesh,
+ * merging into existing data is supported.
+ * Note the custom-data layout isn't used.
+ * If more comprehensive merging is needed we should move this into a separate function
+ * since this should be kept fast for edit-mode switching and storing undo steps.
+ *
+ * \warning This function doesn't calculate face normals.
+ */
void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFromMeshParams *params)
ATTR_NONNULL(1, 3);
@@ -61,11 +71,32 @@ struct BMeshToMeshParams {
uint update_shapekey_indices : 1;
struct CustomData_MeshMasks cd_mask_extra;
};
+/**
+ *
+ * \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
+ */
void BM_mesh_bm_to_me(struct Main *bmain,
BMesh *bm,
struct Mesh *me,
const struct BMeshToMeshParams *params) ATTR_NONNULL(2, 3, 4);
+/**
+ * A version of #BM_mesh_bm_to_me intended for getting the mesh
+ * to pass to the modifier stack for evaluation,
+ * instead of mode switching (where we make sure all data is kept
+ * and do expensive lookups to maintain shape keys).
+ *
+ * Key differences:
+ *
+ * - Don't support merging with existing mesh.
+ * - Ignore shape-keys.
+ * - Ignore vertex-parents.
+ * - Ignore selection history.
+ * - Uses simpler method to calculate #ME_EDGEDRAW
+ * - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
+ *
+ * \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
+ */
void BM_mesh_bm_to_me_for_eval(BMesh *bm,
struct Mesh *me,
const struct CustomData_MeshMasks *cd_mask_extra)
diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.c b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
index 1d393abcd56..db21e50bb71 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c
@@ -85,9 +85,6 @@ static BMFace *bm_face_copy_with_arrays(
return f_dst;
}
-/**
- * Geometry must be completely isolated.
- */
void BM_mesh_copy_arrays(BMesh *bm_src,
BMesh *bm_dst,
BMVert **verts_src,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.h b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
index 8ace555d61f..d15ef8f4ab2 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h
@@ -20,6 +20,9 @@
* \ingroup bmesh
*/
+/**
+ * Geometry must be completely isolated.
+ */
void BM_mesh_copy_arrays(BMesh *bm_src,
BMesh *bm_dst,
BMVert **verts_src,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c
index 8119d9eb57d..34c07b4f310 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c
@@ -247,11 +247,6 @@ static void bm_face_calc_normals_cb(void *UNUSED(userdata),
BM_face_calc_normal(f, f->no);
}
-/**
- * \brief BMesh Compute Normals
- *
- * Updates the normals of a mesh.
- */
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params)
{
if (params->face_normals) {
@@ -295,10 +290,6 @@ static void bm_partial_verts_parallel_range_calc_normal_cb(
bm_vert_calc_normals_impl(v);
}
-/**
- * A version of #BM_mesh_normals_update that updates a subset of geometry,
- * used to avoid the overhead of updating everything.
- */
void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm),
const BMPartialUpdate *bmpinfo,
const struct BMeshNormalsUpdate_Params *params)
@@ -343,12 +334,6 @@ void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpin
/** \name Update Vertex & Face Normals (Custom Coords)
* \{ */
-/**
- * \brief BMesh Compute Normals from/to external data.
- *
- * Computes the vertex normals of a mesh into vnos,
- * using given vertex coordinates (vcos) and polygon normals (fnos).
- */
void BM_verts_calc_normal_vcos(BMesh *bm,
const float (*fnos)[3],
const float (*vcos)[3],
@@ -435,12 +420,6 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm,
bm->elem_index_dirty &= ~BM_EDGE;
}
-/**
- * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
- *
- * Used when defining an empty custom loop normals data layer,
- * to keep same shading as with auto-smooth!
- */
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
{
if (split_angle >= (float)M_PI) {
@@ -457,11 +436,6 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
/** \name Loop Normals Calculation API
* \{ */
-/**
- * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
- * Needed because cyclic smooth fans have no obvious 'entry point',
- * and yet we need to walk them once, and only once.
- */
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
{
BMLoop *lfan_pivot_next = l_curr;
@@ -520,7 +494,8 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
float (*r_lnos)[3],
MLoopNorSpaceArray *r_lnors_spacearr)
{
- BLI_assert((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) == 0);
+ BLI_assert((bm->elem_index_dirty & BM_LOOP) == 0);
+ BLI_assert((fnos == NULL) || ((bm->elem_index_dirty & BM_FACE) == 0));
BLI_assert((vcos == NULL) || ((bm->elem_index_dirty & BM_VERT) == 0));
UNUSED_VARS_NDEBUG(bm);
@@ -1719,13 +1694,6 @@ static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm,
}
}
-/**
- * \brief BMesh Compute Loop Normals from/to external data.
- *
- * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
- * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
- * (splitting edges).
- */
void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
const float (*vnos)[3],
@@ -1932,10 +1900,6 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
#endif
}
-/**
- * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
- * take care to run this before setting up tags.
- */
void BM_lnorspace_update(BMesh *bm)
{
if (bm->lnor_spacearr == NULL) {
@@ -2249,10 +2213,6 @@ void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
/** \name Custom Normals / Vector Layer Conversion
* \{ */
-/**
- * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
- * take care to run this before setting up tags.
- */
bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
{
BMFace *f;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.h b/source/blender/bmesh/intern/bmesh_mesh_normals.h
index ecd627d4bfe..a2e64b1dc9b 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.h
@@ -30,17 +30,39 @@ struct BMeshNormalsUpdate_Params {
bool face_normals;
};
+/**
+ * \brief BMesh Compute Normals
+ *
+ * Updates the normals of a mesh.
+ */
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *param);
void BM_mesh_normals_update(BMesh *bm);
+/**
+ * A version of #BM_mesh_normals_update that updates a subset of geometry,
+ * used to avoid the overhead of updating everything.
+ */
void BM_mesh_normals_update_with_partial_ex(BMesh *bm,
const struct BMPartialUpdate *bmpinfo,
const struct BMeshNormalsUpdate_Params *param);
void BM_mesh_normals_update_with_partial(BMesh *bm, const struct BMPartialUpdate *bmpinfo);
+/**
+ * \brief BMesh Compute Normals from/to external data.
+ *
+ * Computes the vertex normals of a mesh into vnos,
+ * using given vertex coordinates (vcos) and polygon normals (fnos).
+ */
void BM_verts_calc_normal_vcos(BMesh *bm,
const float (*fnos)[3],
const float (*vcos)[3],
float (*vnos)[3]);
+/**
+ * \brief BMesh Compute Loop Normals from/to external data.
+ *
+ * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
+ * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
+ * (splitting edges).
+ */
void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
const float (*vnos)[3],
@@ -53,10 +75,19 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
const int cd_loop_clnors_offset,
const bool do_rebuild);
+/**
+ * Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
+ * Needed because cyclic smooth fans have no obvious 'entry point',
+ * and yet we need to walk them once, and only once.
+ */
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3]);
void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all);
void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor);
+/**
+ * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
+ * take care to run this before setting up tags.
+ */
void BM_lnorspace_update(BMesh *bm);
void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges);
#ifndef NDEBUG
@@ -68,7 +99,17 @@ struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm,
const bool do_all_loops_of_vert);
void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
+/**
+ * \warning This function sets #BM_ELEM_TAG on loops & edges via #bm_mesh_loops_calc_normals,
+ * take care to run this before setting up tags.
+ */
bool BM_custom_loop_normals_to_vector_layer(struct BMesh *bm);
void BM_custom_loop_normals_from_vector_layer(struct BMesh *bm, bool add_sharp_edges);
+/**
+ * Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
+ *
+ * Used when defining an empty custom loop normals data layer,
+ * to keep same shading as with auto-smooth!
+ */
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.c b/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
index 46fd2ad9a31..ad9b8414525 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.c
@@ -103,10 +103,6 @@ BLI_INLINE bool partial_elem_face_ensure(BMPartialUpdate *bmpinfo,
return false;
}
-/**
- * All Tagged & Connected, see: #BM_mesh_partial_create_from_verts
- * Operate on everything that's tagged as well as connected geometry.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
const BMPartialUpdate_Params *params,
const BLI_bitmap *verts_mask,
@@ -216,11 +212,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
return bmpinfo;
}
-/**
- * All Connected, operate on all faces that have both tagged and un-tagged vertices.
- *
- * Reduces computations when transforming isolated regions.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
BMesh *bm,
const BMPartialUpdate_Params *params,
@@ -314,25 +305,6 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
return bmpinfo;
}
-/**
- * All Connected, operate on all faces that have vertices in the same group.
- *
- * Reduces computations when transforming isolated regions.
- *
- * This is a version of #BM_mesh_partial_create_from_verts_group_single
- * that handles multiple groups instead of a bitmap mask.
- *
- * This is needed for example when transform has mirror enabled,
- * since one side needs to have a different group to the other since a face that has vertices
- * attached to both won't have an affine transformation.
- *
- * \param verts_groups: Vertex aligned array of groups.
- * Values are used as follows:
- * - >0: Each face is grouped with other faces of the same group.
- * - 0: Not in a group (don't handle these).
- * - -1: Don't use grouping logic (include any face that contains a vertex with this group).
- * \param verts_groups_count: The number of non-zero values in `verts_groups`.
- */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_multi(
BMesh *bm,
const BMPartialUpdate_Params *params,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
index cf4eab22836..57f57053606 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
@@ -52,18 +52,46 @@ typedef struct BMPartialUpdate {
BMPartialUpdate_Params params;
} BMPartialUpdate;
+/**
+ * All Tagged & Connected, see: #BM_mesh_partial_create_from_verts
+ * Operate on everything that's tagged as well as connected geometry.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
const BMPartialUpdate_Params *params,
const unsigned int *verts_mask,
const int verts_mask_count)
ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+/**
+ * All Connected, operate on all faces that have both tagged and un-tagged vertices.
+ *
+ * Reduces computations when transforming isolated regions.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
BMesh *bm,
const BMPartialUpdate_Params *params,
const unsigned int *verts_mask,
const int verts_mask_count) ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+/**
+ * All Connected, operate on all faces that have vertices in the same group.
+ *
+ * Reduces computations when transforming isolated regions.
+ *
+ * This is a version of #BM_mesh_partial_create_from_verts_group_single
+ * that handles multiple groups instead of a bitmap mask.
+ *
+ * This is needed for example when transform has mirror enabled,
+ * since one side needs to have a different group to the other since a face that has vertices
+ * attached to both won't have an affine transformation.
+ *
+ * \param verts_group: Vertex aligned array of groups.
+ * Values are used as follows:
+ * - >0: Each face is grouped with other faces of the same group.
+ * - 0: Not in a group (don't handle these).
+ * - -1: Don't use grouping logic (include any face that contains a vertex with this group).
+ * \param verts_group_count: The number of non-zero values in `verts_groups`.
+ */
BMPartialUpdate *BM_mesh_partial_create_from_verts_group_multi(
BMesh *bm,
const BMPartialUpdate_Params *params,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
index 9f477bc8a9c..94d8901edf8 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.c
@@ -549,9 +549,6 @@ static int bmesh_calc_tessellation_for_face_beauty(BMLoop *(*looptris)[3],
}
}
-/**
- * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
- */
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3])
{
#ifndef NDEBUG
diff --git a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
index 9a6a20d7568..91eac6bc6fc 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_tessellate.h
@@ -35,6 +35,9 @@ void BM_mesh_calc_tessellation_ex(BMesh *bm,
const struct BMeshCalcTessellation_Params *params);
void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3]);
+/**
+ * A version of #BM_mesh_calc_tessellation that avoids degenerate triangles.
+ */
void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3]);
void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm,
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c
index f8830e1557b..3145ceceafd 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c
@@ -50,12 +50,6 @@
(void)0
# endif
-/**
- * Check of this BMesh is valid,
- * this function can be slow since its intended to help with debugging.
- *
- * \return true when the mesh is valid.
- */
bool BM_mesh_validate(BMesh *bm)
{
EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, bm->totedge);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.h b/source/blender/bmesh/intern/bmesh_mesh_validate.h
index 2112e1f3200..203c8a89c55 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.h
@@ -23,4 +23,10 @@
* \ingroup bmesh
*/
+/**
+ * Check of this #BMesh is valid,
+ * this function can be slow since its intended to help with debugging.
+ *
+ * \return true when the mesh is valid.
+ */
bool BM_mesh_validate(BMesh *bm);
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 5fa12397a07..0a3857a6e0a 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -31,31 +31,6 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
-/**
- * \brief Dissolve Vert
- *
- * Turns the face region surrounding a manifold vertex into a single polygon.
- *
- * \par Example:
- * <pre>
- * +---------+ +---------+
- * | \ / | | |
- * Before: | v | After: | |
- * | / \ | | |
- * +---------+ +---------+
- * </pre>
- *
- * This function can also collapse edges too
- * in cases when it can't merge into faces.
- *
- * \par Example:
- * <pre>
- * Before: +----v----+ After: +---------+
- * </pre>
- *
- * \note dissolves vert, in more situations than BM_disk_dissolve
- * (e.g. if the vert is part of a wire edge, etc).
- */
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
{
/* logic for 3 or more is identical */
@@ -87,9 +62,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
return BM_disk_dissolve(bm, v);
}
-/**
- * dissolves all faces around a vert, and removes it.
- */
bool BM_disk_dissolve(BMesh *bm, BMVert *v)
{
BMEdge *e, *keepedge = NULL, *baseedge = NULL;
@@ -205,19 +177,6 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
return true;
}
-/**
- * \brief Faces Join Pair
- *
- * Joins two adjacent faces together.
- *
- * \note This method calls to #BM_faces_join to do its work.
- * This means connected edges which also share the two faces will be joined.
- *
- * If the windings do not match the winding of the new face will follow
- * \a l_a's winding (i.e. \a l_b will be reversed before the join).
- *
- * \return The combined face or NULL on failure.
- */
BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
{
BLI_assert((l_a != l_b) && (l_a->e == l_b->e));
@@ -231,24 +190,6 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_de
return BM_faces_join(bm, faces, 2, do_del);
}
-/**
- * \brief Face Split
- *
- * Split a face along two vertices. returns the newly made face, and sets
- * the \a r_l member to a loop in the newly created edge.
- *
- * \param bm: The bmesh
- * \param f: the original face
- * \param l_a, l_b: Loops of this face, their vertices define
- * the split edge to be created (must be differ and not can't be adjacent in the face).
- * \param r_l: pointer which will receive the BMLoop for the split edge in the new face
- * \param example: Edge used for attributes of splitting edge, if non-NULL
- * \param no_double: Use an existing edge if found
- *
- * \return Pointer to the newly created face representing one side of the split
- * if the split is successful (and the original face will be the other side).
- * NULL if the split fails.
- */
BMFace *BM_face_split(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -313,24 +254,6 @@ BMFace *BM_face_split(BMesh *bm,
return f_new;
}
-/**
- * \brief Face Split with intermediate points
- *
- * Like BM_face_split, but with an edge split by \a n intermediate points with given coordinates.
- *
- * \param bm: The bmesh.
- * \param f: the original face.
- * \param l_a, l_b: Vertices which define the split edge, must be different.
- * \param cos: Array of coordinates for intermediate points.
- * \param n: Length of \a cos (must be > 0).
- * \param r_l: pointer which will receive the BMLoop.
- * for the first split edge (from \a l_a) in the new face.
- * \param example: Edge used for attributes of splitting edge, if non-NULL.
- *
- * \return Pointer to the newly created face representing one side of the split
- * if the split is successful (and the original face will be the other side).
- * NULL if the split fails.
- */
BMFace *BM_face_split_n(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -404,29 +327,6 @@ BMFace *BM_face_split_n(BMesh *bm,
return f_new;
}
-/**
- * \brief Vert Collapse Faces
- *
- * Collapses vertex \a v_kill that has only two manifold edges
- * onto a vertex it shares an edge with.
- * \a fac defines the amount of interpolation for Custom Data.
- *
- * \note that this is not a general edge collapse function.
- *
- * \note this function is very close to #BM_vert_collapse_edge,
- * both collapse a vertex and return a new edge.
- * Except this takes a factor and merges custom data.
- *
- * \param bm: The bmesh
- * \param e_kill: The edge to collapse
- * \param v_kill: The vertex to collapse into the edge
- * \param fac: The factor along the edge
- * \param join_faces: When true the faces around the vertex will be joined
- * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
- * \param kill_degenerate_faces: Removes faces with less than 3 verts after collapsing.
- *
- * \returns The New Edge
- */
BMEdge *BM_vert_collapse_faces(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -513,13 +413,6 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
return e_new;
}
-/**
- * \brief Vert Collapse Faces
- *
- * Collapses a vertex onto another vertex it shares an edge with.
- *
- * \return The New Edge
- */
BMEdge *BM_vert_collapse_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -560,34 +453,12 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm,
#undef DO_V_INTERP
-/**
- * Collapse and edge into a single vertex.
- */
BMVert *BM_edge_collapse(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
{
return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
}
-/**
- * \brief Edge Split
- *
- * <pre>
- * Before: v
- * +-----------------------------------+
- * e
- *
- * After: v v_new (returned)
- * +-----------------+-----------------+
- * r_e e
- * </pre>
- *
- * \param e: The edge to split.
- * \param v: One of the vertices in \a e and defines the "from" end of the splitting operation,
- * the new vertex will be \a fac of the way from \a v to the other end.
- * \param r_e: The newly created edge.
- * \return The new vertex.
- */
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
{
BMVert *v_new, *v_other;
@@ -703,11 +574,6 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
return v_new;
}
-/**
- * \brief Split an edge multiple times evenly
- *
- * \param r_varr: Optional array, verts in between (v1 -> v2)
- */
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
{
int i;
@@ -725,11 +591,6 @@ BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr)
return v_new;
}
-/**
- * Swap v1 & v2
- *
- * \note Typically we shouldn't care about this, however it's used when extruding wire edges.
- */
void BM_edge_verts_swap(BMEdge *e)
{
SWAP(BMVert *, e->v1, e->v2);
@@ -785,20 +646,6 @@ bool BM_face_validate(BMFace *face, FILE *err)
}
#endif
-/**
- * Calculate the 2 loops which _would_ make up the newly rotated Edge
- * but don't actually change anything.
- *
- * Use this to further inspect if the loops to be connected have issues:
- *
- * Examples:
- * - the newly formed edge already exists
- * - the new face would be degenerate (zero area / concave / bow-tie)
- * - may want to measure if the new edge gives improved results topology.
- * over the old one, as with beauty fill.
- *
- * \note #BM_edge_rotate_check must have already run.
- */
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2)
{
BMVert *v1, *v2;
@@ -825,12 +672,6 @@ void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2
*r_l2 = BM_face_other_vert_loop(fa, v1, v2);
}
-/**
- * \brief Check if Rotate Edge is OK
- *
- * Quick check to see if we could rotate the edge,
- * use this to avoid calling exceptions on common cases.
- */
bool BM_edge_rotate_check(BMEdge *e)
{
BMFace *fa, *fb;
@@ -860,17 +701,6 @@ bool BM_edge_rotate_check(BMEdge *e)
return false;
}
-/**
- * \brief Check if Edge Rotate Gives Degenerate Faces
- *
- * Check 2 cases
- * 1) does the newly forms edge form a flipped face (compare with previous cross product)
- * 2) does the newly formed edge cause a zero area corner (or close enough to be almost zero)
- *
- * \param e: The edge to test rotation.
- * \param l1, l2: are the loops of the proposed verts to rotate too and should
- * be the result of calling #BM_edge_calc_rotate
- */
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2)
{
/* NOTE: for these vars 'old' just means initial edge state. */
@@ -966,20 +796,6 @@ bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2)
return (len_squared_v3v3(e->v1->co, e->v2->co) > len_squared_v3v3(l1->v->co, l2->v->co));
}
-/**
- * \brief Rotate Edge
- *
- * Spins an edge topologically,
- * either counter-clockwise or clockwise depending on \a ccw.
- *
- * \return The spun edge, NULL on error
- * (e.g., if the edge isn't surrounded by exactly two faces).
- *
- * \note This works by dissolving the edge then re-creating it,
- * so the returned edge won't have the same pointer address as the original one.
- *
- * \see header definition for \a check_flag enum.
- */
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
{
BMVert *v1, *v2;
@@ -1091,9 +907,6 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
return e_new;
}
-/**
- * \brief Rip a single face from a vertex fan
- */
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
{
return bmesh_kernel_unglue_region_make_vert(bm, l_sep);
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 4328187b95e..f4a5a0bce33 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -20,14 +20,73 @@
* \ingroup bmesh
*/
+/**
+ * \brief Dissolve Vert
+ *
+ * Turns the face region surrounding a manifold vertex into a single polygon.
+ *
+ * \par Example:
+ * <pre>
+ * +---------+ +---------+
+ * | \ / | | |
+ * Before: | v | After: | |
+ * | / \ | | |
+ * +---------+ +---------+
+ * </pre>
+ *
+ * This function can also collapse edges too
+ * in cases when it can't merge into faces.
+ *
+ * \par Example:
+ * <pre>
+ * Before: +----v----+ After: +---------+
+ * </pre>
+ *
+ * \note dissolves vert, in more situations than BM_disk_dissolve
+ * (e.g. if the vert is part of a wire edge, etc).
+ */
bool BM_vert_dissolve(BMesh *bm, BMVert *v);
+/**
+ * dissolves all faces around a vert, and removes it.
+ */
bool BM_disk_dissolve(BMesh *bm, BMVert *v);
+/**
+ * \brief Faces Join Pair
+ *
+ * Joins two adjacent faces together.
+ *
+ * \note This method calls to #BM_faces_join to do its work.
+ * This means connected edges which also share the two faces will be joined.
+ *
+ * If the windings do not match the winding of the new face will follow
+ * \a l_a's winding (i.e. \a l_b will be reversed before the join).
+ *
+ * \return The combined face or NULL on failure.
+ */
BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del);
/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
+/**
+ * \brief Face Split
+ *
+ * Split a face along two vertices. returns the newly made face, and sets
+ * the \a r_l member to a loop in the newly created edge.
+ *
+ * \param bm: The bmesh
+ * \param f: the original face
+ * \param l_a, l_b: Loops of this face, their vertices define
+ * the split edge to be created (must be differ and not can't be adjacent in the face).
+ * \param r_l: pointer which will receive the BMLoop for the split edge in the new face
+ * \param example: Edge used for attributes of splitting edge, if non-NULL
+ * \param no_double: Use an existing edge if found
+ *
+ * \return Pointer to the newly created face representing one side of the split
+ * if the split is successful (and the original face will be the other side).
+ * NULL if the split fails.
+ */
BMFace *BM_face_split(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -36,6 +95,24 @@ BMFace *BM_face_split(BMesh *bm,
BMEdge *example,
const bool no_double);
+/**
+ * \brief Face Split with intermediate points
+ *
+ * Like BM_face_split, but with an edge split by \a n intermediate points with given coordinates.
+ *
+ * \param bm: The bmesh.
+ * \param f: the original face.
+ * \param l_a, l_b: Vertices which define the split edge, must be different.
+ * \param cos: Array of coordinates for intermediate points.
+ * \param n: Length of \a cos (must be > 0).
+ * \param r_l: pointer which will receive the BMLoop.
+ * for the first split edge (from \a l_a) in the new face.
+ * \param example: Edge used for attributes of splitting edge, if non-NULL.
+ *
+ * \return Pointer to the newly created face representing one side of the split
+ * if the split is successful (and the original face will be the other side).
+ * NULL if the split fails.
+ */
BMFace *BM_face_split_n(BMesh *bm,
BMFace *f,
BMLoop *l_a,
@@ -45,6 +122,29 @@ BMFace *BM_face_split_n(BMesh *bm,
BMLoop **r_l,
BMEdge *example);
+/**
+ * \brief Vert Collapse Faces
+ *
+ * Collapses vertex \a v_kill that has only two manifold edges
+ * onto a vertex it shares an edge with.
+ * \a fac defines the amount of interpolation for Custom Data.
+ *
+ * \note that this is not a general edge collapse function.
+ *
+ * \note this function is very close to #BM_vert_collapse_edge,
+ * both collapse a vertex and return a new edge.
+ * Except this takes a factor and merges custom data.
+ *
+ * \param bm: The bmesh
+ * \param e_kill: The edge to collapse
+ * \param v_kill: The vertex to collapse into the edge
+ * \param fac: The factor along the edge
+ * \param join_faces: When true the faces around the vertex will be joined
+ * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
+ * \param kill_degenerate_faces: Removes faces with less than 3 verts after collapsing.
+ *
+ * \returns The New Edge
+ */
BMEdge *BM_vert_collapse_faces(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -53,6 +153,13 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
const bool join_faces,
const bool kill_degenerate_faces,
const bool kill_duplicate_faces);
+/**
+ * \brief Vert Collapse Faces
+ *
+ * Collapses a vertex onto another vertex it shares an edge with.
+ *
+ * \return The New Edge
+ */
BMEdge *BM_vert_collapse_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
@@ -60,24 +167,101 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm,
const bool kill_degenerate_faces,
const bool kill_duplicate_faces);
+/**
+ * Collapse and edge into a single vertex.
+ */
BMVert *BM_edge_collapse(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
const bool do_del,
const bool kill_degenerate_faces);
+/**
+ * \brief Edge Split
+ *
+ * <pre>
+ * Before: v
+ * +-----------------------------------+
+ * e
+ *
+ * After: v v_new (returned)
+ * +-----------------+-----------------+
+ * r_e e
+ * </pre>
+ *
+ * \param e: The edge to split.
+ * \param v: One of the vertices in \a e and defines the "from" end of the splitting operation,
+ * the new vertex will be \a fac of the way from \a v to the other end.
+ * \param r_e: The newly created edge.
+ * \return The new vertex.
+ */
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac);
+/**
+ * \brief Split an edge multiple times evenly
+ *
+ * \param r_varr: Optional array, verts in between (v1 -> v2)
+ */
BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr);
+/**
+ * Swap v1 & v2
+ *
+ * \note Typically we shouldn't care about this, however it's used when extruding wire edges.
+ */
void BM_edge_verts_swap(BMEdge *e);
bool BM_face_validate(BMFace *face, FILE *err);
+/**
+ * Calculate the 2 loops which _would_ make up the newly rotated Edge
+ * but don't actually change anything.
+ *
+ * Use this to further inspect if the loops to be connected have issues:
+ *
+ * Examples:
+ * - the newly formed edge already exists
+ * - the new face would be degenerate (zero area / concave / bow-tie)
+ * - may want to measure if the new edge gives improved results topology.
+ * over the old one, as with beauty fill.
+ *
+ * \note #BM_edge_rotate_check must have already run.
+ */
void BM_edge_calc_rotate(BMEdge *e, const bool ccw, BMLoop **r_l1, BMLoop **r_l2);
+/**
+ * \brief Check if Rotate Edge is OK
+ *
+ * Quick check to see if we could rotate the edge,
+ * use this to avoid calling exceptions on common cases.
+ */
bool BM_edge_rotate_check(BMEdge *e);
+/**
+ * \brief Check if Edge Rotate Gives Degenerate Faces
+ *
+ * Check 2 cases
+ * 1) does the newly forms edge form a flipped face (compare with previous cross product)
+ * 2) does the newly formed edge cause a zero area corner (or close enough to be almost zero)
+ *
+ * \param e: The edge to test rotation.
+ * \param l1, l2: are the loops of the proposed verts to rotate too and should
+ * be the result of calling #BM_edge_calc_rotate
+ */
bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2);
bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2);
+/**
+ * \brief Rotate Edge
+ *
+ * Spins an edge topologically,
+ * either counter-clockwise or clockwise depending on \a ccw.
+ *
+ * \return The spun edge, NULL on error
+ * (e.g., if the edge isn't surrounded by exactly two faces).
+ *
+ * \note This works by dissolving the edge then re-creating it,
+ * so the returned edge won't have the same pointer address as the original one.
+ *
+ * \see header definition for \a check_flag enum.
+ */
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag);
/** Flags for #BM_edge_rotate */
@@ -92,6 +276,9 @@ enum {
BM_EDGEROT_CHECK_BEAUTY = (1 << 3),
};
+/**
+ * \brief Rip a single face from a vertex fan
+ */
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep);
BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep);
BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len);
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 0f9488bd091..c60e8af68e5 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -341,50 +341,161 @@ typedef struct BMOpDefine {
BMOpTypeFlag type_flag;
} BMOpDefine;
-/*------------- Operator API --------------*/
-
-/* data types that use pointers (arrays, etc) should never
- * have it set directly. and never use BMO_slot_ptr_set to
- * pass in a list of edges or any arrays, really. */
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator API
+ *
+ * \note data types that use pointers (arrays, etc) must _never_ have it set directly.
+ * Don't #BMO_slot_ptr_set to pass in a list of edges or any arrays.
+ * \{ */
+/**
+ * \brief BMESH OPSTACK INIT OP
+ *
+ * Initializes an operator structure to a certain type
+ */
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname);
-/* executes an operator, pushing and popping a new tool flag
- * layer as appropriate. */
+/**
+ * \brief BMESH OPSTACK EXEC OP
+ *
+ * Executes a passed in operator.
+ *
+ * This handles the allocation and freeing of temporary tool flag
+ * layers and starting/stopping the modeling loop.
+ * Can be called from other operators exec callbacks as well.
+ */
void BMO_op_exec(BMesh *bm, BMOperator *op);
-/* finishes an operator (though note the operator's tool flag is removed
- * after it finishes executing in BMO_op_exec). */
+/**
+ * \brief BMESH OPSTACK FINISH OP
+ *
+ * Does housekeeping chores related to finishing up an operator.
+ *
+ * \note the operator's tool flag is removed after it finishes executing in #BMO_op_exec.
+ */
void BMO_op_finish(BMesh *bm, BMOperator *op);
-/* count the number of elements with the specified flag enabled.
- * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */
+/**
+ * Count the number of elements with the specified flag enabled.
+ * type can be a bit-mask of #BM_FACE, #BM_EDGE, or #BM_FACE.
+ */
int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag);
-/* count the number of elements with the specified flag disabled.
- * type can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE. */
+/**
+ * Count the number of elements with the specified flag disabled.
+ * type can be a bit-mask of #BM_FACE, #BM_EDGE, or #BM_FACE.
+ */
int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag);
-/*---------formatted operator initialization/execution-----------*/
+/**
+ * \brief BMESH OPSTACK PUSH
+ *
+ * Pushes the operator-stack down one level and allocates a new flag layer if appropriate.
+ */
void BMO_push(BMesh *bm, BMOperator *op);
+/**
+ * \brief BMESH OPSTACK POP
+ *
+ * Pops the operator-stack one level and frees a flag layer if appropriate
+ *
+ * BMESH_TODO: investigate NOT freeing flag layers.
+ */
void BMO_pop(BMesh *bm);
-/* Executes an operator. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Formatted Operator Initialization/Execution
+ *
+ * Format Strings for #BMOperator Initialization.
+ *
+ * This system is used to execute or initialize an operator,
+ * using a formatted-string system.
+ *
+ * The basic format for the format string is:
+ * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
+ *
+ * Example:
+ *
+ * \code{.c}
+ * BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
+ * "delete context=%i geom=%hv",
+ * DEL_ONLYFACES, BM_ELEM_SELECT);
+ * \endcode
+ * **Primitive Types**
+ * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
+ * - `i` - int. #BMO_OP_SLOT_INT
+ * - `f` - float. #BMO_OP_SLOT_FLT
+ * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
+ * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
+ * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
+ * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
+ * **Utility**
+ *
+ * Pass an existing slot which is copied to either an input or output slot.
+ * Taking the operator and slot-name pair of args (BMOperator *, const char *).
+ * - `s` - slot_in (lower case)
+ * - `S` - slot_out (upper case)
+ * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
+ * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
+ * - `eb` - elem buffer, take an array and a length.
+ * - `av` - all verts
+ * - `ae` - all edges
+ * - `af` - all faces
+ * - `hv` - header flagged verts (hflag)
+ * - `he` - header flagged edges (hflag)
+ * - `hf` - header flagged faces (hflag)
+ * - `Hv` - header flagged verts (hflag off)
+ * - `He` - header flagged edges (hflag off)
+ * - `Hf` - header flagged faces (hflag off)
+ * - `fv` - flagged verts (oflag)
+ * - `fe` - flagged edges (oflag)
+ * - `ff` - flagged faces (oflag)
+ * - `Fv` - flagged verts (oflag off)
+ * - `Fe` - flagged edges (oflag off)
+ * - `Ff` - flagged faces (oflag off)
+ *
+ * \note The common v/e/f suffix can be mixed,
+ * so `avef` is can be used for all verts, edges and faces.
+ * Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
+ *
+ * \{ */
+
+/** Executes an operator. */
bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt, ...);
-/* initializes, but doesn't execute an operator. this is so you can
+/**
+ * Initializes, but doesn't execute an operator. this is so you can
* gain access to the outputs of the operator. note that you have
- * to execute/finish (BMO_op_exec and BMO_op_finish) yourself. */
+ * to execute/finish (BMO_op_exec and BMO_op_finish) yourself.
+ */
bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...);
-/* va_list version, used to implement the above two functions,
- * plus EDBM_op_callf in editmesh_utils.c. */
+/**
+ * A `va_list` version, used to implement the above two functions,
+ * plus #EDBM_op_callf in editmesh_utils.c.
+ */
bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, va_list vlist);
-/* test whether a named slot exists */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator Slot Access
+ * \{ */
+
+/**
+ * \brief BMESH OPSTACK HAS SLOT
+ *
+ * \return Success if the slot if found.
+ */
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
/* get a pointer to a slot. this may be removed layer on from the public API. */
+/**
+ * \brief BMESH OPSTACK GET SLOT
+ *
+ * Returns a pointer to the slot of type 'slot_code'
+ */
BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
/* copies the data of a slot from one operator to another. src and dst are the
@@ -393,12 +504,20 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
_bmo_slot_copy( \
(op_src)->slots_src, slot_name_src, (op_dst)->slots_dst, slot_name_dst, (op_dst)->arena)
+/**
+ * \brief BMESH OPSTACK COPY SLOT
+ *
+ * define used.
+ * Copies data from one slot to another.
+ */
void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
struct MemArena *arena_dst);
+/** \} */
+
/* del "context" slot values, used for operator too */
enum {
DEL_VERTS = 1,
@@ -433,6 +552,10 @@ typedef enum {
void BMO_op_flag_enable(BMesh *bm, BMOperator *op, const int op_flag);
void BMO_op_flag_disable(BMesh *bm, BMOperator *op, const int op_flag);
+/* -------------------------------------------------------------------- */
+/** \name BMesh Operator Slot Get/Set
+ * \{ */
+
void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const float f);
@@ -441,13 +564,17 @@ void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i);
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * Return a copy of the element buffer.
+ */
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len);
-/* don't pass in arrays that are supposed to map to elements this way.
+/**
+ * Don't pass in arrays that are supposed to map to elements this way.
*
* so, e.g. passing in list of floats per element in another slot is bad.
- * passing in, e.g. pointer to an editmesh for the conversion operator is fine
- * though. */
+ * passing in, e.g. pointer to an edit-mesh for the conversion operator is fine though.
+ */
void BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, void *p);
void *BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -455,10 +582,12 @@ void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const float vec[3]);
void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3]);
-/* only supports square mats */
-/* size must be 3 or 4; this api is meant only for transformation matrices.
- * note that internally the matrix is stored in 4x4 form, and it's safe to
- * call whichever BMO_Get_MatXXX function you want. */
+/**
+ * Only supports square matrices.
+ * size must be 3 or 4; this api is meant only for transformation matrices.
+ *
+ * \note the matrix is stored in 4x4 form, and it's safe to call whichever function you want.
+ */
void BMO_slot_mat_set(BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -471,6 +600,8 @@ void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
float r_mat[3][3]);
+/** \} */
+
void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag);
void BMO_mesh_selected_remap(BMesh *bm,
@@ -479,19 +610,25 @@ void BMO_mesh_selected_remap(BMesh *bm,
BMOpSlot *slot_face_map,
const bool check_select);
-/* copies the values from another slot to the end of the output slot */
+/**
+ * Copies the values from another slot to the end of the output slot.
+ */
#define BMO_slot_buffer_append( \
op_src, slots_src, slot_name_src, op_dst, slots_dst, slot_name_dst) \
_bmo_slot_buffer_append( \
(op_src)->slots_src, slot_name_src, (op_dst)->slots_dst, slot_name_dst, (op_dst)->arena)
+/**
+ * Copies the values from another slot to the end of the output slot.
+ */
void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
struct MemArena *arena_dst);
-/* puts every element of type 'type' (which is a bitmask) with tool
- * flag 'flag', into a slot. */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) with tool flag 'flag', into a slot.
+ */
void BMO_slot_buffer_from_enabled_flag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -499,8 +636,9 @@ void BMO_slot_buffer_from_enabled_flag(BMesh *bm,
const char htype,
const short oflag);
-/* puts every element of type 'type' (which is a bitmask) without tool
- * flag 'flag', into a slot. */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) without tool flag 'flag', into a slot.
+ */
void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -508,27 +646,45 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
const char htype,
const short oflag);
-/* tool-flags all elements inside an element slot array with flag flag. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Flags elements in a slots buffer
+ */
void BMO_slot_buffer_flag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char htype,
const short oflag);
-/* clears tool-flag flag from all elements inside a slot array. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer
+ */
void BMO_slot_buffer_flag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char htype,
const short oflag);
-/* tool-flags all elements inside an element slot array with flag flag. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Header Flags elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
void BMO_slot_buffer_hflag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char htype,
const char hflag,
const bool do_flush);
-/* clears tool-flag flag from all elements inside a slot array. */
+/**
+ * \brief BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ */
void BMO_slot_buffer_hflag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -536,19 +692,20 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
const char hflag,
const bool do_flush);
-/* puts every element of type 'type' (which is a bitmask) with header
- * flag 'flag', into a slot. NOTE: ignores hidden elements
- * (e.g. elements with header flag BM_ELEM_HIDDEN set). */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) with header flag 'flag', into a slot.
+ * \note ignores hidden elements (e.g. elements with header flag BM_ELEM_HIDDEN set).
+ */
void BMO_slot_buffer_from_enabled_hflag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char htype,
const char hflag);
-
-/* puts every element of type 'type' (which is a bitmask) without
- * header flag 'flag', into a slot. NOTE: ignores hidden elements
- * (e.g. elements with header flag BM_ELEM_HIDDEN set). */
+/**
+ * Puts every element of type 'type' (which is a bit-mask) without header flag 'flag', into a slot.
+ * \note ignores hidden elements (e.g. elements with header flag BM_ELEM_HIDDEN set).
+ */
void BMO_slot_buffer_from_disabled_hflag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -564,14 +721,21 @@ void BMO_slot_buffer_from_array(BMOperator *op,
void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele);
void *BMO_slot_buffer_get_single(BMOpSlot *slot);
-/* counts number of elements inside a slot array. */
+/** Return the number of elements inside a slot array. */
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/** Return the number of elements inside a slot map. */
int BMO_slot_map_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * Inserts a key/value mapping into a mapping slot. note that it copies the
+ * value, it doesn't store a reference to it.
+ */
void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data);
-/* flags all elements in a mapping. note that the mapping must only have
- * bmesh elements in it. */
+/**
+ * Flags all elements in a mapping.
+ * \note that the mapping must only have #BMesh elements in it.
+ */
void BMO_slot_map_to_flag(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -583,6 +747,11 @@ void *BMO_slot_buffer_alloc(BMOperator *op,
const char *slot_name,
const int len);
+/**
+ * \brief BMO_ALL_TO_SLOT
+ *
+ * Copies all elements of a certain type into an operator slot.
+ */
void BMO_slot_buffer_from_all(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -636,12 +805,22 @@ typedef struct BMOIter {
void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+/**
+ * \brief New Iterator
+ *
+ * \param restrictmask: restricts the iteration to certain element types
+ * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
+ * over an element buffer (not a mapping). */
void *BMO_iter_new(BMOIter *iter,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
const char restrictmask);
void *BMO_iter_step(BMOIter *iter);
+/**
+ * Returns a pointer to the key-value when iterating over mappings.
+ * remember for pointer maps this will be a pointer to a pointer.
+ */
void **BMO_iter_map_value_p(BMOIter *iter);
void *BMO_iter_map_value_ptr(BMOIter *iter);
@@ -660,6 +839,7 @@ bool BMO_iter_map_value_bool(BMOIter *iter);
ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter), i_++)
+/* operator slot type information - size of one element of the type given. */
extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES];
int BMO_opcode_from_opname(const char *opname);
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index 221994aa313..dd35f0feee7 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -42,7 +42,6 @@ static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *identifier);
-/* operator slot type information - size of one element of the type given. */
const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
0, /* 0: BMO_OP_SLOT_SENTINEL */
sizeof(int), /* 1: BMO_OP_SLOT_BOOL */
@@ -70,11 +69,6 @@ void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
op->flag &= ~op_flag;
}
-/**
- * \brief BMESH OPSTACK PUSH
- *
- * Pushes the opstack down one level and allocates a new flag layer if appropriate.
- */
void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
{
bm->toolflag_index++;
@@ -90,13 +84,6 @@ void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
}
}
-/**
- * \brief BMESH OPSTACK POP
- *
- * Pops the opstack one level and frees a flag layer if appropriate
- *
- * BMESH_TODO: investigate NOT freeing flag layers.
- */
void BMO_pop(BMesh *bm)
{
if (bm->toolflag_index > 0) {
@@ -152,11 +139,6 @@ static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args
}
}
-/**
- * \brief BMESH OPSTACK INIT OP
- *
- * Initializes an operator structure to a certain type
- */
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
{
int opcode = BMO_opcode_from_opname(opname);
@@ -188,15 +170,6 @@ void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
BLI_memarena_use_calloc(op->arena);
}
-/**
- * \brief BMESH OPSTACK EXEC OP
- *
- * Executes a passed in operator.
- *
- * This handles the allocation and freeing of temporary flag
- * layers and starting/stopping the modeling loop.
- * Can be called from other operators exec callbacks as well.
- */
void BMO_op_exec(BMesh *bm, BMOperator *op)
{
/* allocate tool flags on demand */
@@ -216,11 +189,6 @@ void BMO_op_exec(BMesh *bm, BMOperator *op)
BMO_pop(bm);
}
-/**
- * \brief BMESH OPSTACK FINISH OP
- *
- * Does housekeeping chores related to finishing up an operator.
- */
void BMO_op_finish(BMesh *bm, BMOperator *op)
{
bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_in, op->slots_in);
@@ -238,22 +206,12 @@ void BMO_op_finish(BMesh *bm, BMOperator *op)
#endif
}
-/**
- * \brief BMESH OPSTACK HAS SLOT
- *
- * \return Success if the slot if found.
- */
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
{
int slot_code = bmo_name_to_slotcode(slot_args, identifier);
return (slot_code >= 0);
}
-/**
- * \brief BMESH OPSTACK GET SLOT
- *
- * Returns a pointer to the slot of type 'slot_code'
- */
BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
{
int slot_code = bmo_name_to_slotcode_check(slot_args, identifier);
@@ -267,12 +225,6 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
return &slot_args[slot_code];
}
-/**
- * \brief BMESH OPSTACK COPY SLOT
- *
- * define used.
- * Copies data from one slot to another.
- */
void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
const char *slot_name_src,
BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
@@ -393,7 +345,6 @@ void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
slot->data.i = i;
}
-/* only supports square mats */
void BMO_slot_mat_set(BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -515,7 +466,6 @@ bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
return slot->data.i;
}
-/* if you want a copy of the elem buffer */
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
@@ -698,9 +648,6 @@ int BMO_slot_map_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name
return BLI_ghash_len(slot->data.ghash);
}
-/* inserts a key/value mapping into a mapping slot. note that it copies the
- * value, it doesn't store a reference to it. */
-
void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data)
{
(void)op; /* Ignored in release builds. */
@@ -796,11 +743,6 @@ void *BMO_slot_buffer_alloc(BMOperator *op,
return slot->data.buf;
}
-/**
- * \brief BMO_ALL_TO_SLOT
- *
- * Copies all elements of a certain type into an operator slot.
- */
void BMO_slot_buffer_from_all(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -987,9 +929,6 @@ void *BMO_slot_buffer_get_single(BMOpSlot *slot)
return slot->len ? (BMHeader *)slot->data.buf[0] : NULL;
}
-/**
- * Copies the values from another slot to the end of the output slot.
- */
void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
const char *slot_name_dst,
BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
@@ -1115,12 +1054,6 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Header Flags elements in a slots buffer, automatically
- * using the selection API where appropriate.
- */
void BMO_slot_buffer_hflag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1155,12 +1088,6 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Removes flags from elements in a slots buffer, automatically
- * using the selection API where appropriate.
- */
void BMO_slot_buffer_hflag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1194,11 +1121,6 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Flags elements in a slots buffer
- */
void BMO_slot_buffer_flag_enable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1221,11 +1143,6 @@ void BMO_slot_buffer_flag_enable(BMesh *bm,
}
}
-/**
- * \brief BMO_FLAG_BUFFER
- *
- * Removes flags from elements in a slots buffer
- */
void BMO_slot_buffer_flag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1434,12 +1351,6 @@ void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
return slot->data.buf ? *slot->data.buf : NULL;
}
-/**
- * \brief New Iterator
- *
- * \param restrictmask: restricts the iteration to certain element types
- * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
- * over an element buffer (not a mapping). */
void *BMO_iter_new(BMOIter *iter,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
@@ -1513,10 +1424,6 @@ void *BMO_iter_step(BMOIter *iter)
/* used for iterating over mappings */
-/**
- * Returns a pointer to the key-value when iterating over mappings.
- * remember for pointer maps this will be a pointer to a pointer.
- */
void **BMO_iter_map_value_p(BMOIter *iter)
{
return iter->val;
@@ -1584,7 +1491,6 @@ bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
return false;
}
-/* returns error code or 0 if no error */
bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level)
{
BMOpError *err = bm->errorstack.first;
@@ -1694,60 +1600,6 @@ static int BMO_opcode_from_opname_check(const char *opname)
return i;
}
-/**
- * \brief Format Strings for #BMOperator Initialization.
- *
- * This system is used to execute or initialize an operator,
- * using a formatted-string system.
- *
- * The basic format for the format string is:
- * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
- *
- * Example:
- *
- * \code{.c}
- * BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
- * "delete context=%i geom=%hv",
- * DEL_ONLYFACES, BM_ELEM_SELECT);
- * \endcode
- * **Primitive Types**
- * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
- * - `i` - int. #BMO_OP_SLOT_INT
- * - `f` - float. #BMO_OP_SLOT_FLT
- * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
- * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
- * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
- * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
- * **Utility**
- *
- * Pass an existing slot which is copied to either an input or output slot.
- * Taking the operator and slot-name pair of args (BMOperator *, const char *).
- * - `s` - slot_in (lower case)
- * - `S` - slot_out (upper case)
- * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
- * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
- * - `eb` - elem buffer, take an array and a length.
- * - `av` - all verts
- * - `ae` - all edges
- * - `af` - all faces
- * - `hv` - header flagged verts (hflag)
- * - `he` - header flagged edges (hflag)
- * - `hf` - header flagged faces (hflag)
- * - `Hv` - header flagged verts (hflag off)
- * - `He` - header flagged edges (hflag off)
- * - `Hf` - header flagged faces (hflag off)
- * - `fv` - flagged verts (oflag)
- * - `fe` - flagged edges (oflag)
- * - `ff` - flagged faces (oflag)
- * - `Fv` - flagged verts (oflag off)
- * - `Fe` - flagged edges (oflag off)
- * - `Ff` - flagged faces (oflag off)
- *
- * \note The common v/e/f suffix can be mixed,
- * so `avef` is can be used for all verts, edges and faces.
- * Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
- */
-
bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, va_list vlist)
{
// BMOpDefine *def;
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index a701fe3eb85..83f2c402c35 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -170,17 +170,50 @@ void BM_mesh_esubdivide(BMesh *bm,
const short use_only_quads,
const int seed);
+/**
+ * Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on
+ * \param x_segments: The x-resolution of the grid
+ * \param y_segments: The y-resolution of the grid
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_grid(BMesh *bm,
const uint x_segments,
const uint y_segments,
const short oflag,
const int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with spherical projected UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param mat: The transform matrix applied to the created circle.
+ * \param radius: The size of the circle.
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_circle(BMesh *bm,
float mat[4][4],
const float radius,
const short oflag,
const int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param mat: The transform matrix applied to the created cone/cylinder.
+ * \param radius_top: The size of the top end of the cone/cylinder.
+ * \param radius_bottom: The size of the bottom end of the cone/cylinder.
+ * \param segments: The number of subdivisions in the sides of the cone/cylinder.
+ * \param cap_ends: Whether the ends of the cone/cylinder are filled or not.
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_cone(BMesh *bm,
float mat[4][4],
const float radius_top,
@@ -189,6 +222,15 @@ void BM_mesh_calc_uvs_cone(BMesh *bm,
const bool cap_ends,
const short oflag,
const int cd_loop_uv_offset);
+/**
+ * Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
+ *
+ * \note Expects tagged faces to be six quads.
+ * \note Caller must order faces for correct alignment.
+ *
+ * \param bm: The BMesh to operate on.
+ * \param oflag: The flag to check faces with.
+ */
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag);
#include "intern/bmesh_operator_api_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 51ae47adacc..e9eaf865e3c 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -117,15 +117,6 @@ static void bm_face_calc_poly_center_median_vertex_cos(const BMFace *f,
mul_v3_fl(r_cent, 1.0f / f->len);
}
-/**
- * For tools that insist on using triangles, ideally we would cache this data.
- *
- * \param use_fixed_quad: When true,
- * always split quad along (0 -> 2) regardless of concave corners,
- * (as done in #BM_mesh_calc_tessellation).
- * \param r_loops: Store face loop pointers, (f->len)
- * \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
- */
void BM_face_calc_tessellation(const BMFace *f,
const bool use_fixed_quad,
BMLoop **r_loops,
@@ -177,9 +168,6 @@ void BM_face_calc_tessellation(const BMFace *f,
}
}
-/**
- * Return a point inside the face.
- */
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
{
const BMLoop *l_tri[3];
@@ -218,9 +206,6 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
mid_v3_v3v3v3(r_co, l_tri[0]->v->co, l_tri[1]->v->co, l_tri[2]->v->co);
}
-/**
- * get the area of the face
- */
float BM_face_calc_area(const BMFace *f)
{
/* inline 'area_poly_v3' logic, avoid creating a temp array */
@@ -235,9 +220,6 @@ float BM_face_calc_area(const BMFace *f)
return len_v3(n) * 0.5f;
}
-/**
- * Get the area of the face in world space.
- */
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
{
/* inline 'area_poly_v3' logic, avoid creating a temp array */
@@ -257,9 +239,6 @@ float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
return len_v3(n) * 0.5f;
}
-/**
- * get the area of UV face
- */
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
{
/* inline 'area_poly_v2' logic, avoid creating a temp array */
@@ -276,9 +255,6 @@ float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
return fabsf(cross * 0.5f);
}
-/**
- * compute the perimeter of an ngon
- */
float BM_face_calc_perimeter(const BMFace *f)
{
const BMLoop *l_iter, *l_first;
@@ -292,9 +268,6 @@ float BM_face_calc_perimeter(const BMFace *f)
return perimeter;
}
-/**
- * Calculate the perimeter of a ngon in world space.
- */
float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
{
const BMLoop *l_iter, *l_first;
@@ -355,14 +328,6 @@ static int bm_vert_tri_find_unique_edge(BMVert *verts[3])
return order[0];
}
-/**
- * Calculate a tangent from any 3 vertices.
- *
- * The tangent aligns to the most *unique* edge
- * (the edge most unlike the other two).
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
{
const int index = bm_vert_tri_find_unique_edge(verts);
@@ -372,14 +337,6 @@ void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Calculate a tangent from any 3 vertices,
- *
- * The tangent follows the center-line formed by the most unique edges center
- * and the opposite vertex.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
{
const int index = bm_vert_tri_find_unique_edge(verts);
@@ -394,9 +351,6 @@ void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using the longest edge.
- */
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
{
const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
@@ -406,11 +360,6 @@ void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using the two longest disconnected edges.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
{
if (f->len == 3) {
@@ -471,11 +420,6 @@ void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3])
}
}
-/**
- * Compute the tangent of the face, using the edge farthest away from any vertex in the face.
- *
- * \param r_tangent: Calculated unit length tangent (return value).
- */
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
{
BMLoop *l_iter, *l_first;
@@ -508,11 +452,6 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute the tangent of the face, using longest distance between vertices on the face.
- *
- * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
- */
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
{
BMLoop *l_iter, *l_first;
@@ -541,11 +480,6 @@ void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * Compute a meaningful direction along the face (use for gizmo axis).
- *
- * \note Callers shouldn't depend on the *exact* method used here.
- */
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
{
if (f->len == 3) {
@@ -564,9 +498,6 @@ void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
}
}
-/**
- * expands bounds (min/max must be initialized).
- */
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
{
const BMLoop *l_iter, *l_first;
@@ -576,9 +507,6 @@ void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
} while ((l_iter = l_iter->next) != l_first);
}
-/**
- * computes center of face in 3d. uses center of bounding box.
- */
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter, *l_first;
@@ -594,9 +522,6 @@ void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
mid_v3_v3v3(r_cent, min, max);
}
-/**
- * computes center of face in 3d. uses center of bounding box.
- */
void BM_face_calc_center_bounds_vcos(const BMesh *bm,
const BMFace *f,
float r_cent[3],
@@ -619,9 +544,6 @@ void BM_face_calc_center_bounds_vcos(const BMesh *bm,
mid_v3_v3v3(r_cent, min, max);
}
-/**
- * computes the center of a face, using the mean average
- */
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter, *l_first;
@@ -635,10 +557,6 @@ void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
mul_v3_fl(r_cent, 1.0f / (float)f->len);
}
-/**
- * computes the center of a face, using the mean average
- * weighted by edge length
- */
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
{
const BMLoop *l_iter;
@@ -663,12 +581,6 @@ void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
}
}
-/**
- * \brief POLY ROTATE PLANE
- *
- * Rotates a polygon so that its
- * normal is pointing towards the mesh Z axis
- */
void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts)
{
float mat[3][3];
@@ -684,9 +596,6 @@ void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nver
}
}
-/**
- * updates face and vertex normals incident on an edge
- */
void BM_edge_normals_update(BMEdge *e)
{
BMIter iter;
@@ -800,24 +709,11 @@ void BM_vert_normal_update_all(BMVert *v)
}
}
-/**
- * update a vert normal (but not the faces incident on it)
- */
void BM_vert_normal_update(BMVert *v)
{
BM_vert_calc_normal(v, v->no);
}
-/**
- * \brief BMESH UPDATE FACE NORMAL
- *
- * Updates the stored normal for the
- * given face. Requires that a buffer
- * of sufficient length to store projected
- * coordinates for all of the face's vertices
- * is passed in as well.
- */
-
float BM_face_calc_normal(const BMFace *f, float r_no[3])
{
BMLoop *l;
@@ -849,7 +745,6 @@ void BM_face_normal_update(BMFace *f)
BM_face_calc_normal(f, f->no);
}
-/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
float BM_face_calc_normal_vcos(const BMesh *bm,
const BMFace *f,
float r_no[3],
@@ -884,12 +779,6 @@ float BM_face_calc_normal_vcos(const BMesh *bm,
}
}
-/**
- * Calculate a normal from a vertex cloud.
- *
- * \note We could make a higher quality version that takes all vertices into account.
- * Currently it finds 4 outer most points returning its normal.
- */
void BM_verts_calc_normal_from_cloud_ex(
BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent)
{
@@ -991,9 +880,6 @@ void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal
BM_verts_calc_normal_from_cloud_ex(varr, varr_len, r_normal, NULL, NULL);
}
-/**
- * Calculates the face subset normal.
- */
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
{
const float *v_prev, *v_curr;
@@ -1014,7 +900,6 @@ float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, fl
return normalize_v3(r_no);
}
-/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f,
float r_cent[3],
@@ -1027,12 +912,6 @@ void BM_face_calc_center_median_vcos(const BMesh *bm,
bm_face_calc_poly_center_median_vertex_cos(f, r_cent, vertexCos);
}
-/**
- * \brief Face Flip Normal
- *
- * Reverses the winding of a face.
- * \note This updates the calculated normal.
- */
void BM_face_normal_flip_ex(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
@@ -1048,16 +927,6 @@ void BM_face_normal_flip(BMesh *bm, BMFace *f)
BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
}
-/**
- * BM POINT IN FACE
- *
- * Projects co onto face f, and returns true if it is inside
- * the face bounds.
- *
- * \note this uses a best-axis projection test,
- * instead of projecting co directly into f's orientation space,
- * so there might be accuracy issues.
- */
bool BM_face_point_inside_test(const BMFace *f, const float co[3])
{
float axis_mat[3][3];
@@ -1080,29 +949,6 @@ bool BM_face_point_inside_test(const BMFace *f, const float co[3])
return isect_point_poly_v2(co_2d, projverts, f->len, false);
}
-/**
- * \brief BMESH TRIANGULATE FACE
- *
- * Breaks all quads and ngons down to triangles.
- * It uses polyfill for the ngons splitting, and
- * the beautify operator when use_beauty is true.
- *
- * \param r_faces_new: if non-null, must be an array of BMFace pointers,
- * with a length equal to (f->len - 3). It will be filled with the new
- * triangles (not including the original triangle).
- *
- * \param r_faces_double: When newly created faces are duplicates of existing faces,
- * they're added to this list. Caller must handle de-duplication.
- * This is done because its possible _all_ faces exist already,
- * and in that case we would have to remove all faces including the one passed,
- * which causes complications adding/removing faces while looking over them.
- *
- * \note The number of faces is _almost_ always (f->len - 3),
- * However there may be faces that already occupying the
- * triangles we would make, so the caller must check \a r_faces_new_tot.
- *
- * \note use_tag tags new flags and edges.
- */
void BM_face_triangulate(BMesh *bm,
BMFace *f,
BMFace **r_faces_new,
@@ -1325,14 +1171,6 @@ void BM_face_triangulate(BMesh *bm,
}
}
-/**
- * each pair of loops defines a new edge, a split. this function goes
- * through and sets pairs that are geometrically invalid to null. a
- * split is invalid, if it forms a concave angle or it intersects other
- * edges in the face, or it intersects another split. in the case of
- * intersecting splits, only the first of the set of intersecting
- * splits survives
- */
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
{
float out[2] = {-FLT_MAX, -FLT_MAX};
@@ -1430,10 +1268,6 @@ void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int l
#undef EDGE_SHARE_VERT
}
-/**
- * This simply checks that the verts don't connect faces which would have more optimal splits.
- * but _not_ check for correctness.
- */
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
{
int i;
@@ -1447,12 +1281,6 @@ void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
}
}
-/**
- * Small utility functions for fast access
- *
- * faster alternative to:
- * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
- */
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1466,10 +1294,6 @@ void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
r_verts[2] = l->v;
}
-/**
- * faster alternative to:
- * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
- */
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1485,12 +1309,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
r_verts[3] = l->v;
}
-/**
- * Small utility functions for fast access
- *
- * faster alternative to:
- * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
- */
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
@@ -1504,10 +1322,6 @@ void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3])
r_loops[2] = l;
}
-/**
- * faster alternative to:
- * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);
- */
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4])
{
BMLoop *l = BM_FACE_FIRST_LOOP(f);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 5be7f4a5f3b..e4545e610a0 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -25,68 +25,200 @@ struct Heap;
#include "BLI_compiler_attrs.h"
+/**
+ * For tools that insist on using triangles, ideally we would cache this data.
+ *
+ * \param use_fixed_quad: When true,
+ * always split quad along (0 -> 2) regardless of concave corners,
+ * (as done in #BM_mesh_calc_tessellation).
+ * \param r_loops: Store face loop pointers, (f->len)
+ * \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
+ */
void BM_face_calc_tessellation(const BMFace *f,
const bool use_fixed_quad,
BMLoop **r_loops,
uint (*r_index)[3]);
+/**
+ * Return a point inside the face.
+ */
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]);
+
+/**
+ * \brief BMESH UPDATE FACE NORMAL
+ *
+ * Updates the stored normal for the
+ * given face. Requires that a buffer
+ * of sufficient length to store projected
+ * coordinates for all of the face's vertices
+ * is passed in as well.
+ */
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
+/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
float BM_face_calc_normal_vcos(const BMesh *bm,
const BMFace *f,
float r_no[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * Calculate a normal from a vertex cloud.
+ *
+ * \note We could make a higher quality version that takes all vertices into account.
+ * Currently it finds 4 outer most points returning its normal.
+ */
void BM_verts_calc_normal_from_cloud_ex(
BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent);
void BM_verts_calc_normal_from_cloud(BMVert **varr, int varr_len, float r_normal[3]);
+/**
+ * Calculates the face subset normal.
+ */
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
ATTR_NONNULL();
+/**
+ * get the area of the face
+ */
float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get the area of the face in world space.
+ */
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * get the area of UV face
+ */
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * compute the perimeter of an ngon
+ */
float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Calculate the perimeter of a ngon in world space.
+ */
float BM_face_calc_perimeter_with_mat3(const BMFace *f,
const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the longest edge.
+ */
void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the two longest disconnected edges.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using the edge farthest away from any vertex in the face.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute the tangent of the face, using longest distance between vertices on the face.
+ *
+ * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal
+ */
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * Compute a meaningful direction along the face (use for gizmo axis).
+ *
+ * \note Callers shouldn't depend on the *exact* method used here.
+ */
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3]) ATTR_NONNULL();
+/**
+ * computes center of face in 3d. uses center of bounding box.
+ */
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3]) ATTR_NONNULL();
+/**
+ * computes center of face in 3d. uses center of bounding box.
+ */
void BM_face_calc_center_bounds_vcos(const BMesh *bm,
const BMFace *f,
float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * computes the center of a face, using the mean average
+ */
void BM_face_calc_center_median(const BMFace *f, float r_center[3]) ATTR_NONNULL();
+/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f,
float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
+/**
+ * computes the center of a face, using the mean average
+ * weighted by edge length
+ */
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3]) ATTR_NONNULL();
+/**
+ * expands bounds (min/max must be initialized).
+ */
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3]);
void BM_face_normal_update(BMFace *f) ATTR_NONNULL();
+/**
+ * updates face and vertex normals incident on an edge
+ */
void BM_edge_normals_update(BMEdge *e) ATTR_NONNULL();
bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3]);
bool BM_vert_calc_normal(const BMVert *v, float r_no[3]);
+/**
+ * update a vert normal (but not the faces incident on it)
+ */
void BM_vert_normal_update(BMVert *v) ATTR_NONNULL();
void BM_vert_normal_update_all(BMVert *v) ATTR_NONNULL();
+/**
+ * \brief Face Flip Normal
+ *
+ * Reverses the winding of a face.
+ * \note This updates the calculated normal.
+ */
void BM_face_normal_flip_ex(BMesh *bm,
BMFace *f,
const int cd_loop_mdisp_offset,
const bool use_loop_mdisp_flip) ATTR_NONNULL();
void BM_face_normal_flip(BMesh *bm, BMFace *f) ATTR_NONNULL();
+/**
+ * BM POINT IN FACE
+ *
+ * Projects co onto face f, and returns true if it is inside
+ * the face bounds.
+ *
+ * \note this uses a best-axis projection test,
+ * instead of projecting co directly into f's orientation space,
+ * so there might be accuracy issues.
+ */
bool BM_face_point_inside_test(const BMFace *f, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BMESH TRIANGULATE FACE
+ *
+ * Breaks all quads and ngons down to triangles.
+ * It uses poly-fill for the ngons splitting, and
+ * the beautify operator when use_beauty is true.
+ *
+ * \param r_faces_new: if non-null, must be an array of BMFace pointers,
+ * with a length equal to (f->len - 3). It will be filled with the new
+ * triangles (not including the original triangle).
+ *
+ * \param r_faces_double: When newly created faces are duplicates of existing faces,
+ * they're added to this list. Caller must handle de-duplication.
+ * This is done because its possible _all_ faces exist already,
+ * and in that case we would have to remove all faces including the one passed,
+ * which causes complications adding/removing faces while looking over them.
+ *
+ * \note The number of faces is _almost_ always (f->len - 3),
+ * However there may be faces that already occupying the
+ * triangles we would make, so the caller must check \a r_faces_new_tot.
+ *
+ * \note use_tag tags new flags and edges.
+ */
void BM_face_triangulate(BMesh *bm,
BMFace *f,
BMFace **r_faces_new,
@@ -100,14 +232,62 @@ void BM_face_triangulate(BMesh *bm,
struct MemArena *pf_arena,
struct Heap *pf_heap) ATTR_NONNULL(1, 2);
+/**
+ * each pair of loops defines a new edge, a split. this function goes
+ * through and sets pairs that are geometrically invalid to null. a
+ * split is invalid, if it forms a concave angle or it intersects other
+ * edges in the face, or it intersects another split. in the case of
+ * intersecting splits, only the first of the set of intersecting
+ * splits survives
+ */
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
+/**
+ * This simply checks that the verts don't connect faces which would have more optimal splits.
+ * but _not_ check for correctness.
+ */
void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
+/**
+ * Small utility functions for fast access
+ *
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 3);
+ */
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3]) ATTR_NONNULL();
+/**
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void **)v, 4);
+ */
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
+/**
+ * Small utility functions for fast access
+ *
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3);
+ */
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
+/**
+ * faster alternative to:
+ * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4);
+ */
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
+/**
+ * Calculate a tangent from any 3 vertices.
+ *
+ * The tangent aligns to the most *unique* edge
+ * (the edge most unlike the other two).
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]);
+/**
+ * Calculate a tangent from any 3 vertices,
+ *
+ * The tangent follows the center-line formed by the most unique edges center
+ * and the opposite vertex.
+ *
+ * \param r_tangent: Calculated unit length tangent (return value).
+ */
void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]);
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
index 103d7621f87..24d9c194054 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -452,14 +452,6 @@ static bool bm_face_split_edgenet_find_loop(BMVert *v_init,
return false;
}
-/**
- * Splits a face into many smaller faces defined by an edge-net.
- * handle customdata and degenerate cases.
- *
- * - Isolated holes or unsupported face configurations, will be ignored.
- * - Customdata calculations aren't efficient
- * (need to calculate weights for each vert).
- */
bool BM_face_split_edgenet(BMesh *bm,
BMFace *f,
BMEdge **edge_net,
@@ -1223,14 +1215,6 @@ static bool bm_vert_partial_connect_check_overlap(const int *remap,
#endif /* USE_PARTIAL_CONNECT */
-/**
- * For when the edge-net has holes in it-this connects them.
- *
- * \param use_partial_connect: Support for handling islands connected by only a single edge,
- * \note that this is quite slow so avoid using where possible.
- * \param mem_arena: Avoids many small allocs & should be cleared after each use.
- * take care since \a edge_net_new is stored in \a r_edge_net_new.
- */
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
BMFace *f,
BMEdge **edge_net_init,
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
index 6833f067421..a25f38a84b3 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
@@ -20,6 +20,14 @@
* \ingroup bmesh
*/
+/**
+ * Splits a face into many smaller faces defined by an edge-net.
+ * handle customdata and degenerate cases.
+ *
+ * - Isolated holes or unsupported face configurations, will be ignored.
+ * - Customdata calculations aren't efficient
+ * (need to calculate weights for each vert).
+ */
bool BM_face_split_edgenet(BMesh *bm,
BMFace *f,
BMEdge **edge_net,
@@ -27,12 +35,20 @@ bool BM_face_split_edgenet(BMesh *bm,
BMFace ***r_face_arr,
int *r_face_arr_len);
+/**
+ * For when the edge-net has holes in it-this connects them.
+ *
+ * \param use_partial_connect: Support for handling islands connected by only a single edge,
+ * \note that this is quite slow so avoid using where possible.
+ * \param mem_arena: Avoids many small allocs & should be cleared after each use.
+ * take care since \a edge_net_new is stored in \a r_edge_net_new.
+ */
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
BMFace *f,
BMEdge **edge_net_init,
const uint edge_net_init_len,
bool use_partial_connect,
- struct MemArena *arena,
+ struct MemArena *mem_arena,
BMEdge ***r_edge_net_new,
uint *r_edge_net_new_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3, 6, 7, 8);
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index e1df7744e41..e7e8b7107e5 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -34,6 +34,12 @@
* it can take most of the CPU time when running some tools. */
# define BM_CHECK_ELEMENT(el) (void)(el)
#else
+/**
+ * Check the element is valid.
+ *
+ * BMESH_TODO, when this raises an error the output is incredibly confusing.
+ * need to have some nice way to print/debug what the heck's going on.
+ */
int bmesh_elem_check(void *element, const char htype);
# define BM_CHECK_ELEMENT(el) \
{ \
@@ -86,6 +92,12 @@ enum {
} \
(void)0
+/**
+ * \brief POLY ROTATE PLANE
+ *
+ * Rotates a polygon so that its
+ * normal is pointing towards the mesh Z axis
+ */
void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts);
/* include the rest of our private declarations */
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 795d8829ee7..fe2142670a2 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -37,24 +37,6 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
-/**
- * \brief Other Loop in Face Sharing an Edge
- *
- * Finds the other loop that shares \a v with \a e loop in \a f.
- * <pre>
- * +----------+
- * | |
- * | f |
- * | |
- * +----------+ <-- return the face loop of this vertex.
- * v --> e
- * ^ ^ <------- These vert args define direction
- * in the face to check.
- * The faces loop direction is ignored.
- * </pre>
- *
- * \note caller must ensure \a e is used in \a f
- */
BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
{
BMLoop *l = BM_face_edge_share_loop(f, e);
@@ -62,38 +44,12 @@ BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v)
return BM_loop_other_edge_loop(l, v);
}
-/**
- * See #BM_face_other_edge_loop This is the same functionality
- * to be used when the edges loop is already known.
- */
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
{
BLI_assert(BM_vert_in_edge(l->e, v));
return l->v == v ? l->prev : l->next;
}
-/**
- * \brief Other Loop in Face Sharing a Vertex
- *
- * Finds the other loop in a face.
- *
- * This function returns a loop in \a f that shares an edge with \a v
- * The direction is defined by \a v_prev, where the return value is
- * the loop of what would be 'v_next'
- * <pre>
- * +----------+ <-- return the face loop of this vertex.
- * | |
- * | f |
- * | |
- * +----------+
- * v_prev --> v
- * ^^^^^^ ^ <-- These vert args define direction
- * in the face to check.
- * The faces loop direction is ignored.
- * </pre>
- *
- * \note \a v_prev and \a v _implicitly_ define an edge.
- */
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
{
BMLoop *l_iter = BM_face_vert_share_loop(f, v);
@@ -116,22 +72,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
return NULL;
}
-/**
- * \brief Other Loop in Face Sharing a Vert
- *
- * Finds the other loop that shares \a v with \a e loop in \a f.
- * <pre>
- * +----------+ <-- return the face loop of this vertex.
- * | |
- * | |
- * | |
- * +----------+ <-- This vertex defines the direction.
- * l v
- * ^ <------- This loop defines both the face to search
- * and the edge, in combination with 'v'
- * The faces loop direction is ignored.
- * </pre>
- */
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
{
#if 0 /* works but slow */
@@ -157,22 +97,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
#endif
}
-/**
- * Return the other loop that uses this edge.
- *
- * In this case the loop defines the vertex,
- * the edge passed in defines the direction to step.
- *
- * <pre>
- * +----------+ <-- Return the face-loop of this vertex.
- * | |
- * | e | <-- This edge defines the direction.
- * | |
- * +----------+ <-- This loop defines the face and vertex..
- * l
- * </pre>
- *
- */
BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
{
BLI_assert(BM_vert_in_edge(e, l->v));
@@ -187,9 +111,6 @@ BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e)
return NULL;
}
-/**
- * Check if verts share a face.
- */
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b)
{
if (v_a->e && v_b->e) {
@@ -255,9 +176,6 @@ BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
return NULL;
}
-/**
- * Given 2 verts, find the smallest face they share and give back both loops.
- */
BMFace *BM_vert_pair_share_face_by_len(
BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
{
@@ -325,24 +243,12 @@ static float bm_face_calc_split_dot(BMLoop *l_a, BMLoop *l_b)
return -1.0f;
}
-/**
- * Check if a point is inside the corner defined by a loop
- * (within the 2 planes defined by the loops corner & face normal).
- *
- * \return signed, squared distance to the loops planes, less than 0.0 when outside.
- */
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3])
{
const float *axis = l->f->no;
return dist_signed_squared_to_corner_v3v3v3(co, l->prev->v->co, l->v->co, l->next->v->co, axis);
}
-/**
- * Check if a point is inside the edge defined by a loop
- * (within the plane defined by the loops edge & face normal).
- *
- * \return signed, squared distance to the edge plane, less than 0.0 when outside.
- */
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
{
const float *axis = l->f->no;
@@ -356,13 +262,6 @@ float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
return dist_signed_squared_to_plane_v3(co, plane);
}
-/**
- * Given 2 verts,
- * find a face they share that has the lowest angle across these verts and give back both loops.
- *
- * This can be better than #BM_vert_pair_share_face_by_len
- * because concave splits are ranked lowest.
- */
BMFace *BM_vert_pair_share_face_by_angle(
BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
{
@@ -409,25 +308,15 @@ BMFace *BM_vert_pair_share_face_by_angle(
return f_cur;
}
-/**
- * Get the first loop of a vert. Uses the same initialization code for the first loop of the
- * iterator API
- */
BMLoop *BM_vert_find_first_loop(BMVert *v)
{
return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL;
}
-/**
- * A version of #BM_vert_find_first_loop that ignores hidden loops.
- */
BMLoop *BM_vert_find_first_loop_visible(BMVert *v)
{
return v->e ? bmesh_disk_faceloop_find_first_visible(v->e, v) : NULL;
}
-/**
- * Returns true if the vertex is used in a given face.
- */
bool BM_vert_in_face(BMVert *v, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -452,10 +341,6 @@ bool BM_vert_in_face(BMVert *v, BMFace *f)
return false;
}
-/**
- * Compares the number of vertices in an array
- * that appear in a given face
- */
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -496,9 +381,6 @@ int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f)
return count;
}
-/**
- * Return true if all verts are in the face.
- */
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
{
BMLoop *l_iter, *l_first;
@@ -549,9 +431,6 @@ bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
return ok;
}
-/**
- * Returns whether or not a given edge is part of a given face.
- */
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
{
if (e->l) {
@@ -568,22 +447,6 @@ bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
return false;
}
-/**
- * Given a edge and a loop (assumes the edge is manifold). returns
- * the other faces loop, sharing the same vertex.
- *
- * <pre>
- * +-------------------+
- * | |
- * | |
- * |l_other <-- return |
- * +-------------------+ <-- A manifold edge between 2 faces
- * |l e <-- edge |
- * |^ <-------- loop |
- * | |
- * +-------------------+
- * </pre>
- */
BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
{
BMLoop *l_other;
@@ -609,31 +472,6 @@ BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
return l_other;
}
-/**
- * Utility function to step around a fan of loops,
- * using an edge to mark the previous side.
- *
- * \note all edges must be manifold,
- * once a non manifold edge is hit, return NULL.
- *
- * <pre>
- * ,.,-->|
- * _,-' |
- * ,' | (notice how 'e_step'
- * / | and 'l' define the
- * / | direction the arrow
- * | return | points).
- * | loop --> |
- * ---------------------+---------------------
- * ^ l --> |
- * | |
- * assign e_step |
- * |
- * begin e_step ----> |
- * |
- * </pre>
- */
-
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
{
BMEdge *e_prev = *e_step;
@@ -655,12 +493,6 @@ BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
return NULL;
}
-/**
- * The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
- * All edges in the fan must be manifold, otherwise return NULL.
- *
- * \note This could (probably) be done more efficiently.
- */
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
{
BMLoop *l_a;
@@ -707,28 +539,16 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
return NULL;
}
-/**
- * Returns edge length
- */
float BM_edge_calc_length(const BMEdge *e)
{
return len_v3v3(e->v1->co, e->v2->co);
}
-/**
- * Returns edge length squared (for comparisons)
- */
float BM_edge_calc_length_squared(const BMEdge *e)
{
return len_squared_v3v3(e->v1->co, e->v2->co);
}
-/**
- * Utility function, since enough times we have an edge
- * and want to access 2 connected faces.
- *
- * \return true when only 2 faces are found.
- */
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
{
BMLoop *la, *lb;
@@ -744,12 +564,6 @@ bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
return false;
}
-/**
- * Utility function, since enough times we have an edge
- * and want to access 2 connected loops.
- *
- * \return true when only 2 faces are found.
- */
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
{
BMLoop *la, *lb;
@@ -765,9 +579,6 @@ bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
return false;
}
-/**
- * Fast alternative to `(BM_vert_edge_count(v) == 2)`.
- */
bool BM_vert_is_edge_pair(const BMVert *v)
{
const BMEdge *e = v->e;
@@ -778,10 +589,6 @@ bool BM_vert_is_edge_pair(const BMVert *v)
return false;
}
-/**
- * Fast alternative to `(BM_vert_edge_count(v) == 2)`
- * that checks both edges connect to the same faces.
- */
bool BM_vert_is_edge_pair_manifold(const BMVert *v)
{
const BMEdge *e = v->e;
@@ -794,11 +601,6 @@ bool BM_vert_is_edge_pair_manifold(const BMVert *v)
return false;
}
-/**
- * Access a verts 2 connected edges.
- *
- * \return true when only 2 verts are found.
- */
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
{
BMEdge *e_a = v->e;
@@ -816,9 +618,6 @@ bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
return false;
}
-/**
- * Returns the number of edges around this vertex.
- */
int BM_vert_edge_count(const BMVert *v)
{
return bmesh_disk_count(v);
@@ -841,9 +640,6 @@ int BM_vert_edge_count_nonwire(const BMVert *v)
}
return count;
}
-/**
- * Returns the number of faces around this edge
- */
int BM_edge_face_count(const BMEdge *e)
{
int count = 0;
@@ -879,10 +675,6 @@ int BM_edge_face_count_at_most(const BMEdge *e, const int count_max)
return count;
}
-/**
- * Returns the number of faces around this vert
- * length matches #BM_LOOPS_OF_VERT iterator
- */
int BM_vert_face_count(const BMVert *v)
{
return bmesh_disk_facevert_count(v);
@@ -893,11 +685,6 @@ int BM_vert_face_count_at_most(const BMVert *v, int count_max)
return bmesh_disk_facevert_count_at_most(v, count_max);
}
-/**
- * Return true if the vertex is connected to _any_ faces.
- *
- * same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
- */
bool BM_vert_face_check(const BMVert *v)
{
if (v->e != NULL) {
@@ -912,10 +699,6 @@ bool BM_vert_face_check(const BMVert *v)
return false;
}
-/**
- * Tests whether or not the vertex is part of a wire edge.
- * (ie: has no faces attached to it)
- */
bool BM_vert_is_wire(const BMVert *v)
{
if (v->e) {
@@ -933,13 +716,6 @@ bool BM_vert_is_wire(const BMVert *v)
return false;
}
-/**
- * A vertex is non-manifold if it meets the following conditions:
- * 1: Loose - (has no edges/faces incident upon it).
- * 2: Joins two distinct regions - (two pyramids joined at the tip).
- * 3: Is part of an edge with more than 2 faces.
- * 4: Is part of a wire edge.
- */
bool BM_vert_is_manifold(const BMVert *v)
{
BMEdge *e_iter, *e_first, *e_prev;
@@ -1064,9 +840,6 @@ static int bm_loop_region_count__clear(BMLoop *l)
return count;
}
-/**
- * The number of loops connected to this loop (not including disconnected regions).
- */
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total)
{
const int count = bm_loop_region_count__recursive(l->e, l->v);
@@ -1085,10 +858,6 @@ int BM_loop_region_loops_count(BMLoop *l)
return BM_loop_region_loops_count_at_most(l, NULL);
}
-/**
- * A version of #BM_vert_is_manifold
- * which only checks if we're connected to multiple isolated regions.
- */
bool BM_vert_is_manifold_region(const BMVert *v)
{
BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
@@ -1100,10 +869,6 @@ bool BM_vert_is_manifold_region(const BMVert *v)
return true;
}
-/**
- * Check if the edge is convex or concave
- * (depends on face winding)
- */
bool BM_edge_is_convex(const BMEdge *e)
{
if (BM_edge_is_manifold(e)) {
@@ -1121,9 +886,6 @@ bool BM_edge_is_convex(const BMEdge *e)
return true;
}
-/**
- * \return true when loop customdata is contiguous.
- */
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e,
const int cd_loop_type,
const int cd_loop_offset)
@@ -1182,11 +944,6 @@ bool BM_vert_is_boundary(const BMVert *v)
return false;
}
-/**
- * Returns the number of faces that are adjacent to both f1 and f2,
- * \note Could be sped up a bit by not using iterators and by tagging
- * faces on either side, then count the tags rather then searching.
- */
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
{
BMIter iter1, iter2;
@@ -1205,9 +962,6 @@ int BM_face_share_face_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * same as #BM_face_share_face_count but returns a bool
- */
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
{
BMIter iter1, iter2;
@@ -1225,9 +979,6 @@ bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
return false;
}
-/**
- * Counts the number of edges two faces share (if any)
- */
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1244,9 +995,6 @@ int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * Returns true if the faces share an edge
- */
bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
{
BMLoop *l_iter;
@@ -1262,9 +1010,6 @@ bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
return false;
}
-/**
- * Counts the number of verts two faces share (if any).
- */
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1281,9 +1026,6 @@ int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
return count;
}
-/**
- * Returns true if the faces share a vert.
- */
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
{
BMLoop *l_iter;
@@ -1299,18 +1041,12 @@ bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
return false;
}
-/**
- * Returns true when 2 loops share an edge (are adjacent in the face-fan)
- */
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b)
{
BLI_assert(l_a->v == l_b->v);
return (ELEM(l_a->e, l_b->e, l_b->prev->e) || ELEM(l_b->e, l_a->e, l_a->prev->e));
}
-/**
- * Test if e1 shares any faces with e2
- */
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
{
BMLoop *l;
@@ -1329,9 +1065,6 @@ bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
return false;
}
-/**
- * Test if e1 shares any quad faces with e2
- */
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
{
BMLoop *l;
@@ -1352,17 +1085,11 @@ bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2)
return false;
}
-/**
- * Tests to see if e1 shares a vertex with e2
- */
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
{
return (e1->v1 == e2->v1 || e1->v1 == e2->v2 || e1->v2 == e2->v1 || e1->v2 == e2->v2);
}
-/**
- * Return the shared vertex between the two edges or NULL
- */
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
{
BLI_assert(e1 != e2);
@@ -1375,14 +1102,6 @@ BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
return NULL;
}
-/**
- * \brief Return the Loop Shared by Edge and Vert
- *
- * Finds the loop used which uses \a in face loop \a l
- *
- * \note this function takes a loop rather than an edge
- * so we can select the face that the loop should be from.
- */
BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
{
BLI_assert(BM_vert_in_edge(l->e, v));
@@ -1392,14 +1111,6 @@ BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
return l->next;
}
-/**
- * \brief Return the Loop Shared by Face and Vertex
- *
- * Finds the loop used which uses \a v in face loop \a l
- *
- * \note currently this just uses simple loop in future may be sped up
- * using radial vars
- */
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
{
BMLoop *l_first;
@@ -1415,14 +1126,6 @@ BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v)
return NULL;
}
-/**
- * \brief Return the Loop Shared by Face and Edge
- *
- * Finds the loop used which uses \a e in face loop \a l
- *
- * \note currently this just uses simple loop in future may be sped up
- * using radial vars
- */
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
{
BMLoop *l_first;
@@ -1438,18 +1141,6 @@ BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
return NULL;
}
-/**
- * Returns the verts of an edge as used in a face
- * if used in a face at all, otherwise just assign as used in the edge.
- *
- * Useful to get a deterministic winding order when calling
- * BM_face_create_ngon() on an arbitrary array of verts,
- * though be sure to pick an edge which has a face.
- *
- * \note This is in fact quite a simple check,
- * mainly include this function so the intent is more obvious.
- * We know these 2 verts will _always_ make up the loops edge
- */
void BM_edge_ordered_verts_ex(const BMEdge *edge,
BMVert **r_v1,
BMVert **r_v2,
@@ -1466,9 +1157,6 @@ void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
BM_edge_ordered_verts_ex(edge, r_v1, r_v2, edge->l);
}
-/**
- * \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
- */
BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
{
BMLoop *l_step = l->prev;
@@ -1486,9 +1174,6 @@ BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
return l_step;
}
-/**
- * \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
- */
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
{
BMLoop *l_step = l->next;
@@ -1506,10 +1191,6 @@ BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq
return l_step;
}
-/**
- * Check if the loop is convex or concave
- * (depends on face normal)
- */
bool BM_loop_is_convex(const BMLoop *l)
{
float e_dir_prev[3];
@@ -1522,26 +1203,11 @@ bool BM_loop_is_convex(const BMLoop *l)
return dot_v3v3(l_no, l->f->no) > 0.0f;
}
-/**
- * Calculates the angle between the previous and next loops
- * (angle at this loops face corner).
- *
- * \return angle in radians
- */
float BM_loop_calc_face_angle(const BMLoop *l)
{
return angle_v3v3v3(l->prev->v->co, l->v->co, l->next->v->co);
}
-/**
- * \brief BM_loop_calc_face_normal
- *
- * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
- *
- * \param l: The loop to calculate the normal at.
- * \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
- * \param r_normal: Resulting normal.
- */
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
{
/* NOTE: we cannot use result of normal_tri_v3 here to detect colinear vectors
@@ -1571,9 +1237,6 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
return 0.0f;
}
-/**
- * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
- */
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
@@ -1604,11 +1267,6 @@ float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
return 0.0f;
}
-/**
- * #BM_loop_calc_face_normal_safe_ex with predefined sane epsilon.
- *
- * Since this doesn't scale based on triangle size, fixed value works well.
- */
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
{
return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
@@ -1623,15 +1281,6 @@ float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal);
}
-/**
- * \brief BM_loop_calc_face_normal
- *
- * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
- *
- * \param l: The loop to calculate the normal at
- * \param r_normal: Resulting normal
- * \return The length of the cross product (double the area).
- */
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
{
float v1[3], v2[3];
@@ -1646,14 +1295,6 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
return len;
}
-/**
- * \brief BM_loop_calc_face_direction
- *
- * Calculate the direction a loop is pointing.
- *
- * \param l: The loop to calculate the direction at
- * \param r_dir: Resulting direction
- */
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
{
float v_prev[3];
@@ -1669,15 +1310,6 @@ void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
normalize_v3(r_dir);
}
-/**
- * \brief BM_loop_calc_face_tangent
- *
- * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
- * This vector always points inward into the face.
- *
- * \param l: The loop to calculate the tangent at
- * \param r_tangent: Resulting tangent
- */
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
{
float v_prev[3];
@@ -1708,14 +1340,6 @@ void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
normalize_v3(r_tangent);
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
{
if (BM_edge_is_manifold(e)) {
@@ -1730,14 +1354,6 @@ float BM_edge_calc_face_angle(const BMEdge *e)
return BM_edge_calc_face_angle_ex(e, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces in world space.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
const float imat3[3][3],
const float fallback)
@@ -1764,14 +1380,6 @@ float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3
return BM_edge_calc_face_angle_with_imat3_ex(e, imat3, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE ANGLE
- *
- * Calculates the angle between two faces.
- * Assumes the face normals are correct.
- *
- * \return angle in radians
- */
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
{
if (BM_edge_is_manifold(e)) {
@@ -1787,19 +1395,6 @@ float BM_edge_calc_face_angle_signed(const BMEdge *e)
return BM_edge_calc_face_angle_signed_ex(e, DEG2RADF(90.0f));
}
-/**
- * \brief BMESH EDGE/FACE TANGENT
- *
- * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
- * This vector always points inward into the face.
- *
- * \brief BM_edge_calc_face_tangent
- * \param e:
- * \param e_loop: The loop to calculate the tangent at,
- * used to get the face and winding direction.
- * \param r_tangent: The loop corner tangent to set
- */
-
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
{
float tvec[3];
@@ -1813,13 +1408,6 @@ void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_ta
normalize_v3(r_tangent);
}
-/**
- * \brief BMESH VERT/EDGE ANGLE
- *
- * Calculates the angle a verts 2 edges.
- *
- * \returns the angle in radians
- */
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
{
BMEdge *e1, *e2;
@@ -1843,10 +1431,6 @@ float BM_vert_calc_edge_angle(const BMVert *v)
return BM_vert_calc_edge_angle_ex(v, DEG2RADF(90.0f));
}
-/**
- * \note this isn't optimal to run on an array of verts,
- * see 'solidify_add_thickness' for a function which runs on an array.
- */
float BM_vert_calc_shell_factor(const BMVert *v)
{
BMIter iter;
@@ -1865,8 +1449,6 @@ float BM_vert_calc_shell_factor(const BMVert *v)
}
return 1.0f;
}
-/* alternate version of #BM_vert_calc_shell_factor which only
- * uses 'hflag' faces, but falls back to all if none found. */
float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
{
BMIter iter;
@@ -1896,10 +1478,6 @@ float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const cha
return 1.0f;
}
-/**
- * \note quite an obscure function.
- * used in bmesh operators that have a relative scale options,
- */
float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
{
BMIter iter;
@@ -1920,9 +1498,6 @@ float BM_vert_calc_median_tagged_edge_length(const BMVert *v)
return 0.0f;
}
-/**
- * Returns the loop of the shortest edge in f.
- */
BMLoop *BM_face_find_shortest_loop(BMFace *f)
{
BMLoop *shortest_loop = NULL;
@@ -1944,9 +1519,6 @@ BMLoop *BM_face_find_shortest_loop(BMFace *f)
return shortest_loop;
}
-/**
- * Returns the loop of the longest edge in f.
- */
BMLoop *BM_face_find_longest_loop(BMFace *f)
{
BMLoop *longest_loop = NULL;
@@ -2020,11 +1592,6 @@ BMEdge *BM_edge_exists(BMVert *v_a, BMVert *v_b)
}
#endif
-/**
- * Returns an edge sharing the same vertices as this one.
- * This isn't an invalid state but tools should clean up these cases before
- * returning the mesh to the user.
- */
BMEdge *BM_edge_find_double(BMEdge *e)
{
BMVert *v = e->v1;
@@ -2042,10 +1609,6 @@ BMEdge *BM_edge_find_double(BMEdge *e)
return NULL;
}
-/**
- * Only #BMEdge.l access us needed, however when we want the first visible loop,
- * a utility function is needed.
- */
BMLoop *BM_edge_find_first_loop_visible(BMEdge *e)
{
if (e->l != NULL) {
@@ -2060,13 +1623,6 @@ BMLoop *BM_edge_find_first_loop_visible(BMEdge *e)
return NULL;
}
-/**
- * Given a set of vertices (varr), find out if
- * there is a face with exactly those vertices
- * (and only those vertices).
- *
- * \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
- */
BMFace *BM_face_exists(BMVert **varr, int len)
{
if (varr[0]->e) {
@@ -2115,9 +1671,6 @@ BMFace *BM_face_exists(BMVert **varr, int len)
return NULL;
}
-/**
- * Check if the face has an exact duplicate (both winding directions).
- */
BMFace *BM_face_find_double(BMFace *f)
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
@@ -2150,18 +1703,6 @@ BMFace *BM_face_find_double(BMFace *f)
return NULL;
}
-/**
- * Given a set of vertices and edges (\a varr, \a earr), find out if
- * all those vertices are filled in by existing faces that _only_ use those vertices.
- *
- * This is for use in cases where creating a face is possible but would result in
- * many overlapping faces.
- *
- * An example of how this is used: when 2 tri's are selected that share an edge,
- * pressing Fkey would make a new overlapping quad (without a check like this)
- *
- * \a earr and \a varr can be in any order, however they _must_ form a closed loop.
- */
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
{
BMFace *f;
@@ -2270,7 +1811,6 @@ finally:
return ok;
}
-/* same as 'BM_face_exists_multi' but built vert array from edges */
bool BM_face_exists_multi_edge(BMEdge **earr, int len)
{
BMVert **varr = BLI_array_alloca(varr, len);
@@ -2284,20 +1824,6 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len)
return BM_face_exists_multi(varr, earr, len);
}
-/**
- * Given a set of vertices (varr), find out if
- * all those vertices overlap an existing face.
- *
- * \note The face may contain other verts \b not in \a varr.
- *
- * \note Its possible there are more than one overlapping faces,
- * in this case the first one found will be returned.
- *
- * \param varr: Array of unordered verts.
- * \param len: \a varr array length.
- * \return The face or NULL.
- */
-
BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
{
BMIter viter;
@@ -2336,14 +1862,6 @@ BMFace *BM_face_exists_overlap(BMVert **varr, const int len)
return f_overlap;
}
-/**
- * Given a set of vertices (varr), find out if
- * there is a face that uses vertices only from this list
- * (that the face is a subset or made from the vertices given).
- *
- * \param varr: Array of unordered verts.
- * \param len: varr array length.
- */
bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
{
BMIter viter;
@@ -2477,7 +1995,6 @@ bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
return false;
}
-/* convenience functions for checking flags */
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
{
return (BM_elem_flag_test(e->v1, hflag) || BM_elem_flag_test(e->v2, hflag));
@@ -2527,9 +2044,6 @@ bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len)
return false;
}
-/**
- * Use within assert's to check normals are valid.
- */
bool BM_face_is_normal_valid(const BMFace *f)
{
const float eps = 0.0001f;
@@ -2591,23 +2105,6 @@ double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
return vol;
}
-/* NOTE: almost duplicate of #BM_mesh_calc_edge_groups, keep in sync. */
-/**
- * Calculate isolated groups of faces with optional filtering.
- *
- * \param bm: the BMesh.
- * \param r_groups_array: Array of ints to fill in, length of bm->totface
- * (or when hflag_test is set, the number of flagged faces).
- * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
- * int pairs: (array_start, array_length).
- * \param filter_fn: Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
- * \param user_data: Optional user data for \a filter_fn, can be NULL.
- * \param hflag_test: Optional flag to test faces,
- * use to exclude faces from the calculation, 0 for all faces.
- * \param htype_step: BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges
- * (having both set is supported too).
- * \return The number of groups found.
- */
int BM_mesh_calc_face_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -2617,6 +2114,8 @@ int BM_mesh_calc_face_groups(BMesh *bm,
const char hflag_test,
const char htype_step)
{
+ /* NOTE: almost duplicate of #BM_mesh_calc_edge_groups, keep in sync. */
+
#ifdef DEBUG
int group_index_len = 1;
#else
@@ -2755,25 +2254,6 @@ int BM_mesh_calc_face_groups(BMesh *bm,
return group_curr;
}
-/* NOTE: almost duplicate of #BM_mesh_calc_face_groups, keep in sync. */
-/**
- * Calculate isolated groups of edges with optional filtering.
- *
- * \param bm: the BMesh.
- * \param r_groups_array: Array of ints to fill in, length of bm->totedge
- * (or when hflag_test is set, the number of flagged edges).
- * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
- * int pairs: (array_start, array_length).
- * \param filter_fn: Filter the edges or verts we step over (depends on \a htype_step)
- * as to which types we deal with.
- * \param user_data: Optional user data for \a filter_fn, can be NULL.
- * \param hflag_test: Optional flag to test edges,
- * use to exclude edges from the calculation, 0 for all edges.
- * \return The number of groups found.
- *
- * \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
- * since we always walk over verts.
- */
int BM_mesh_calc_edge_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -2781,6 +2261,8 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
void *user_data,
const char hflag_test)
{
+ /* NOTE: almost duplicate of #BM_mesh_calc_face_groups, keep in sync. */
+
#ifdef DEBUG
int group_index_len = 1;
#else
@@ -2892,13 +2374,6 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
return group_curr;
}
-/**
- * This is an alternative to #BM_mesh_calc_edge_groups.
- *
- * While we could call this, then create vertex & face arrays,
- * it requires looping over geometry connectivity twice,
- * this slows down edit-mesh separate by loose parts, see: T70864.
- */
int BM_mesh_calc_edge_groups_as_arrays(
BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int (**r_groups)[3])
{
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index 021358f81ad..48a1d100c72 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -20,11 +20,24 @@
* \ingroup bmesh
*/
+/**
+ * Returns true if the vertex is used in a given face.
+ */
bool BM_vert_in_face(BMVert *v, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Compares the number of vertices in an array
+ * that appear in a given face
+ */
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return true if all verts are in the face.
+ */
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns whether or not a given edge is part of a given face.
+ */
bool BM_edge_in_face(const BMEdge *e, const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -35,27 +48,175 @@ BLI_INLINE bool BM_verts_in_edge(const BMVert *v1,
const BMVert *v2,
const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns edge length
+ */
float BM_edge_calc_length(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns edge length squared (for comparisons)
+ */
float BM_edge_calc_length_squared(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Utility function, since enough times we have an edge
+ * and want to access 2 connected faces.
+ *
+ * \return true when only 2 faces are found.
+ */
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb) ATTR_NONNULL();
+/**
+ * Utility function, since enough times we have an edge
+ * and want to access 2 connected loops.
+ *
+ * \return true when only 2 faces are found.
+ */
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb) ATTR_NONNULL();
BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Given a edge and a loop (assumes the edge is manifold). returns
+ * the other faces loop, sharing the same vertex.
+ *
+ * <pre>
+ * +-------------------+
+ * | |
+ * | |
+ * |l_other <-- return |
+ * +-------------------+ <-- A manifold edge between 2 faces
+ * |l e <-- edge |
+ * |^ <-------- loop |
+ * | |
+ * +-------------------+
+ * </pre>
+ */
BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing an Edge
+ *
+ * Finds the other loop that shares \a v with \a e loop in \a f.
+ * <pre>
+ * +----------+
+ * | |
+ * | f |
+ * | |
+ * +----------+ <-- return the face loop of this vertex.
+ * v --> e
+ * ^ ^ <------- These vert args define direction
+ * in the face to check.
+ * The faces loop direction is ignored.
+ * </pre>
+ *
+ * \note caller must ensure \a e is used in \a f
+ */
BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * See #BM_face_other_edge_loop This is the same functionality
+ * to be used when the edges loop is already known.
+ */
BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing a Vertex
+ *
+ * Finds the other loop in a face.
+ *
+ * This function returns a loop in \a f that shares an edge with \a v
+ * The direction is defined by \a v_prev, where the return value is
+ * the loop of what would be 'v_next'
+ * <pre>
+ * +----------+ <-- return the face loop of this vertex.
+ * | |
+ * | f |
+ * | |
+ * +----------+
+ * v_prev --> v
+ * ^^^^^^ ^ <-- These vert args define direction
+ * in the face to check.
+ * The faces loop direction is ignored.
+ * </pre>
+ *
+ * \note \a v_prev and \a v _implicitly_ define an edge.
+ */
BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Return the other loop that uses this edge.
+ *
+ * In this case the loop defines the vertex,
+ * the edge passed in defines the direction to step.
+ *
+ * <pre>
+ * +----------+ <-- Return the face-loop of this vertex.
+ * | |
+ * | e | <-- This edge defines the direction.
+ * | |
+ * +----------+ <-- This loop defines the face and vertex..
+ * l
+ * </pre>
+ *
+ */
BMLoop *BM_loop_other_vert_loop_by_edge(BMLoop *l, BMEdge *e) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief Other Loop in Face Sharing a Vert
+ *
+ * Finds the other loop that shares \a v with \a e loop in \a f.
+ * <pre>
+ * +----------+ <-- return the face loop of this vertex.
+ * | |
+ * | |
+ * | |
+ * +----------+ <-- This vertex defines the direction.
+ * l v
+ * ^ <------- This loop defines both the face to search
+ * and the edge, in combination with 'v'
+ * The faces loop direction is ignored.
+ * </pre>
+ */
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Utility function to step around a fan of loops,
+ * using an edge to mark the previous side.
+ *
+ * \note all edges must be manifold,
+ * once a non manifold edge is hit, return NULL.
+ *
+ * \code{.unparsed}
+ * ,.,-->|
+ * _,-' |
+ * ,' | (notice how 'e_step'
+ * / | and 'l' define the
+ * / | direction the arrow
+ * | return | points).
+ * | loop --> |
+ * ---------------------+---------------------
+ * ^ l --> |
+ * | |
+ * assign e_step |
+ * |
+ * begin e_step ----> |
+ * |
+ * \endcode
+ */
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Get the first loop of a vert. Uses the same initialization code for the first loop of the
+ * iterator API
+ */
BMLoop *BM_vert_find_first_loop(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BM_vert_find_first_loop that ignores hidden loops.
+ */
BMLoop *BM_vert_find_first_loop_visible(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Only #BMEdge.l access us needed, however when we want the first visible loop,
+ * a utility function is needed.
+ */
BMLoop *BM_edge_find_first_loop_visible(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if verts share a face.
+ */
bool BM_vert_pair_share_face_check(BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
@@ -70,11 +231,21 @@ BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
void *user_data,
BMLoop **r_l_a,
BMLoop **r_l_b) ATTR_NONNULL(1, 2, 4, 6, 7);
+/**
+ * Given 2 verts, find the smallest face they share and give back both loops.
+ */
BMFace *BM_vert_pair_share_face_by_len(BMVert *v_a,
BMVert *v_b,
BMLoop **r_l_a,
BMLoop **r_l_b,
const bool allow_adjacent) ATTR_NONNULL();
+/**
+ * Given 2 verts,
+ * find a face they share that has the lowest angle across these verts and give back both loops.
+ *
+ * This can be better than #BM_vert_pair_share_face_by_len
+ * because concave splits are ranked lowest.
+ */
BMFace *BM_vert_pair_share_face_by_angle(BMVert *v_a,
BMVert *v_b,
BMLoop **r_l_a,
@@ -92,57 +263,169 @@ int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NON
#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == (n) + 1)
int BM_vert_edge_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of edges around this vertex.
+ */
int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == n)
#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_at_most(e, (n) + 1) == (n) + 1)
int BM_edge_face_count_at_most(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of faces around this edge
+ */
int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == n)
#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_at_most(v, (n) + 1) == (n) + 1)
int BM_vert_face_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of faces around this vert
+ * length matches #BM_LOOPS_OF_VERT iterator
+ */
int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
+ * All edges in the fan must be manifold, otherwise return NULL.
+ *
+ * \note This could (probably) be done more efficiently.
+ */
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Fast alternative to `(BM_vert_edge_count(v) == 2)`.
+ */
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Fast alternative to `(BM_vert_edge_count(v) == 2)`
+ * that checks both edges connect to the same faces.
+ */
bool BM_vert_is_edge_pair_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Access a verts 2 connected edges.
+ *
+ * \return true when only 2 verts are found.
+ */
bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
+/**
+ * Return true if the vertex is connected to _any_ faces.
+ *
+ * same as `BM_vert_face_count(v) != 0` or `BM_vert_find_first_loop(v) == NULL`.
+ */
bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Tests whether or not the vertex is part of a wire edge.
+ * (ie: has no faces attached to it)
+ */
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A vertex is non-manifold if it meets the following conditions:
+ * 1: Loose - (has no edges/faces incident upon it).
+ * 2: Joins two distinct regions - (two pyramids joined at the tip).
+ * 3: Is part of an edge with more than 2 faces.
+ * 4: Is part of a wire edge.
+ */
bool BM_vert_is_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * A version of #BM_vert_is_manifold
+ * which only checks if we're connected to multiple isolated regions.
+ */
bool BM_vert_is_manifold_region(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_boundary(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if the edge is convex or concave
+ * (depends on face winding)
+ */
bool BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return true when loop customdata is contiguous.
+ */
bool BM_edge_is_contiguous_loop_cd(const BMEdge *e,
const int cd_loop_type,
const int cd_loop_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * The number of loops connected to this loop (not including disconnected regions).
+ */
int BM_loop_region_loops_count_at_most(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
int BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Check if the loop is convex or concave
+ * (depends on face normal)
+ */
bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if a point is inside the corner defined by a loop
+ * (within the 2 planes defined by the loops corner & face normal).
+ *
+ * \return signed, squared distance to the loops planes, less than 0.0 when outside.
+ */
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if a point is inside the edge defined by a loop
+ * (within the plane defined by the loops edge & face normal).
+ *
+ * \return signed, squared distance to the edge plane, less than 0.0 when outside.
+ */
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \return The previous loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
+ */
BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
+/**
+ * \return The next loop, over \a eps_sq distance from \a l (or \a NULL if l_stop is reached).
+ */
BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq);
+/**
+ * Calculates the angle between the previous and next loops
+ * (angle at this loops face corner).
+ *
+ * \return angle in radians
+ */
float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BM_loop_calc_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
+ *
+ * \param l: The loop to calculate the normal at
+ * \param r_normal: Resulting normal
+ * \return The length of the cross product (double the area).
+ */
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+/**
+ * #BM_loop_calc_face_normal_safe_ex with predefined sane epsilon.
+ *
+ * Since this doesn't scale based on triangle size, fixed value works well.
+ */
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
-float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3])
+/**
+ * \brief BM_loop_calc_face_normal
+ *
+ * Calculate the normal at this loop corner or fallback to the face normal on straight lines.
+ *
+ * \param l: The loop to calculate the normal at.
+ * \param epsilon_sq: Value to avoid numeric errors (1e-5f works well).
+ * \param r_normal: Resulting normal.
+ */
+float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3])
ATTR_NONNULL();
+/**
+ * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
+ */
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
@@ -153,15 +436,56 @@ float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
float const (*vertexCos)[3],
float r_normal[3]) ATTR_NONNULL();
+/**
+ * \brief BM_loop_calc_face_direction
+ *
+ * Calculate the direction a loop is pointing.
+ *
+ * \param l: The loop to calculate the direction at
+ * \param r_dir: Resulting direction
+ */
void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3]);
+/**
+ * \brief BM_loop_calc_face_tangent
+ *
+ * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
+ * This vector always points inward into the face.
+ *
+ * \param l: The loop to calculate the tangent at
+ * \param r_tangent: Resulting tangent
+ */
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e,
const float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BMESH EDGE/FACE ANGLE
+ *
+ * Calculates the angle between two faces in world space.
+ * Assumes the face normals are correct.
+ *
+ * \return angle in radians
+ */
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
const float imat3[3][3],
const float fallback) ATTR_WARN_UNUSED_RESULT
@@ -170,55 +494,210 @@ float BM_edge_calc_face_angle_with_imat3(const BMEdge *e,
const float imat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BMESH EDGE/FACE TANGENT
+ *
+ * Calculate the tangent at this loop corner or fallback to the face normal on straight lines.
+ * This vector always points inward into the face.
+ *
+ * \brief BM_edge_calc_face_tangent
+ * \param e:
+ * \param e_loop: The loop to calculate the tangent at,
+ * used to get the face and winding direction.
+ * \param r_tangent: The loop corner tangent to set
+ */
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
ATTR_NONNULL();
float BM_vert_calc_edge_angle(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief BMESH VERT/EDGE ANGLE
+ *
+ * Calculates the angle a verts 2 edges.
+ *
+ * \returns the angle in radians
+ */
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \note this isn't optimal to run on an array of verts,
+ * see 'solidify_add_thickness' for a function which runs on an array.
+ */
float BM_vert_calc_shell_factor(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/* alternate version of #BM_vert_calc_shell_factor which only
+ * uses 'hflag' faces, but falls back to all if none found. */
float BM_vert_calc_shell_factor_ex(const BMVert *v,
const float no[3],
const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \note quite an obscure function.
+ * used in bmesh operators that have a relative scale options,
+ */
float BM_vert_calc_median_tagged_edge_length(const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the loop of the shortest edge in f.
+ */
BMLoop *BM_face_find_shortest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns the loop of the longest edge in f.
+ */
BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_edge_exists(BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns an edge sharing the same vertices as this one.
+ * This isn't an invalid state but tools should clean up these cases before
+ * returning the mesh to the user.
+ */
BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Given a set of vertices (varr), find out if
+ * there is a face with exactly those vertices
+ * (and only those vertices).
+ *
+ * \note there used to be a BM_face_exists_overlap function that checks for partial overlap.
+ */
BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
+/**
+ * Check if the face has an exact duplicate (both winding directions).
+ */
BMFace *BM_face_find_double(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Given a set of vertices and edges (\a varr, \a earr), find out if
+ * all those vertices are filled in by existing faces that _only_ use those vertices.
+ *
+ * This is for use in cases where creating a face is possible but would result in
+ * many overlapping faces.
+ *
+ * An example of how this is used: when 2 tri's are selected that share an edge,
+ * pressing Fkey would make a new overlapping quad (without a check like this)
+ *
+ * \a earr and \a varr can be in any order, however they _must_ form a closed loop.
+ */
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/* same as 'BM_face_exists_multi' but built vert array from edges */
bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Given a set of vertices (varr), find out if
+ * all those vertices overlap an existing face.
+ *
+ * \note The face may contain other verts \b not in \a varr.
+ *
+ * \note Its possible there are more than one overlapping faces,
+ * in this case the first one found will be returned.
+ *
+ * \param varr: Array of unordered verts.
+ * \param len: \a varr array length.
+ * \return The face or NULL.
+ */
BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Given a set of vertices (varr), find out if
+ * there is a face that uses vertices only from this list
+ * (that the face is a subset or made from the vertices given).
+ *
+ * \param varr: Array of unordered verts.
+ * \param len: varr array length.
+ */
bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Returns the number of faces that are adjacent to both f1 and f2,
+ * \note Could be sped up a bit by not using iterators and by tagging
+ * faces on either side, then count the tags rather then searching.
+ */
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Counts the number of edges two faces share (if any)
+ */
int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Counts the number of verts two faces share (if any).
+ */
int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * same as #BM_face_share_face_count but returns a bool
+ */
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the faces share an edge
+ */
bool BM_face_share_edge_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true if the faces share a vert.
+ */
bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Returns true when 2 loops share an edge (are adjacent in the face-fan)
+ */
bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Test if e1 shares any faces with e2
+ */
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Test if e1 shares any quad faces with e2
+ */
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Tests to see if e1 shares a vertex with e2
+ */
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Return the shared vertex between the two edges or NULL
+ */
BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Edge and Vert
+ *
+ * Finds the loop used which uses \a in face loop \a l
+ *
+ * \note this function takes a loop rather than an edge
+ * so we can select the face that the loop should be from.
+ */
BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Face and Vertex
+ *
+ * Finds the loop used which uses \a v in face loop \a l
+ *
+ * \note currently this just uses simple loop in future may be sped up
+ * using radial vars
+ */
BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief Return the Loop Shared by Face and Edge
+ *
+ * Finds the loop used which uses \a e in face loop \a l
+ *
+ * \note currently this just uses simple loop in future may be sped up
+ * using radial vars
+ */
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2) ATTR_NONNULL();
+/**
+ * Returns the verts of an edge as used in a face
+ * if used in a face at all, otherwise just assign as used in the edge.
+ *
+ * Useful to get a deterministic winding order when calling
+ * BM_face_create_ngon() on an arbitrary array of verts,
+ * though be sure to pick an edge which has a face.
+ *
+ * \note This is in fact quite a simple check,
+ * mainly include this function so the intent is more obvious.
+ * We know these 2 verts will _always_ make up the loops edge
+ */
void BM_edge_ordered_verts_ex(const BMEdge *edge,
BMVert **r_v1,
BMVert **r_v2,
@@ -234,6 +713,7 @@ bool BM_edge_is_all_face_flag_test(const BMEdge *e,
const char hflag,
const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/* convenience functions for checking flags */
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
@@ -246,10 +726,29 @@ bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_
bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Use within assert's to check normals are valid.
+ */
bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
double BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Calculate isolated groups of faces with optional filtering.
+ *
+ * \param bm: the BMesh.
+ * \param r_groups_array: Array of ints to fill in, length of bm->totface
+ * (or when hflag_test is set, the number of flagged faces).
+ * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
+ * int pairs: (array_start, array_length).
+ * \param filter_fn: Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
+ * \param user_data: Optional user data for \a filter_fn, can be NULL.
+ * \param hflag_test: Optional flag to test faces,
+ * use to exclude faces from the calculation, 0 for all faces.
+ * \param htype_step: BM_VERT to walk over face-verts, BM_EDGE to walk over faces edges
+ * (having both set is supported too).
+ * \return The number of groups found.
+ */
int BM_mesh_calc_face_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -258,6 +757,24 @@ int BM_mesh_calc_face_groups(BMesh *bm,
void *user_data,
const char hflag_test,
const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+/**
+ * Calculate isolated groups of edges with optional filtering.
+ *
+ * \param bm: the BMesh.
+ * \param r_groups_array: Array of ints to fill in, length of `bm->totedge`
+ * (or when hflag_test is set, the number of flagged edges).
+ * \param r_group_index: index, length pairs into \a r_groups_array, size of return value
+ * int pairs: (array_start, array_length).
+ * \param filter_fn: Filter the edges or verts we step over (depends on \a htype_step)
+ * as to which types we deal with.
+ * \param user_data: Optional user data for \a filter_fn, can be NULL.
+ * \param hflag_test: Optional flag to test edges,
+ * use to exclude edges from the calculation, 0 for all edges.
+ * \return The number of groups found.
+ *
+ * \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
+ * since we always walk over verts.
+ */
int BM_mesh_calc_edge_groups(BMesh *bm,
int *r_groups_array,
int (**r_group_index)[2],
@@ -265,6 +782,13 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
void *user_data,
const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+/**
+ * This is an alternative to #BM_mesh_calc_edge_groups.
+ *
+ * While we could call this, then create vertex & face arrays,
+ * it requires looping over geometry connectivity twice,
+ * this slows down edit-mesh separate by loose parts, see: T70864.
+ */
int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm,
BMVert **verts,
BMEdge **edges,
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.c b/source/blender/bmesh/intern/bmesh_query_uv.c
index f9b87e4e71c..f069613f5b3 100644
--- a/source/blender/bmesh/intern/bmesh_query_uv.c
+++ b/source/blender/bmesh/intern/bmesh_query_uv.c
@@ -48,14 +48,6 @@ static void uv_aspect(const BMLoop *l,
*/
#define UV_ASPECT(l, r_uv) uv_aspect(l, aspect, cd_loop_uv_offset, r_uv)
-/**
- * Computes the UV center of a face, using the mean average weighted by edge length.
- *
- * See #BM_face_calc_center_median_weighted for matching spatial functionality.
- *
- * \param aspect: Calculate the center scaling by these values, and finally dividing.
- * Since correct weighting depends on having the correct aspect.
- */
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
const int cd_loop_uv_offset,
@@ -109,9 +101,6 @@ void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset,
mul_v2_fl(r_cent, 1.0f / (float)f->len);
}
-/**
- * Calculate the UV cross product (use the sign to check the winding).
- */
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset)
{
float(*uvs)[2] = BLI_array_alloca(uvs, f->len);
@@ -148,9 +137,6 @@ void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop
} while ((l_iter = l_iter->next) != l_first);
}
-/**
- * Check if two loops that share an edge also have the same UV coordinates.
- */
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->e == l_b->e);
@@ -165,9 +151,6 @@ bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
equals_v2v2(luv_a_next->uv, luv_b_next->uv));
}
-/**
- * Check if two loops that share a vertex also have the same UV coordinates.
- */
bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->v == l_b->v);
@@ -179,9 +162,6 @@ bool BM_loop_uv_share_vert_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_
return true;
}
-/**
- * Check if two loops that share a vertex also have the same UV coordinates.
- */
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
{
BLI_assert(l_a->v == l_b->v);
@@ -204,9 +184,6 @@ bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int
return true;
}
-/**
- * Check if the point is inside the UV face.
- */
bool BM_face_uv_point_inside_test(const BMFace *f, const float co[2], const int cd_loop_uv_offset)
{
float(*projverts)[2] = BLI_array_alloca(projverts, f->len);
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.h b/source/blender/bmesh/intern/bmesh_query_uv.h
index 850b27d3894..d63b8e5e701 100644
--- a/source/blender/bmesh/intern/bmesh_query_uv.h
+++ b/source/blender/bmesh/intern/bmesh_query_uv.h
@@ -27,6 +27,14 @@ float BM_loop_uv_calc_edge_length(const BMLoop *l,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Computes the UV center of a face, using the mean average weighted by edge length.
+ *
+ * See #BM_face_calc_center_median_weighted for matching spatial functionality.
+ *
+ * \param aspect: Calculate the center scaling by these values, and finally dividing.
+ * Since correct weighting depends on having the correct aspect.
+ */
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
const int cd_loop_uv_offset,
@@ -34,6 +42,9 @@ void BM_face_uv_calc_center_median_weighted(const BMFace *f,
void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2])
ATTR_NONNULL();
+/**
+ * Calculate the UV cross product (use the sign to check the winding).
+ */
float BM_face_uv_calc_cross(const BMFace *f, const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -46,19 +57,31 @@ bool BM_loop_uv_share_edge_check_with_limit(BMLoop *l_a,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if two loops that share an edge also have the same UV coordinates.
+ */
bool BM_loop_uv_share_edge_check(BMLoop *l_a,
BMLoop *l_b,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if two loops that share a vertex also have the same UV coordinates.
+ */
bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * Check if two loops that share a vertex also have the same UV coordinates.
+ */
bool BM_loop_uv_share_vert_check(BMLoop *l_a,
BMLoop *l_b,
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Check if the point is inside the UV face.
+ */
bool BM_face_uv_point_inside_test(const BMFace *f,
const float co[2],
const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index 1f1ad0bae5b..08b0920c115 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -47,11 +47,6 @@ void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
}
}
-/**
- * Handles all connected data, use with care.
- *
- * Assumes caller has setup correct state before the swap is done.
- */
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
{
/* swap out loops */
@@ -268,14 +263,6 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
return true;
}
-/**
- * \brief DISK COUNT FACE VERT
- *
- * Counts the number of loop users
- * for this vertex. Note that this is
- * equivalent to counting the number of
- * faces incident upon this vertex
- */
int bmesh_disk_facevert_count(const BMVert *v)
{
/* is there an edge on this vert at all */
@@ -315,14 +302,6 @@ int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max)
return count;
}
-/**
- * \brief FIND FIRST FACE EDGE
- *
- * Finds the first edge in a vertices
- * Disk cycle that has one of this
- * vert's loops attached
- * to it.
- */
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -334,11 +313,6 @@ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
return NULL;
}
-/**
- * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
- *
- * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
- */
BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -350,9 +324,6 @@ BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
return NULL;
}
-/**
- * A version of #bmesh_disk_faceloop_find_first that ignores hidden faces.
- */
BMLoop *bmesh_disk_faceloop_find_first_visible(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_iter = e;
@@ -384,7 +355,6 @@ BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v)
return (BMEdge *)e;
}
-/*****radial cycle functions, e.g. loops surrounding edges**** */
bool bmesh_radial_validate(int radlen, BMLoop *l)
{
BMLoop *l_iter = l;
@@ -442,14 +412,6 @@ void bmesh_radial_loop_append(BMEdge *e, BMLoop *l)
l->e = e;
}
-/**
- * \brief BMESH RADIAL REMOVE LOOP
- *
- * Removes a loop from an radial cycle. If edge e is non-NULL
- * it should contain the radial cycle, and it will also get
- * updated (in the case that the edge's link into the radial
- * cycle was the loop which is being removed from the cycle).
- */
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
{
/* if e is non-NULL, l must be in the radial cycle of e */
@@ -480,10 +442,6 @@ void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
l->e = NULL;
}
-/**
- * A version of #bmesh_radial_loop_remove which only performs the radial unlink,
- * leaving the edge untouched.
- */
void bmesh_radial_loop_unlink(BMLoop *l)
{
if (l->radial_next != l) {
@@ -497,12 +455,6 @@ void bmesh_radial_loop_unlink(BMLoop *l)
l->e = NULL;
}
-/**
- * \brief BME RADIAL FIND FIRST FACE VERT
- *
- * Finds the first loop of v around radial
- * cycle
- */
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -553,12 +505,6 @@ int bmesh_radial_length(const BMLoop *l)
return i;
}
-/**
- * \brief RADIAL COUNT FACE VERT
- *
- * Returns the number of times a vertex appears
- * in a radial cycle
- */
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -590,11 +536,6 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const
return count;
}
-/**
- * \brief RADIAL CHECK FACE VERT
- *
- * Quicker check for `bmesh_radial_facevert_count(...) != 0`.
- */
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
{
const BMLoop *l_iter;
@@ -608,7 +549,6 @@ bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
return false;
}
-/*****loop cycle functions, e.g. loops surrounding a face**** */
bool bmesh_loop_validate(BMFace *f)
{
int i;
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index ca51a9c39de..e2e26a69d44 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -31,6 +31,7 @@
*/
/* LOOP CYCLE MANAGEMENT */
+/*****loop cycle functions, e.g. loops surrounding a face**** */
bool bmesh_loop_validate(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* DISK CYCLE MANAGEMENT */
@@ -48,11 +49,35 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W
ATTR_NONNULL();
int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief DISK COUNT FACE VERT
+ *
+ * Counts the number of loop users
+ * for this vertex. Note that this is
+ * equivalent to counting the number of
+ * faces incident upon this vertex
+ */
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \brief FIND FIRST FACE EDGE
+ *
+ * Finds the first edge in a vertices
+ * Disk cycle that has one of this
+ * vert's loops attached
+ * to it.
+ */
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls.
+ *
+ * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first
+ */
BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * A version of #bmesh_disk_faceloop_find_first that ignores hidden faces.
+ */
BMLoop *bmesh_disk_faceloop_find_first_visible(const BMEdge *e,
const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -61,7 +86,19 @@ BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WAR
/* RADIAL CYCLE MANAGEMENT */
void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+/**
+ * \brief BMESH RADIAL REMOVE LOOP
+ *
+ * Removes a loop from an radial cycle. If edge e is non-NULL
+ * it should contain the radial cycle, and it will also get
+ * updated (in the case that the edge's link into the radial
+ * cycle was the loop which is being removed from the cycle).
+ */
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+/**
+ * A version of #bmesh_radial_loop_remove which only performs the radial unlink,
+ * leaving the edge untouched.
+ */
void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
/* NOTE:
* bmesh_radial_loop_next(BMLoop *l) / prev.
@@ -71,20 +108,43 @@ int bmesh_radial_facevert_count_at_most(const BMLoop *l,
const BMVert *v,
const int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief RADIAL COUNT FACE VERT
+ *
+ * Returns the number of times a vertex appears
+ * in a radial cycle
+ */
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief RADIAL CHECK FACE VERT
+ *
+ * Quicker check for `bmesh_radial_facevert_count(...) != 0`.
+ */
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/**
+ * \brief BME RADIAL FIND FIRST FACE VERT
+ *
+ * Finds the first loop of v around radial
+ * cycle
+ */
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+/*****radial cycle functions, e.g. loops surrounding edges**** */
bool bmesh_radial_validate(int radlen, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* EDGE UTILITIES */
void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
+/**
+ * Handles all connected data, use with care.
+ *
+ * Assumes caller has setup correct state before the swap is done.
+ */
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
index b8fdd534842..e1f7430bc53 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.c
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -60,12 +60,6 @@ void *BMW_begin(BMWalker *walker, void *start)
return BMW_current_state(walker) ? walker->step(walker) : NULL;
}
-/**
- * \brief Init Walker
- *
- * Allocates and returns a new mesh walker of a given type.
- * The elements visited are filtered by the bitmask 'searchmask'.
- */
void BMW_init(BMWalker *walker,
BMesh *bm,
int type,
@@ -124,11 +118,6 @@ void BMW_init(BMWalker *walker,
BLI_listbase_clear(&walker->states);
}
-/**
- * \brief End Walker
- *
- * Frees a walker's worklist.
- */
void BMW_end(BMWalker *walker)
{
BLI_mempool_destroy(walker->worklist);
@@ -136,9 +125,6 @@ void BMW_end(BMWalker *walker)
BLI_gset_free(walker->visit_set_alt, NULL);
}
-/**
- * \brief Step Walker
- */
void *BMW_step(BMWalker *walker)
{
BMHeader *head;
@@ -148,22 +134,11 @@ void *BMW_step(BMWalker *walker)
return head;
}
-/**
- * \brief Walker Current Depth
- *
- * Returns the current depth of the walker.
- */
-
int BMW_current_depth(BMWalker *walker)
{
return walker->depth;
}
-/**
- * \brief Main Walking Function
- *
- * Steps a mesh walker forward by one element
- */
void *BMW_walk(BMWalker *walker)
{
void *current = NULL;
@@ -177,13 +152,6 @@ void *BMW_walk(BMWalker *walker)
return NULL;
}
-/**
- * \brief Current Walker State
- *
- * Returns the first state from the walker state
- * worklist. This state is the next in the
- * worklist for processing.
- */
void *BMW_current_state(BMWalker *walker)
{
BMwGenericWalker *currentstate = walker->states.first;
@@ -203,12 +171,6 @@ void *BMW_current_state(BMWalker *walker)
return currentstate;
}
-/**
- * \brief Remove Current Walker State
- *
- * Remove and free an item from the end of the walker state
- * worklist.
- */
void BMW_state_remove(BMWalker *walker)
{
void *oldstate;
@@ -217,15 +179,6 @@ void BMW_state_remove(BMWalker *walker)
BLI_mempool_free(walker->worklist, oldstate);
}
-/**
- * \brief Add a new Walker State
- *
- * Allocate a new empty state and put it on the worklist.
- * A pointer to the new state is returned so that the caller
- * can fill in the state data. The new state will be inserted
- * at the front for depth-first walks, and at the end for
- * breadth-first walks.
- */
void *BMW_state_add(BMWalker *walker)
{
BMwGenericWalker *newstate;
@@ -245,12 +198,6 @@ void *BMW_state_add(BMWalker *walker)
return newstate;
}
-/**
- * \brief Reset Walker
- *
- * Frees all states from the worklist, resetting the walker
- * for reuse in a new walk.
- */
void BMW_reset(BMWalker *walker)
{
while (BMW_current_state(walker)) {
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index d0348aa11dc..f36f77ce009 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -67,6 +67,12 @@ typedef struct BMWalker {
/* define to make BMW_init more clear */
#define BMW_MASK_NOP 0
+/**
+ * \brief Init Walker
+ *
+ * Allocates and returns a new mesh walker of a given type.
+ * The elements visited are filtered by the bitmask 'searchmask'.
+ */
void BMW_init(struct BMWalker *walker,
BMesh *bm,
int type,
@@ -76,15 +82,61 @@ void BMW_init(struct BMWalker *walker,
BMWFlag flag,
int layer);
void *BMW_begin(BMWalker *walker, void *start);
+/**
+ * \brief Step Walker
+ */
void *BMW_step(struct BMWalker *walker);
+/**
+ * \brief End Walker
+ *
+ * Frees a walker's worklist.
+ */
void BMW_end(struct BMWalker *walker);
+/**
+ * \brief Walker Current Depth
+ *
+ * Returns the current depth of the walker.
+ */
int BMW_current_depth(BMWalker *walker);
/* These are used by custom walkers. */
+/**
+ * \brief Current Walker State
+ *
+ * Returns the first state from the walker state
+ * worklist. This state is the next in the
+ * worklist for processing.
+ */
void *BMW_current_state(BMWalker *walker);
+/**
+ * \brief Add a new Walker State
+ *
+ * Allocate a new empty state and put it on the worklist.
+ * A pointer to the new state is returned so that the caller
+ * can fill in the state data. The new state will be inserted
+ * at the front for depth-first walks, and at the end for
+ * breadth-first walks.
+ */
void *BMW_state_add(BMWalker *walker);
+/**
+ * \brief Remove Current Walker State
+ *
+ * Remove and free an item from the end of the walker state
+ * worklist.
+ */
void BMW_state_remove(BMWalker *walker);
+/**
+ * \brief Main Walking Function
+ *
+ * Steps a mesh walker forward by one element
+ */
void *BMW_walk(BMWalker *walker);
+/**
+ * \brief Reset Walker
+ *
+ * Frees all states from the worklist, resetting the walker
+ * for reuse in a new walk.
+ */
void BMW_reset(BMWalker *walker);
#define BMW_ITER(ele, walker, data) \
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 7931e953295..15d3a6a6a53 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -94,6 +94,7 @@ static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
}
return BM_edge_is_wire(e);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -107,6 +108,7 @@ static bool bmw_edge_is_wire(const BMWalker *walker, const BMEdge *e)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_VertShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
{
BMwShellWalker *shellWalk = NULL;
@@ -236,6 +238,7 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
*
* \note this is mainly useful to loop over a shell delimited by edges.
* \{ */
+
static void bmw_LoopShellWalker_visitLoop(BMWalker *walker, BMLoop *l)
{
BMwLoopShellWalker *shellWalk = NULL;
@@ -509,6 +512,7 @@ static void *bmw_LoopShellWireWalker_step(BMWalker *walker)
* Starts at an edge on the mesh and walks over the 'shell' it belongs
* to via visiting connected faces.
* \{ */
+
static void bmw_FaceShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
{
BMwShellWalker *shellWalk = NULL;
@@ -564,6 +568,7 @@ static void *bmw_FaceShellWalker_step(BMWalker *walker)
return e;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -573,6 +578,7 @@ static void *bmw_FaceShellWalker_step(BMWalker *walker)
*
* Walk from a vertex to all connected vertices.
* \{ */
+
static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v)
{
BMwConnectedVertexWalker *vwalk;
@@ -640,6 +646,7 @@ static void *bmw_ConnectedVertexWalker_step(BMWalker *walker)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_IslandboundWalker_begin(BMWalker *walker, void *data)
{
BMLoop *l = data;
@@ -735,6 +742,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker)
*
* \todo Add restriction flag/callback for wire edges.
* \{ */
+
static void bmw_IslandWalker_begin(BMWalker *walker, void *data)
{
BMwIslandWalker *iwalk = NULL;
@@ -1299,6 +1307,7 @@ static void *bmw_FaceLoopWalker_step(BMWalker *walker)
* Conditions for starting and stepping the edge ring have been
* tuned to match behavior users expect (dating back to v2.4x).
* \{ */
+
static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data)
{
BMwEdgeringWalker *lwalk, owalk, *owalk_pt;
@@ -1850,6 +1859,12 @@ static BMWalker bmw_ConnectedVertexWalker_Type = {
BM_VERT, /* Valid restrict masks. */
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name All Walker Types
+ * \{ */
+
BMWalker *bm_walker_types[] = {
&bmw_VertShellWalker_Type, /* #BMW_VERT_SHELL */
&bmw_LoopShellWalker_Type, /* #BMW_LOOP_SHELL */
@@ -1868,3 +1883,5 @@ BMWalker *bm_walker_types[] = {
};
const int bm_totwalkers = ARRAY_SIZE(bm_walker_types);
+
+/** \} */
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index 660633e8a0f..29fd8d9094b 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -120,19 +120,18 @@ typedef struct PathLinkState {
float co_prev[3];
} PathLinkState;
-/**
- * \name Min Dist Dir Util
+/* -------------------------------------------------------------------- */
+/** \name Min Dist Dir Util
*
* Simply getting the closest intersecting vert/edge is _not_ good enough. see T43792
* we need to get the closest in both directions since the absolute closest may be a dead-end.
*
* Logic is simple:
*
- * - first intersection, store the direction.
- * - successive intersections will update the first distance if its aligned with the first hit.
+ * - First intersection, store the direction.
+ * - Successive intersections will update the first distance if its aligned with the first hit.
* otherwise update the opposite distance.
- * - caller stores best outcome in both directions.
- *
+ * - Caller stores best outcome in both directions.
* \{ */
typedef struct MinDistDir {
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index a740e4d66e8..c337724d096 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -31,12 +31,11 @@
#define ELE_NEW 1
#define ELE_OUT 2
-/* This is what runs when pressing the F key
- * doing the best thing here isn't always easy create vs dissolve, its nice to support
- * but it _really_ gives issues we might have to not call dissolve. - campbell
- */
void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
{
+ /* NOTE(@campbellbarton): doing the best thing here isn't always easy create vs dissolve,
+ * its nice to support but it _really_ gives issues we might have to not call dissolve. */
+
BMOIter oiter;
BMHeader *h;
int totv = 0, tote = 0, totf = 0;
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 360dcc2c79e..82d277ec3af 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -488,7 +488,6 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
/* done with cleanup */
}
-/* Limited Dissolve */
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
{
BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges");
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index d8047499780..69404c8ba0e 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -787,14 +787,6 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
}
}
-/**
- * Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on
- * \param x_segments: The x-resolution of the grid
- * \param y_segments: The y-resolution of the grid
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_grid(BMesh *bm,
const uint x_segments,
const uint y_segments,
@@ -1130,12 +1122,6 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset)
}
}
-/**
- * Fills first available UV-map with spherical projected UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_offset)
{
BMFace *f;
@@ -1343,14 +1329,6 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on.
- * \param mat: The transform matrix applied to the created circle.
- * \param radius: The size of the circle.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_circle(
BMesh *bm, float mat[4][4], const float radius, const short oflag, const int cd_loop_uv_offset)
{
@@ -1534,17 +1512,6 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
- *
- * \param bm: The BMesh to operate on.
- * \param mat: The transform matrix applied to the created cone/cylinder.
- * \param radius_top: The size of the top end of the cone/cylinder.
- * \param radius_bottom: The size of the bottom end of the cone/cylinder.
- * \param segments: The number of subdivisions in the sides of the cone/cylinder.
- * \param cap_ends: Whether the ends of the cone/cylinder are filled or not.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_cone(BMesh *bm,
float mat[4][4],
const float radius_top,
@@ -1710,15 +1677,6 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
-/**
- * Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
- *
- * \note Expects tagged faces to be six quads.
- * \note Caller must order faces for correct alignment.
- *
- * \param bm: The BMesh to operate on.
- * \param oflag: The flag to check faces with.
- */
void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag)
{
BMFace *f;
diff --git a/source/blender/bmesh/operators/bmo_split_edges.c b/source/blender/bmesh/operators/bmo_split_edges.c
index d030a6e11b0..5a00094ef45 100644
--- a/source/blender/bmesh/operators/bmo_split_edges.c
+++ b/source/blender/bmesh/operators/bmo_split_edges.c
@@ -27,7 +27,6 @@
#include "intern/bmesh_operators_private.h" /* own include */
-/* keep this operator fast, its used in a modifier */
void bmo_split_edges_exec(BMesh *bm, BMOperator *op)
{
const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts");
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 7311c94a0d8..05837ae2a0e 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -1187,12 +1187,14 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
vlen = BLI_array_len(loops);
/* find the boundary of one of the split edges */
- for (a = 1; a < vlen; a++) {
- if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) &&
+ for (a = 0; a < vlen; a++) {
+ if (!BMO_vert_flag_test(bm, loops[a ? (a - 1) : (vlen - 1)]->v, ELE_INNER) &&
BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER)) {
break;
}
}
+ /* Failure to break means there is an internal error. */
+ BLI_assert(a < vlen);
if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
b = (a + numcuts + 1) % vlen;
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index 6a80f360f59..7f0bfc5e2c9 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -1061,9 +1061,10 @@ static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v)
return BMO_edge_flag_test_bool(bm, e, EDGE_RIM);
}
-/* keep this operator fast, its used in a modifier */
void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op)
{
+ /* NOTE: keep this operator fast, its used in a modifier. */
+
ListBase eloops_rim = {NULL};
BMOIter siter;
BMEdge *e;
diff --git a/source/blender/bmesh/operators/bmo_unsubdivide.c b/source/blender/bmesh/operators/bmo_unsubdivide.c
index c5de6df34a7..f11e359e962 100644
--- a/source/blender/bmesh/operators/bmo_unsubdivide.c
+++ b/source/blender/bmesh/operators/bmo_unsubdivide.c
@@ -29,11 +29,10 @@
#include "intern/bmesh_operators_private.h" /* own include */
-/* - BMVert.flag & BM_ELEM_TAG: shows we touched this vert
- * - BMVert.index == -1: shows we will remove this vert
- */
void bmo_unsubdivide_exec(BMesh *bm, BMOperator *op)
{
+ /* - `BMVert.flag & BM_ELEM_TAG`: Shows we touched this vert.
+ * - `BMVert.index == -1`: Shows we will remove this vert. */
BMVert *v;
BMIter iter;
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index d5c5063f2cb..b7cf9c88282 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -235,12 +235,6 @@ static float bm_edge_calc_rotate_beauty__angle(const float v1[3],
return FLT_MAX;
}
-/**
- * Assuming we have 2 triangles sharing an edge (2 - 4),
- * check if the edge running from (1 - 3) gives better results.
- *
- * \return (negative number means the edge can be rotated, lager == better).
- */
float BM_verts_calc_rotate_beauty(const BMVert *v1,
const BMVert *v2,
const BMVert *v3,
@@ -374,9 +368,6 @@ static void bm_edge_update_beauty_cost(BMEdge *e,
/* -------------------------------------------------------------------- */
/* Beautify Fill */
-/**
- * \note This function sets the edge indices to invalid values.
- */
void BM_mesh_beautify_fill(BMesh *bm,
BMEdge **edge_array,
const int edge_array_len,
diff --git a/source/blender/bmesh/tools/bmesh_beautify.h b/source/blender/bmesh/tools/bmesh_beautify.h
index d0fef828e7c..2e7950118c1 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.h
+++ b/source/blender/bmesh/tools/bmesh_beautify.h
@@ -27,6 +27,9 @@ enum {
EDGE_RESTRICT_DEGENERATE = (1 << 1),
};
+/**
+ * \note This function sets the edge indices to invalid values.
+ */
void BM_mesh_beautify_fill(BMesh *bm,
BMEdge **edge_array,
const int edge_array_len,
@@ -35,6 +38,12 @@ void BM_mesh_beautify_fill(BMesh *bm,
const short oflag_edge,
const short oflag_face);
+/**
+ * Assuming we have 2 triangles sharing an edge (2 - 4),
+ * check if the edge running from (1 - 3) gives better results.
+ *
+ * \return (negative number means the edge can be rotated, lager == better).
+ */
float BM_verts_calc_rotate_beauty(const BMVert *v1,
const BMVert *v2,
const BMVert *v3,
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 6cf3641fed2..2f471bf0b81 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -7443,18 +7443,6 @@ static void bevel_limit_offset(BevelParams *bp, BMesh *bm)
}
}
-/**
- * - Currently only bevels BM_ELEM_TAG'd verts and edges.
- *
- * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
- * the caller needs to ensure these are cleared before calling
- * if its going to use this tag.
- *
- * - If limit_offset is set, adjusts offset down if necessary
- * to avoid geometry collisions.
- *
- * \warning all tagged edges _must_ be manifold.
- */
void BM_mesh_bevel(BMesh *bm,
const float offset,
const int offset_type,
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index de57e1c62a9..03c10ee9f80 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -23,6 +23,18 @@
struct CurveProfile;
struct MDeformVert;
+/**
+ * - Currently only bevels BM_ELEM_TAG'd verts and edges.
+ *
+ * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too,
+ * the caller needs to ensure these are cleared before calling
+ * if its going to use this tag.
+ *
+ * - If limit_offset is set, adjusts offset down if necessary
+ * to avoid geometry collisions.
+ *
+ * \warning all tagged edges _must_ be manifold.
+ */
void BM_mesh_bevel(BMesh *bm,
const float offset,
const int offset_type,
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index 8f03b86b859..d220b183b8d 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -88,7 +88,7 @@ static short plane_point_test_v3(const float plane[4],
*
* Hide flag access
* (for more readable code since same flag is used differently for vert/edge-face).
- */
+ * \{ */
/** Enable when vertex is in the center and its faces have been added to the stack. */
BLI_INLINE void vert_is_center_enable(BMVert *v)
@@ -411,11 +411,6 @@ finally:
/** \name Public BMesh Bisect Function
* \{ */
-/**
- * \param use_snap_center: Snap verts onto the plane.
- * \param use_tag: Only bisect tagged edges and faces.
- * \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
- */
void BM_mesh_bisect_plane(BMesh *bm,
const float plane[4],
const bool use_snap_center,
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h
index f64b5d8097c..120935296b7 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.h
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h
@@ -20,6 +20,11 @@
* \ingroup bmesh
*/
+/**
+ * \param use_snap_center: Snap verts onto the plane.
+ * \param use_tag: Only bisect tagged edges and faces.
+ * \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
+ */
void BM_mesh_bisect_plane(BMesh *bm,
const float plane[4],
const bool use_snap_center,
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index 487ef6427af..e244bc377db 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -456,14 +456,6 @@ bool BM_mesh_boolean(BMesh *bm,
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
}
-/**
- * Perform a Knife Intersection operation on the mesh bm.
- * There are either one or two operands, the same as described above for BM_mesh_boolean().
- * If use_separate_all is true, each edge that is created from the intersection should
- * be used to separate all its incident faces. TODO: implement that.
- * TODO: need to ensure that "selected/non-selected" flag of original faces gets propagated
- * to the intersection result faces.
- */
bool BM_mesh_boolean_knife(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h
index ed77242e14c..4dacc7b1095 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.h
+++ b/source/blender/bmesh/tools/bmesh_boolean.h
@@ -35,6 +35,16 @@ bool BM_mesh_boolean(BMesh *bm,
const bool hole_tolerant,
const int boolean_mode);
+/**
+ * Perform a Knife Intersection operation on the mesh `bm`.
+ * There are either one or two operands, the same as described above for #BM_mesh_boolean().
+ *
+ * \param use_separate_all: When true, each edge that is created from the intersection should
+ * be used to separate all its incident faces. TODO: implement that.
+ *
+ * TODO: need to ensure that "selected/non-selected" flag of original faces gets propagated
+ * to the intersection result faces.
+ */
bool BM_mesh_boolean_knife(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_decimate.h b/source/blender/bmesh/tools/bmesh_decimate.h
index c62288c269a..1de241a1326 100644
--- a/source/blender/bmesh/tools/bmesh_decimate.h
+++ b/source/blender/bmesh/tools/bmesh_decimate.h
@@ -20,6 +20,20 @@
* \ingroup bmesh
*/
+/**
+ * \brief BM_mesh_decimate
+ * \param bm: The mesh
+ * \param factor: face count multiplier [0 - 1]
+ * \param vweights: Optional array of vertex aligned weights [0 - 1],
+ * a vertex group is the usual source for this.
+ * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
+ * \param symmetry_eps: Threshold when matching mirror verts.
+ *
+ * \note The caller is responsible for recalculating face and vertex normals.
+ * - Vertex normals are maintained while decimating,
+ * although they won't necessarily match the final recalculated normals.
+ * - Face normals are not maintained at all.
+ */
void BM_mesh_decimate_collapse(BMesh *bm,
const float factor,
float *vweights,
@@ -28,6 +42,8 @@ void BM_mesh_decimate_collapse(BMesh *bm,
const int symmetry_axis,
const float symmetry_eps);
+/**
+ * \param tag_only: so we can call this from an operator */
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only);
void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 97fccbe01fd..e90e50ef8ff 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -1277,20 +1277,6 @@ static bool bm_decim_edge_collapse(BMesh *bm,
/* Main Decimate Function
* ********************** */
-/**
- * \brief BM_mesh_decimate
- * \param bm: The mesh
- * \param factor: face count multiplier [0 - 1]
- * \param vweights: Optional array of vertex aligned weights [0 - 1],
- * a vertex group is the usual source for this.
- * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
- * \param symmetry_eps: Threshold when matching mirror verts.
- *
- * \note The caller is responsible for recalculating face and vertex normals.
- * - Vertex normals are maintained while decimating,
- * although they won't necessarily match the final recalculated normals.
- * - Face normals are not maintained at all.
- */
void BM_mesh_decimate_collapse(BMesh *bm,
const float factor,
float *vweights,
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index c96a7be1adf..ca0f31fdf75 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -168,8 +168,6 @@ enum {
* - BMVert.index == -1: shows we will remove this vert
*/
-/**
- * \param tag_only: so we can call this from an operator */
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only)
{
#ifdef USE_WALKER
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 242b269ed47..4cad1d3cb3c 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -422,15 +422,6 @@ static LinkNode *bm_edgenet_path_calc_best(BMEdge *e,
return path;
}
-/**
- * Fill in faces from an edgenet made up of boundary and wire edges.
- *
- * \note New faces currently don't have their normals calculated and are flipped randomly.
- * The caller needs to flip faces correctly.
- *
- * \param bm: The mesh to operate on.
- * \param use_edge_tag: Only fill tagged edges.
- */
void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag)
{
VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__);
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.h b/source/blender/bmesh/tools/bmesh_edgenet.h
index 7855b2e2886..20edb30442c 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.h
+++ b/source/blender/bmesh/tools/bmesh_edgenet.h
@@ -20,4 +20,13 @@
* \ingroup bmesh
*/
+/**
+ * Fill in faces from an edgenet made up of boundary and wire edges.
+ *
+ * \note New faces currently don't have their normals calculated and are flipped randomly.
+ * The caller needs to flip faces correctly.
+ *
+ * \param bm: The mesh to operate on.
+ * \param use_edge_tag: Only fill tagged edges.
+ */
void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag);
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c
index 388e7f41aba..cd5200a660d 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.c
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.c
@@ -28,11 +28,6 @@
#include "bmesh_edgesplit.h" /* own include */
-/**
- * \param use_verts: Use flagged verts instead of edges.
- * \param tag_only: Only split tagged edges.
- * \param copy_select: Copy selection history.
- */
void BM_mesh_edgesplit(BMesh *bm,
const bool use_verts,
const bool tag_only,
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.h b/source/blender/bmesh/tools/bmesh_edgesplit.h
index 4d3db67ef5f..bcbb3ab7857 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.h
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.h
@@ -24,6 +24,11 @@
extern "C" {
#endif
+/**
+ * \param use_verts: Use flagged verts instead of edges.
+ * \param tag_only: Only split tagged edges.
+ * \param copy_select: Copy selection history.
+ */
void BM_mesh_edgesplit(BMesh *bm,
const bool use_verts,
const bool tag_only,
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 947442c7bd8..6824dd5008a 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -947,14 +947,6 @@ static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const f
#endif /* USE_BVH */
-/**
- * Intersect tessellated faces
- * leaving the resulting edges tagged.
- *
- * \param test_fn: Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
- * \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
- * \return true if the mesh is changed (intersections cut or faces removed from boolean).
- */
bool BM_mesh_intersect(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
index d09ea67a3bb..a6c91715f31 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.h
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -24,6 +24,14 @@
extern "C" {
#endif
+/**
+ * Intersect tessellated faces
+ * leaving the resulting edges tagged.
+ *
+ * \param test_fn: Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
+ * \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
+ * \return true if the mesh is changed (intersections cut or faces removed from boolean).
+ */
bool BM_mesh_intersect(BMesh *bm,
struct BMLoop *(*looptris)[3],
const int looptris_tot,
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index ea1e7eb1e43..52bb92a6221 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -580,4 +580,5 @@ LinkNode *BM_mesh_calc_path_face(BMesh *bm,
return path;
}
+
/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_path_uv.c b/source/blender/bmesh/tools/bmesh_path_uv.c
index 30b109d4731..131a8aa0085 100644
--- a/source/blender/bmesh/tools/bmesh_path_uv.c
+++ b/source/blender/bmesh/tools/bmesh_path_uv.c
@@ -198,6 +198,7 @@ struct LinkNode *BM_mesh_calc_path_uv_vert(BMesh *bm,
/* -------------------------------------------------------------------- */
/** \name BM_mesh_calc_path_uv_edge
* \{ */
+
/* TODO(campbell): not very urgent, since the operator fakes this using vertex path. */
/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index 924538490ad..2ada18f51e7 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -1223,6 +1223,7 @@ static BMEdge *bm_face_region_pivot_edge_find(BMFace **faces_region,
return e_pivot;
}
+
/** \} */
#endif /* USE_PIVOT_SEARCH */
@@ -1332,12 +1333,6 @@ static void bm_vert_fasthash_destroy(UUIDFashMatch *fm)
#endif /* USE_PIVOT_FASTMATCH */
-/**
- * Take a face-region and return a list of matching face-regions.
- *
- * \param faces_region: A single, contiguous face-region.
- * \return A list of matching null-terminated face-region arrays.
- */
int BM_mesh_region_match(BMesh *bm,
BMFace **faces_region,
uint faces_region_len,
diff --git a/source/blender/bmesh/tools/bmesh_region_match.h b/source/blender/bmesh/tools/bmesh_region_match.h
index 799af938c31..7b7233783ce 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.h
+++ b/source/blender/bmesh/tools/bmesh_region_match.h
@@ -20,6 +20,12 @@
* \ingroup bmesh
*/
+/**
+ * Take a face-region and return a list of matching face-regions.
+ *
+ * \param faces_region: A single, contiguous face-region.
+ * \return A list of matching null-terminated face-region arrays.
+ */
int BM_mesh_region_match(BMesh *bm,
BMFace **faces_region,
uint faces_region_len,
diff --git a/source/blender/bmesh/tools/bmesh_separate.c b/source/blender/bmesh/tools/bmesh_separate.c
index 3c69ea111bf..e00829604d5 100644
--- a/source/blender/bmesh/tools/bmesh_separate.c
+++ b/source/blender/bmesh/tools/bmesh_separate.c
@@ -32,10 +32,6 @@
#include "bmesh_separate.h" /* own include */
#include "intern/bmesh_private.h"
-/**
- * Split all faces that match `filter_fn`.
- * \note
- */
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data)
{
BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
diff --git a/source/blender/bmesh/tools/bmesh_separate.h b/source/blender/bmesh/tools/bmesh_separate.h
index 9260903a8fa..8c599eef2b0 100644
--- a/source/blender/bmesh/tools/bmesh_separate.h
+++ b/source/blender/bmesh/tools/bmesh_separate.h
@@ -20,4 +20,8 @@
* \ingroup bmesh
*/
+/**
+ * Split all faces that match `filter_fn`.
+ * \note
+ */
void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data);
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c
index af4a4424103..67010fc89c7 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.c
+++ b/source/blender/bmesh/tools/bmesh_wireframe.c
@@ -152,12 +152,6 @@ static bool bm_loop_is_radial_boundary(BMLoop *l_first)
return true;
}
-/**
- * \param defgrp_index: Vertex group index, -1 for no vertex groups.
- *
- * \note All edge tags must be cleared.
- * \note Behavior matches MOD_solidify.c
- */
void BM_mesh_wireframe(BMesh *bm,
const float offset,
const float offset_fac,
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.h b/source/blender/bmesh/tools/bmesh_wireframe.h
index b2c2f5f5523..5b64a16435f 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.h
+++ b/source/blender/bmesh/tools/bmesh_wireframe.h
@@ -22,6 +22,12 @@
#pragma once
+/**
+ * \param defgrp_index: Vertex group index, -1 for no vertex groups.
+ *
+ * \note All edge tags must be cleared.
+ * \note Behavior matches MOD_solidify.c
+ */
void BM_mesh_wireframe(BMesh *bm,
const float offset,
const float offset_fac,
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index 73e66ffeb03..67d189fe5f8 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -28,12 +28,19 @@ extern "C" {
/* Keep ascii art. */
/* clang-format off */
/**
+ *
* \defgroup Model The data model of the compositor
+ * \ingroup compositor
* \defgroup Memory The memory management stuff
+ * \ingroup compositor
* \defgroup Execution The execution logic
+ * \ingroup compositor
* \defgroup Conversion Conversion logic
+ * \ingroup compositor
* \defgroup Node All nodes of the compositor
+ * \ingroup compositor
* \defgroup Operation All operations of the compositor
+ * \ingroup compositor
*
* \page Introduction of the Blender Compositor
*
@@ -301,10 +308,10 @@ extern "C" {
* It can be executed during editing (blenkernel/node.cc) or rendering
* (renderer/pipeline.c)
*
- * \param rd: [struct RenderData]
+ * \param render_data: [struct RenderData]
* Render data for this composite, this won't always belong to a scene.
*
- * \param editingtree: [struct bNodeTree]
+ * \param node_tree: [struct bNodeTree]
* reference to the compositor editing tree
*
* \param rendering: [true false]
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.cc b/source/blender/compositor/intern/COM_ConstantFolder.cc
index 2cf3ac001d1..ca5fd9e8274 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.cc
+++ b/source/blender/compositor/intern/COM_ConstantFolder.cc
@@ -30,10 +30,6 @@ namespace blender::compositor {
using Link = NodeOperationBuilder::Link;
-/**
- * \param operations_builder: Contains all operations to fold.
- * \param exec_system: Execution system.
- */
ConstantFolder::ConstantFolder(NodeOperationBuilder &operations_builder)
: operations_builder_(operations_builder)
{
@@ -135,7 +131,6 @@ Vector<MemoryBuffer *> ConstantFolder::get_constant_input_buffers(NodeOperation
return inputs_bufs;
}
-/** Returns constant operations resulted from folded operations. */
Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperation *> operations)
{
Set<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations);
@@ -151,9 +146,6 @@ Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperati
return new_folds;
}
-/**
- * Evaluate operations with constant elements into primitive constant operations.
- */
int ConstantFolder::fold_operations()
{
WorkScheduler::start(operations_builder_.context());
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.h b/source/blender/compositor/intern/COM_ConstantFolder.h
index f31cb4f4e78..972dbf0e125 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.h
+++ b/source/blender/compositor/intern/COM_ConstantFolder.h
@@ -42,10 +42,18 @@ class ConstantFolder {
rcti first_elem_area_;
public:
+ /**
+ * \param operations_builder: Contains all operations to fold.
+ * \param exec_system: Execution system.
+ */
ConstantFolder(NodeOperationBuilder &operations_builder);
+ /**
+ * Evaluate operations with constant elements into primitive constant operations.
+ */
int fold_operations();
private:
+ /** Returns constant operations resulted from folded operations. */
Vector<ConstantOperation *> try_fold_operations(Span<NodeOperation *> operations);
ConstantOperation *fold_operation(NodeOperation *operation);
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cc b/source/blender/compositor/intern/COM_ExecutionGroup.cc
index d2198fc14e8..63ca642d52d 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cc
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc
@@ -302,10 +302,6 @@ blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
return chunk_order;
}
-/**
- * this method is called for the top execution groups. containing the compositor node or the
- * preview node or the viewer node)
- */
void ExecutionGroup::execute(ExecutionSystem *graph)
{
const CompositorContext &context = graph->get_context();
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index ce5e9dd4699..430cde89a3b 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -365,6 +365,10 @@ class ExecutionGroup {
* \see ViewerOperation
* \param graph:
*/
+ /**
+ * This method is called for the top execution groups. containing the compositor node or the
+ * preview node or the viewer node).
+ */
void execute(ExecutionSystem *graph);
/**
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index 82821a1ddb1..038df6ed9df 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cc
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -118,9 +118,6 @@ void ExecutionSystem::execute()
execution_model_->execute(*this);
}
-/**
- * Multi-threadedly execute given work function passing work_rect splits as argument.
- */
void ExecutionSystem::execute_work(const rcti &work_rect,
std::function<void(const rcti &split_rect)> work_func)
{
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index 4a3fecaca47..4456ec107fa 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -208,6 +208,9 @@ class ExecutionSystem {
return active_buffers_;
}
+ /**
+ * Multi-threadedly execute given work function passing work_rect splits as argument.
+ */
void execute_work(const rcti &work_rect, std::function<void(const rcti &split_rect)> work_func);
/**
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
index 1295437785f..15dbbfde7ed 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
@@ -73,10 +73,6 @@ void FullFrameExecutionModel::determine_areas_to_render_and_reads()
}
}
-/**
- * Returns input buffers with an offset relative to given output coordinates. Returned memory
- * buffers must be deleted.
- */
Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation *op,
const int output_x,
const int output_y)
@@ -137,9 +133,6 @@ void FullFrameExecutionModel::render_operation(NodeOperation *op)
operation_finished(op);
}
-/**
- * Render output operations in order of priority.
- */
void FullFrameExecutionModel::render_operations()
{
const bool is_rendering = context_.is_rendering();
@@ -200,9 +193,6 @@ void FullFrameExecutionModel::render_output_dependencies(NodeOperation *output_o
}
}
-/**
- * Determines all operations areas needed to render given output area.
- */
void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op,
const rcti &output_area)
{
@@ -235,10 +225,6 @@ void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op
}
}
-/**
- * Determines reads to receive by operations in output operation tree (i.e: Number of dependent
- * operations each operation has).
- */
void FullFrameExecutionModel::determine_reads(NodeOperation *output_op)
{
BLI_assert(output_op->is_output_operation(context_.is_rendering()));
@@ -258,10 +244,6 @@ void FullFrameExecutionModel::determine_reads(NodeOperation *output_op)
}
}
-/**
- * Calculates given output operation area to be rendered taking into account viewer and render
- * borders.
- */
void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, rcti &r_area)
{
BLI_assert(output_op->is_output_operation(context_.is_rendering()));
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
index 36d42886c27..ce724a6b934 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
@@ -42,8 +42,8 @@ class SharedOperationBuffers;
class FullFrameExecutionModel : public ExecutionModel {
private:
/**
- * Contains operations active buffers data. Buffers will be disposed once reader operations are
- * finished.
+ * Contains operations active buffers data.
+ * Buffers will be disposed once reader operations are finished.
*/
SharedOperationBuffers &active_buffers_;
@@ -66,8 +66,15 @@ class FullFrameExecutionModel : public ExecutionModel {
private:
void determine_areas_to_render_and_reads();
+ /**
+ * Render output operations in order of priority.
+ */
void render_operations();
void render_output_dependencies(NodeOperation *output_op);
+ /**
+ * Returns input buffers with an offset relative to given output coordinates.
+ * Returned memory buffers must be deleted.
+ */
Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op,
const int output_x,
const int output_y);
@@ -76,8 +83,19 @@ class FullFrameExecutionModel : public ExecutionModel {
void operation_finished(NodeOperation *operation);
+ /**
+ * Calculates given output operation area to be rendered taking into account viewer and render
+ * borders.
+ */
void get_output_render_area(NodeOperation *output_op, rcti &r_area);
+ /**
+ * Determines all operations areas needed to render given output area.
+ */
void determine_areas_to_render(NodeOperation *output_op, const rcti &output_area);
+ /**
+ * Determines reads to receive by operations in output operation tree (i.e: Number of dependent
+ * operations each operation has).
+ */
void determine_reads(NodeOperation *output_op);
void update_progress_bar();
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index 96888ea1c96..ae925f796ee 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cc
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -74,20 +74,12 @@ MemoryBuffer::MemoryBuffer(DataType data_type, const rcti &rect, bool is_a_singl
set_strides();
}
-/**
- * Construct MemoryBuffer from a float buffer. MemoryBuffer is not responsible for
- * freeing it.
- */
MemoryBuffer::MemoryBuffer(
float *buffer, int num_channels, int width, int height, bool is_a_single_elem)
: MemoryBuffer(buffer, num_channels, create_rect(width, height), is_a_single_elem)
{
}
-/**
- * Construct MemoryBuffer from a float buffer area. MemoryBuffer is not responsible for
- * freeing given buffer.
- */
MemoryBuffer::MemoryBuffer(float *buffer,
const int num_channels,
const rcti &rect,
@@ -145,10 +137,6 @@ BuffersIterator<float> MemoryBuffer::iterate_with(Span<MemoryBuffer *> inputs, c
return builder.build();
}
-/**
- * Converts a single elem buffer to a full size buffer (allocates memory for all
- * elements in resolution).
- */
MemoryBuffer *MemoryBuffer::inflate() const
{
BLI_assert(is_a_single_elem());
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 33d78c99ca6..1af047e9ce1 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -132,9 +132,17 @@ class MemoryBuffer {
*/
MemoryBuffer(DataType data_type, const rcti &rect, bool is_a_single_elem = false);
+ /**
+ * Construct MemoryBuffer from a float buffer. MemoryBuffer is not responsible for
+ * freeing it.
+ */
MemoryBuffer(
float *buffer, int num_channels, int width, int height, bool is_a_single_elem = false);
+ /**
+ * Construct MemoryBuffer from a float buffer area. MemoryBuffer is not responsible for
+ * freeing given buffer.
+ */
MemoryBuffer(float *buffer, int num_channels, const rcti &rect, bool is_a_single_elem = false);
/**
@@ -377,6 +385,10 @@ class MemoryBuffer {
return buffer_;
}
+ /**
+ * Converts a single elem buffer to a full size buffer (allocates memory for all
+ * elements in resolution).
+ */
MemoryBuffer *inflate() const;
inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cc b/source/blender/compositor/intern/COM_MemoryProxy.cc
index 895990bc87f..6263c47fc9e 100644
--- a/source/blender/compositor/intern/COM_MemoryProxy.cc
+++ b/source/blender/compositor/intern/COM_MemoryProxy.cc
@@ -25,6 +25,7 @@ MemoryProxy::MemoryProxy(DataType datatype)
{
write_buffer_operation_ = nullptr;
executor_ = nullptr;
+ buffer_ = nullptr;
datatype_ = datatype;
}
diff --git a/source/blender/compositor/intern/COM_MetaData.cc b/source/blender/compositor/intern/COM_MetaData.cc
index 530634a6e41..50561975ae4 100644
--- a/source/blender/compositor/intern/COM_MetaData.cc
+++ b/source/blender/compositor/intern/COM_MetaData.cc
@@ -36,10 +36,6 @@ void MetaData::add_cryptomatte_entry(const blender::StringRef layer_name,
add(blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(layer_name, key), value);
}
-/* Replace the hash neutral cryptomatte keys with hashed versions.
- *
- * When a conversion happens it will also add the cryptomatte name key with the given
- * `layer_name`. */
void MetaData::replace_hash_neutral_cryptomatte_keys(const blender::StringRef layer_name)
{
std::string cryptomatte_hash = entries_.pop_default(META_DATA_KEY_CRYPTOMATTE_HASH, "");
diff --git a/source/blender/compositor/intern/COM_MetaData.h b/source/blender/compositor/intern/COM_MetaData.h
index 0bb014525c3..be47d7c281e 100644
--- a/source/blender/compositor/intern/COM_MetaData.h
+++ b/source/blender/compositor/intern/COM_MetaData.h
@@ -50,6 +50,12 @@ class MetaData {
public:
void add(const blender::StringRef key, const blender::StringRef value);
+ /**
+ * Replace the hash neutral cryptomatte keys with hashed versions.
+ *
+ * When a conversion happens it will also add the cryptomatte name key with the given
+ * `layer_name`.
+ */
void replace_hash_neutral_cryptomatte_keys(const blender::StringRef layer_name);
void add_to_render_result(RenderResult *render_result) const;
#ifdef WITH_CXX_GUARDEDALLOC
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc
index 8a7ae1f4fcb..1f8bc542843 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cc
+++ b/source/blender/compositor/intern/COM_NodeOperation.cc
@@ -37,14 +37,12 @@ NodeOperation::NodeOperation()
btree_ = nullptr;
}
-/** Get constant value when operation is constant, otherwise return default_value. */
float NodeOperation::get_constant_value_default(float default_value)
{
BLI_assert(outputs_.size() > 0 && get_output_socket()->get_data_type() == DataType::Value);
return *get_constant_elem_default(&default_value);
}
-/** Get constant elem when operation is constant, otherwise return default_elem. */
const float *NodeOperation::get_constant_elem_default(const float *default_elem)
{
BLI_assert(outputs_.size() > 0);
@@ -55,11 +53,6 @@ const float *NodeOperation::get_constant_elem_default(const float *default_elem)
return default_elem;
}
-/**
- * Generate a hash that identifies the operation result in the current execution.
- * Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned.
- * If the operation parameters or its linked inputs change, the hash must be re-generated.
- */
std::optional<NodeOperationHash> NodeOperation::generate_hash()
{
params_hash_ = get_default_hash_2(canvas_.xmin, canvas_.xmax);
@@ -150,7 +143,7 @@ void NodeOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
modify_determined_canvas_fn_(r_area);
}
- rcti unused_area;
+ rcti unused_area = COM_AREA_NONE;
const rcti &local_preferred_area = r_area;
for (unsigned int index = 0; index < inputs_.size(); index++) {
if (index == used_canvas_index) {
@@ -213,10 +206,6 @@ const rcti &NodeOperation::get_canvas() const
return canvas_;
}
-/**
- * Mainly used for re-determining canvas of constant operations in cases where preferred canvas
- * depends on the constant element.
- */
void NodeOperation::unset_canvas()
{
BLI_assert(inputs_.size() == 0);
@@ -275,18 +264,6 @@ bool NodeOperation::determine_depending_area_of_interest(rcti *input,
/** \name Full Frame Methods
* \{ */
-/**
- * \brief Get input operation area being read by this operation on rendering given output area.
- *
- * Implementation don't need to ensure r_input_area is within input operation bounds. The
- * caller must clamp it.
- * TODO: See if it's possible to use parameter overloading (input_id for example).
- *
- * \param input_idx: Input operation index for which we want to calculate the area being read.
- * \param output_area: Area being rendered by this operation.
- * \param r_input_area: Returned input operation area that needs to be read in order to render
- * given output area.
- */
void NodeOperation::get_area_of_interest(const int input_idx,
const rcti &output_area,
rcti &r_input_area)
@@ -315,12 +292,6 @@ void NodeOperation::get_area_of_interest(NodeOperation *input_op,
BLI_assert_msg(0, "input_op is not an input operation.");
}
-/**
- * Executes operation image manipulation algorithm rendering given areas.
- * \param output_buf: Buffer to write result to.
- * \param areas: Areas within this operation bounds to render.
- * \param inputs_bufs: Inputs operations buffers.
- */
void NodeOperation::render(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
@@ -333,9 +304,6 @@ void NodeOperation::render(MemoryBuffer *output_buf,
}
}
-/**
- * Renders given areas using operations full frame implementation.
- */
void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
@@ -347,9 +315,6 @@ void NodeOperation::render_full_frame(MemoryBuffer *output_buf,
deinit_execution();
}
-/**
- * Renders given areas using operations tiled implementation.
- */
void NodeOperation::render_full_frame_fallback(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs)
@@ -405,9 +370,6 @@ void NodeOperation::render_tile(MemoryBuffer *output_buf, rcti *tile_rect)
}
}
-/**
- * \return Replaced inputs links.
- */
Vector<NodeOperationOutput *> NodeOperation::replace_inputs_with_buffers(
Span<MemoryBuffer *> inputs_bufs)
{
@@ -461,9 +423,6 @@ SocketReader *NodeOperationInput::get_reader()
return nullptr;
}
-/**
- * \return Whether canvas area could be determined.
- */
bool NodeOperationInput::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
if (link_) {
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index 627fffb1ec7..4412c021517 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -134,6 +134,9 @@ class NodeOperationInput {
SocketReader *get_reader();
+ /**
+ * \return Whether canvas area could be determined.
+ */
bool determine_canvas(const rcti &preferred_area, rcti &r_area);
#ifdef WITH_CXX_GUARDEDALLOC
@@ -351,7 +354,7 @@ class NodeOperation {
*/
eExecutionModel execution_model_;
- rcti canvas_;
+ rcti canvas_ = COM_AREA_NONE;
/**
* Flags how to evaluate this operation.
@@ -385,7 +388,9 @@ class NodeOperation {
return id_;
}
+ /** Get constant value when operation is constant, otherwise return default_value. */
float get_constant_value_default(float default_value);
+ /** Get constant elem when operation is constant, otherwise return default_elem. */
const float *get_constant_elem_default(const float *default_elem);
const NodeOperationFlags get_flags() const
@@ -393,6 +398,11 @@ class NodeOperation {
return flags_;
}
+ /**
+ * Generate a hash that identifies the operation result in the current execution.
+ * Requires `hash_output_params` to be implemented, otherwise `std::nullopt` is returned.
+ * If the operation parameters or its linked inputs change, the hash must be re-generated.
+ */
std::optional<NodeOperationHash> generate_hash();
unsigned int get_number_of_input_sockets() const
@@ -511,6 +521,10 @@ class NodeOperation {
void set_canvas(const rcti &canvas_area);
const rcti &get_canvas() const;
+ /**
+ * Mainly used for re-determining canvas of constant operations in cases where preferred canvas
+ * depends on the constant element.
+ */
void unset_canvas();
/**
@@ -618,6 +632,12 @@ class NodeOperation {
/** \name Full Frame Methods
* \{ */
+ /**
+ * Executes operation image manipulation algorithm rendering given areas.
+ * \param output_buf: Buffer to write result to.
+ * \param areas: Areas within this operation bounds to render.
+ * \param inputs_bufs: Inputs operations buffers.
+ */
void render(MemoryBuffer *output_buf, Span<rcti> areas, Span<MemoryBuffer *> inputs_bufs);
/**
@@ -630,7 +650,16 @@ class NodeOperation {
}
/**
- * Get input operation area being read by this operation on rendering given output area.
+ * \brief Get input operation area being read by this operation on rendering given output area.
+ *
+ * Implementation don't need to ensure r_input_area is within input operation bounds.
+ * The caller must clamp it.
+ * TODO: See if it's possible to use parameter overloading (input_id for example).
+ *
+ * \param input_idx: Input operation index for which we want to calculate the area being read.
+ * \param output_area: Area being rendered by this operation.
+ * \param r_input_area: Returned input operation area that needs to be read in order to render
+ * given output area.
*/
virtual void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area);
void get_area_of_interest(NodeOperation *input_op, const rcti &output_area, rcti &r_input_area);
@@ -749,14 +778,23 @@ class NodeOperation {
/** \name Full Frame Methods
* \{ */
+ /**
+ * Renders given areas using operations full frame implementation.
+ */
void render_full_frame(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs_bufs);
+ /**
+ * Renders given areas using operations tiled implementation.
+ */
void render_full_frame_fallback(MemoryBuffer *output_buf,
Span<rcti> areas,
Span<MemoryBuffer *> inputs);
void render_tile(MemoryBuffer *output_buf, rcti *tile_rect);
+ /**
+ * \return Replaced inputs links.
+ */
Vector<NodeOperationOutput *> replace_inputs_with_buffers(Span<MemoryBuffer *> inputs_bufs);
void remove_buffers_and_restore_original_inputs(
Span<NodeOperationOutput *> original_inputs_links);
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index 5dc66fea670..2109dd9c582 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -481,7 +481,6 @@ static Vector<NodeOperationHash> generate_hashes(Span<NodeOperation *> operation
return hashes;
}
-/** Merge operations with same type, inputs and parameters that produce the same result. */
void NodeOperationBuilder::merge_equal_operations()
{
bool check_for_next_merge = true;
@@ -793,7 +792,6 @@ void NodeOperationBuilder::save_graphviz(StringRefNull name)
}
}
-/** Create a graphviz representation of the NodeOperationBuilder. */
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder)
{
os << "# Builder start\n";
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
index fcb2dd3800e..efc927e7c9e 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
@@ -169,6 +169,7 @@ class NodeOperationBuilder {
private:
PreviewOperation *make_preview_operation() const;
void unlink_inputs_and_relink_outputs(NodeOperation *unlinked_op, NodeOperation *linked_op);
+ /** Merge operations with same type, inputs and parameters that produce the same result. */
void merge_equal_operations();
void merge_equal_operations(NodeOperation *from, NodeOperation *into);
void save_graphviz(StringRefNull name = "");
@@ -177,6 +178,7 @@ class NodeOperationBuilder {
#endif
};
+/** Create a graphviz representation of the NodeOperationBuilder. */
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder);
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder::Link &link);
diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
index c67251b2d20..567b5e0ee53 100644
--- a/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
+++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.cc
@@ -31,13 +31,11 @@ SharedOperationBuffers::BufferData &SharedOperationBuffers::get_buffer_data(Node
return buffers_.lookup_or_add_cb(op, []() { return BufferData(); });
}
-/**
- * Whether given operation area to render is already registered.
- * TODO: Possibly refactor to "request_area". Current implementation is incomplete: partial
- * overlapping, etc. Leading to more rendering than necessary.
- */
bool SharedOperationBuffers::is_area_registered(NodeOperation *op, const rcti &area_to_render)
{
+ /* TODO: Possibly refactor to "request_area". Current implementation is incomplete:
+ * partial overlapping, etc. Leading to more rendering than necessary. */
+
BufferData &buf_data = get_buffer_data(op);
for (rcti &reg_rect : buf_data.render_areas) {
if (BLI_rcti_inside_rcti(&reg_rect, &area_to_render)) {
@@ -47,34 +45,21 @@ bool SharedOperationBuffers::is_area_registered(NodeOperation *op, const rcti &a
return false;
}
-/**
- * Registers an operation area to render.
- */
void SharedOperationBuffers::register_area(NodeOperation *op, const rcti &area_to_render)
{
get_buffer_data(op).render_areas.append(area_to_render);
}
-/**
- * Whether given operation has any registered reads (other operation registered it depends on given
- * operation).
- */
bool SharedOperationBuffers::has_registered_reads(NodeOperation *op)
{
return get_buffer_data(op).registered_reads > 0;
}
-/**
- * Registers an operation read (other operation depends on given operation).
- */
void SharedOperationBuffers::register_read(NodeOperation *read_op)
{
get_buffer_data(read_op).registered_reads++;
}
-/**
- * Get registered areas given operation needs to render.
- */
Vector<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op,
const int offset_x,
const int offset_y)
@@ -88,17 +73,11 @@ Vector<rcti> SharedOperationBuffers::get_areas_to_render(NodeOperation *op,
return dst_areas;
}
-/**
- * Whether this operation buffer has already been rendered.
- */
bool SharedOperationBuffers::is_operation_rendered(NodeOperation *op)
{
return get_buffer_data(op).is_rendered;
}
-/**
- * Stores given operation rendered buffer.
- */
void SharedOperationBuffers::set_rendered_buffer(NodeOperation *op,
std::unique_ptr<MemoryBuffer> buffer)
{
@@ -109,19 +88,12 @@ void SharedOperationBuffers::set_rendered_buffer(NodeOperation *op,
buf_data.is_rendered = true;
}
-/**
- * Get given operation rendered buffer.
- */
MemoryBuffer *SharedOperationBuffers::get_rendered_buffer(NodeOperation *op)
{
BLI_assert(is_operation_rendered(op));
return get_buffer_data(op).buffer.get();
}
-/**
- * Reports an operation has finished reading given operation. If all given operation dependencies
- * have finished its buffer will be disposed.
- */
void SharedOperationBuffers::read_finished(NodeOperation *read_op)
{
BufferData &buf_data = get_buffer_data(read_op);
diff --git a/source/blender/compositor/intern/COM_SharedOperationBuffers.h b/source/blender/compositor/intern/COM_SharedOperationBuffers.h
index d7d0dffabb5..fd053fce02f 100644
--- a/source/blender/compositor/intern/COM_SharedOperationBuffers.h
+++ b/source/blender/compositor/intern/COM_SharedOperationBuffers.h
@@ -50,17 +50,46 @@ class SharedOperationBuffers {
blender::Map<NodeOperation *, BufferData> buffers_;
public:
+ /**
+ * Whether given operation area to render is already registered.
+ */
bool is_area_registered(NodeOperation *op, const rcti &area_to_render);
+ /**
+ * Registers an operation area to render.
+ */
void register_area(NodeOperation *op, const rcti &area_to_render);
+ /**
+ * Whether given operation has any registered reads (other operation registered it depends on
+ * given operation).
+ */
bool has_registered_reads(NodeOperation *op);
+ /**
+ * Registers an operation read (other operation depends on given operation).
+ */
void register_read(NodeOperation *read_op);
+ /**
+ * Get registered areas given operation needs to render.
+ */
Vector<rcti> get_areas_to_render(NodeOperation *op, int offset_x, int offset_y);
+ /**
+ * Whether this operation buffer has already been rendered.
+ */
bool is_operation_rendered(NodeOperation *op);
+ /**
+ * Stores given operation rendered buffer.
+ */
void set_rendered_buffer(NodeOperation *op, std::unique_ptr<MemoryBuffer> buffer);
+ /**
+ * Get given operation rendered buffer.
+ */
MemoryBuffer *get_rendered_buffer(NodeOperation *op);
+ /**
+ * Reports an operation has finished reading given operation. If all given operation dependencies
+ * have finished its buffer will be disposed.
+ */
void read_finished(NodeOperation *read_op);
private:
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cc b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
index aefe74a7e26..702733498c8 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc
@@ -111,8 +111,6 @@ __m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size)
}
#endif
-/* normalized distance from the current (inverted so 1.0 is close and 0.0 is far)
- * 'ease' is applied after, looks nicer */
float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff)
{
float *dist_fac_invert, val;
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h
index ab378983100..e12c5427082 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h
@@ -41,6 +41,10 @@ class BlurBaseOperation : public MultiThreadedOperation, public QualityStepHelpe
#ifdef BLI_HAVE_SSE2
__m128 *convert_gausstab_sse(const float *gausstab, int size);
#endif
+ /**
+ * Normalized distance from the current (inverted so 1.0 is close and 0.0 is far)
+ * 'ease' is applied after, looks nicer.
+ */
float *make_dist_fac_inverse(float rad, int size, int falloff);
void update_size();
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cc b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
index 7cfa1c09298..bf82ae73d55 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.cc
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc
@@ -45,7 +45,7 @@ void ColorCurveOperation::init_execution()
input_black_program_ = this->get_input_socket_reader(2);
input_white_program_ = this->get_input_socket_reader(3);
- BKE_curvemapping_premultiply(curve_mapping_, 0);
+ BKE_curvemapping_premultiply(curve_mapping_, false);
}
void ColorCurveOperation::execute_pixel_sampled(float output[4],
@@ -145,7 +145,7 @@ void ConstantLevelColorCurveOperation::init_execution()
input_fac_program_ = this->get_input_socket_reader(0);
input_image_program_ = this->get_input_socket_reader(1);
- BKE_curvemapping_premultiply(curve_mapping_, 0);
+ BKE_curvemapping_premultiply(curve_mapping_, false);
BKE_curvemapping_set_black_white(curve_mapping_, black_, white_);
}
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cc b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
index 2abc4f71b5e..3aaf402ae24 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cc
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc
@@ -21,7 +21,6 @@
namespace blender::compositor {
-/* DilateErode Distance Threshold */
DilateErodeThresholdOperation::DilateErodeThresholdOperation()
{
this->add_input_socket(DataType::Value);
@@ -268,7 +267,6 @@ void DilateErodeThresholdOperation::update_memory_buffer_partial(MemoryBuffer *o
}
}
-/* Dilate Distance. */
DilateDistanceOperation::DilateDistanceOperation()
{
this->add_input_socket(DataType::Value);
@@ -458,7 +456,6 @@ void DilateDistanceOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-/* Erode Distance */
ErodeDistanceOperation::ErodeDistanceOperation() : DilateDistanceOperation()
{
/* pass */
@@ -531,7 +528,6 @@ void ErodeDistanceOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
}
-/* Dilate step */
DilateStepOperation::DilateStepOperation()
{
this->add_input_socket(DataType::Value);
@@ -809,7 +805,6 @@ void DilateStepOperation::update_memory_buffer_partial(MemoryBuffer *output,
step_update_memory_buffer<Max2Selector>(output, inputs[0], area, iterations_, -FLT_MAX);
}
-/* Erode step */
ErodeStepOperation::ErodeStepOperation() : DilateStepOperation()
{
/* pass */
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h
index 04d25a1fca6..2ca6431862d 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.h
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h
@@ -43,6 +43,7 @@ class DilateErodeThresholdOperation : public MultiThreadedOperation {
int scope_;
public:
+ /* DilateErode Distance Threshold */
DilateErodeThresholdOperation();
/**
@@ -98,6 +99,7 @@ class DilateDistanceOperation : public MultiThreadedOperation {
int scope_;
public:
+ /* Dilate Distance. */
DilateDistanceOperation();
/**
@@ -140,6 +142,7 @@ class DilateDistanceOperation : public MultiThreadedOperation {
class ErodeDistanceOperation : public DilateDistanceOperation {
public:
+ /* Erode Distance */
ErodeDistanceOperation();
/**
@@ -169,6 +172,7 @@ class DilateStepOperation : public MultiThreadedOperation {
int iterations_;
public:
+ /* Dilate step */
DilateStepOperation();
/**
@@ -205,6 +209,7 @@ class DilateStepOperation : public MultiThreadedOperation {
class ErodeStepOperation : public DilateStepOperation {
public:
+ /** Erode step. */
ErodeStepOperation();
void *initialize_tile_data(rcti *rect) override;
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cc b/source/blender/compositor/operations/COM_InpaintOperation.cc
index 2d632bb3681..83bc81d35fc 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cc
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cc
@@ -25,7 +25,6 @@ namespace blender::compositor {
#define ASSERT_XY_RANGE(x, y) \
BLI_assert(x >= 0 && x < this->get_width() && y >= 0 && y < this->get_height())
-/* In-paint (simple convolve using average of known pixels). */
InpaintSimpleOperation::InpaintSimpleOperation()
{
this->add_input_socket(DataType::Color);
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.h b/source/blender/compositor/operations/COM_InpaintOperation.h
index b0d44e22b85..989d154dab5 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.h
+++ b/source/blender/compositor/operations/COM_InpaintOperation.h
@@ -39,6 +39,7 @@ class InpaintSimpleOperation : public NodeOperation {
short *manhattan_distance_;
public:
+ /** In-paint (simple convolve using average of known pixels). */
InpaintSimpleOperation();
/**
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cc b/source/blender/compositor/operations/COM_MathBaseOperation.cc
index 86993ffe887..1a4684ae3f0 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc
@@ -52,7 +52,7 @@ void MathBaseOperation::deinit_execution()
void MathBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperationInput *socket;
- rcti temp_area;
+ rcti temp_area = COM_AREA_NONE;
socket = this->get_input_socket(0);
const bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
if (determined) {
diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc
index 09bbb633459..edae4454b13 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cc
+++ b/source/blender/compositor/operations/COM_MixOperation.cc
@@ -70,7 +70,7 @@ void MixBaseOperation::execute_pixel_sampled(float output[4],
void MixBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
NodeOperationInput *socket;
- rcti temp_area;
+ rcti temp_area = COM_AREA_NONE;
socket = this->get_input_socket(1);
bool determined = socket->determine_canvas(COM_AREA_NONE, temp_area);
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
index 4c584ca43f4..22ece04b900 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
@@ -81,7 +81,7 @@ class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTr
{
PlaneTrackCommon::determine_canvas(preferred_area, r_area);
- rcti unused;
+ rcti unused = COM_AREA_NONE;
rcti &preferred = r_area;
NodeOperation::determine_canvas(preferred, unused);
}
@@ -102,7 +102,7 @@ class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation,
{
PlaneTrackCommon::determine_canvas(preferred_area, r_area);
- rcti unused;
+ rcti unused = COM_AREA_NONE;
rcti &preferred = r_area;
NodeOperation::determine_canvas(preferred, unused);
}
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc
index 7650def2c87..d8e73b7c979 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cc
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc
@@ -263,6 +263,7 @@ void RenderLayersProg::update_memory_buffer_partial(MemoryBuffer *output,
}
/* ******** Render Layers AO Operation ******** */
+
void RenderLayersAOOperation::execute_pixel_sampled(float output[4],
float x,
float y,
@@ -294,6 +295,7 @@ void RenderLayersAOOperation::update_memory_buffer_partial(MemoryBuffer *output,
}
/* ******** Render Layers Alpha Operation ******** */
+
void RenderLayersAlphaProg::execute_pixel_sampled(float output[4],
float x,
float y,
@@ -326,6 +328,7 @@ void RenderLayersAlphaProg::update_memory_buffer_partial(MemoryBuffer *output,
}
/* ******** Render Layers Depth Operation ******** */
+
void RenderLayersDepthProg::execute_pixel_sampled(float output[4],
float x,
float y,
diff --git a/source/blender/compositor/operations/COM_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc
index 8129516f81c..145a2f9c9d0 100644
--- a/source/blender/compositor/operations/COM_RotateOperation.cc
+++ b/source/blender/compositor/operations/COM_RotateOperation.cc
@@ -227,7 +227,7 @@ void RotateOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti input_canvas = r_area;
- rcti unused;
+ rcti unused = COM_AREA_NONE;
get_input_socket(DEGREE_INPUT_INDEX)->determine_canvas(input_canvas, unused);
ensure_degree();
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index ef67b6ca5f9..20e85c69ac8 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -664,9 +664,6 @@ void SMAABlendingWeightCalculationOperation::get_area_of_interest(const int UNUS
/*-----------------------------------------------------------------------------*/
/* Diagonal Search Functions */
-/**
- * These functions allows to perform diagonal pattern searches.
- */
int SMAABlendingWeightCalculationOperation::search_diag1(int x, int y, int dir, bool *found)
{
float e[4];
@@ -714,9 +711,6 @@ int SMAABlendingWeightCalculationOperation::search_diag2(int x, int y, int dir,
return x - dir;
}
-/**
- * This searches for diagonal patterns and returns the corresponding weights.
- */
void SMAABlendingWeightCalculationOperation::calculate_diag_weights(int x,
int y,
const float edges[2],
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.h b/source/blender/compositor/operations/COM_SMAAOperation.h
index 65a88d43fdf..ec04594e0aa 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.h
+++ b/source/blender/compositor/operations/COM_SMAAOperation.h
@@ -111,8 +111,14 @@ class SMAABlendingWeightCalculationOperation : public MultiThreadedOperation {
private:
/* Diagonal Search Functions */
+ /**
+ * These functions allows to perform diagonal pattern searches.
+ */
int search_diag1(int x, int y, int dir, bool *found);
int search_diag2(int x, int y, int dir, bool *found);
+ /**
+ * This searches for diagonal patterns and returns the corresponding weights.
+ */
void calculate_diag_weights(int x, int y, const float edges[2], float weights[2]);
bool is_vertical_search_unneeded(int x, int y);
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc
index 350934b0d3b..281087bb4c7 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cc
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cc
@@ -223,7 +223,7 @@ void ScaleOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti image_canvas = r_area;
- rcti unused;
+ rcti unused = COM_AREA_NONE;
NodeOperationInput *x_socket = get_input_socket(X_INPUT_INDEX);
NodeOperationInput *y_socket = get_input_socket(Y_INPUT_INDEX);
x_socket->determine_canvas(image_canvas, unused);
@@ -374,7 +374,6 @@ bool ScaleAbsoluteOperation::determine_depending_area_of_interest(
return ScaleOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
}
-/* Absolute fixed size. */
ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation()
{
this->add_input_socket(DataType::Color, ResizeMode::None);
@@ -503,7 +502,7 @@ void ScaleFixedSizeOperation::determine_canvas(const rcti &preferred_area, rcti
rcti local_preferred = preferred_area;
local_preferred.xmax = local_preferred.xmin + new_width_;
local_preferred.ymax = local_preferred.ymin + new_height_;
- rcti input_canvas;
+ rcti input_canvas = COM_AREA_NONE;
const bool input_determined = get_input_socket(0)->determine_canvas(local_preferred,
input_canvas);
if (input_determined) {
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h
index 7710aa34c54..cac865b41aa 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.h
+++ b/source/blender/compositor/operations/COM_ScaleOperation.h
@@ -173,6 +173,7 @@ class ScaleFixedSizeOperation : public BaseScaleOperation {
bool is_offset_;
public:
+ /** Absolute fixed size. */
ScaleFixedSizeOperation();
bool determine_depending_area_of_interest(rcti *input,
ReadBufferOperation *read_operation,
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cc b/source/blender/compositor/operations/COM_SplitOperation.cc
index e98c5c986f5..39d097b02e1 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cc
+++ b/source/blender/compositor/operations/COM_SplitOperation.cc
@@ -60,7 +60,7 @@ void SplitOperation::execute_pixel_sampled(float output[4],
void SplitOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- rcti unused_area;
+ rcti unused_area = COM_AREA_NONE;
const bool determined = this->get_input_socket(0)->determine_canvas(COM_AREA_NONE, unused_area);
this->set_canvas_input_index(determined ? 0 : 1);
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc
index 2ed83e87569..f5d47478a8d 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cc
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
@@ -80,7 +80,7 @@ void TextureBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_
if (execution_model_ == eExecutionModel::FullFrame) {
/* Determine inputs. */
- rcti temp;
+ rcti temp = COM_AREA_NONE;
NodeOperation::determine_canvas(r_area, temp);
}
}
diff --git a/source/blender/compositor/operations/COM_TransformOperation.cc b/source/blender/compositor/operations/COM_TransformOperation.cc
index be9bb32e7f0..f18e7e44094 100644
--- a/source/blender/compositor/operations/COM_TransformOperation.cc
+++ b/source/blender/compositor/operations/COM_TransformOperation.cc
@@ -126,7 +126,7 @@ void TransformOperation::determine_canvas(const rcti &preferred_area, rcti &r_ar
get_input_socket(IMAGE_INPUT_INDEX)->determine_canvas(preferred_area, r_area);
if (image_determined) {
rcti image_canvas = r_area;
- rcti unused;
+ rcti unused = COM_AREA_NONE;
get_input_socket(X_INPUT_INDEX)->determine_canvas(image_canvas, unused);
get_input_socket(Y_INPUT_INDEX)->determine_canvas(image_canvas, unused);
get_input_socket(DEGREE_INPUT_INDEX)->determine_canvas(image_canvas, unused);
@@ -171,7 +171,6 @@ void TransformOperation::determine_canvas(const rcti &preferred_area, rcti &r_ar
}
}
-/** Translate -> Rotate -> Scale. */
void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffer *input_img)
{
float rotate_center_x, rotate_center_y;
@@ -198,7 +197,6 @@ void TransformOperation::transform(BuffersIterator<float> &it, const MemoryBuffe
}
}
-/** Scale -> Rotate -> Translate. */
void TransformOperation::transform_inverted(BuffersIterator<float> &it,
const MemoryBuffer *input_img)
{
diff --git a/source/blender/compositor/operations/COM_TransformOperation.h b/source/blender/compositor/operations/COM_TransformOperation.h
index 3c5584a1bea..4db2145cc2d 100644
--- a/source/blender/compositor/operations/COM_TransformOperation.h
+++ b/source/blender/compositor/operations/COM_TransformOperation.h
@@ -35,9 +35,9 @@ class TransformOperation : public MultiThreadedOperation {
int translate_x_;
int translate_y_;
float scale_;
- rcti scale_canvas_;
- rcti rotate_canvas_;
- rcti translate_canvas_;
+ rcti scale_canvas_ = COM_AREA_NONE;
+ rcti rotate_canvas_ = COM_AREA_NONE;
+ rcti translate_canvas_ = COM_AREA_NONE;
/* Set variables. */
PixelSampler sampler_;
@@ -82,7 +82,9 @@ class TransformOperation : public MultiThreadedOperation {
void determine_canvas(const rcti &preferred_area, rcti &r_area) override;
private:
+ /** Translate -> Rotate -> Scale. */
void transform(BuffersIterator<float> &it, const MemoryBuffer *input_img);
+ /** Scale -> Rotate -> Translate. */
void transform_inverted(BuffersIterator<float> &it, const MemoryBuffer *input_img);
};
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc
index 89c7468a67c..d3c87b09fb7 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cc
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cc
@@ -158,7 +158,7 @@ void TranslateCanvasOperation::determine_canvas(const rcti &preferred_area, rcti
if (determined) {
NodeOperationInput *x_socket = get_input_socket(X_INPUT_INDEX);
NodeOperationInput *y_socket = get_input_socket(Y_INPUT_INDEX);
- rcti unused;
+ rcti unused = COM_AREA_NONE;
x_socket->determine_canvas(r_area, unused);
y_socket->determine_canvas(r_area, unused);
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
index 891518d53bf..86bc6d0041a 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc
@@ -69,7 +69,7 @@ void *VariableSizeBokehBlurOperation::initialize_tile_data(rcti *rect)
data->bokeh = (MemoryBuffer *)input_bokeh_program_->initialize_tile_data(rect);
data->size = (MemoryBuffer *)input_size_program_->initialize_tile_data(rect);
- rcti rect2;
+ rcti rect2 = COM_AREA_NONE;
this->determine_depending_area_of_interest(
rect, (ReadBufferOperation *)input_size_program_, &rect2);
@@ -398,7 +398,7 @@ void VariableSizeBokehBlurOperation::update_memory_buffer_partial(MemoryBuffer *
p.image_width = this->get_width();
p.image_height = this->get_height();
- rcti scalar_area;
+ rcti scalar_area = COM_AREA_NONE;
this->get_area_of_interest(SIZE_INPUT_INDEX, area, scalar_area);
BLI_rcti_isect(&scalar_area, &p.size_input->get_rect(), &scalar_area);
const float max_size = p.size_input->get_max_value(scalar_area);
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cc b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
index b220990db76..e34b629f457 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
@@ -40,6 +40,7 @@ void zbuf_free_span(ZSpan *zspan);
void antialias_tagbuf(int xsize, int ysize, char *rectmove);
/* VectorBlurOperation */
+
VectorBlurOperation::VectorBlurOperation()
{
this->add_input_socket(DataType::Color);
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index aa184cce433..0b3e028cd06 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -80,45 +80,67 @@ extern "C" {
/* ************************************************ */
/* Depsgraph API */
-/* CRUD ------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name CRUD
+ * \{ */
/* Get main depsgraph instance from context! */
-/* Create new Depsgraph instance */
-/* TODO: what args are needed here? What's the building-graph entry point? */
+/**
+ * Create new Depsgraph instance.
+ *
+ * TODO: what arguments are needed here? What's the building-graph entry point?
+ */
Depsgraph *DEG_graph_new(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
eEvaluationMode mode);
+/**
+ * Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph.
+ * Used for:
+ * - Undo steps when we do want to re-use the old depsgraph data as much as possible.
+ * - Rendering where we want to re-use objects between different view layers.
+ */
void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Free Depsgraph itself and all its data */
+/** Free graph's contents and graph itself. */
void DEG_graph_free(Depsgraph *graph);
-/* Node Types Registry ---------------------------- */
+/** \} */
-/* Register all node types */
+/* -------------------------------------------------------------------- */
+/** \name Node Types Registry
+ * \{ */
+
+/** Register all node types. */
void DEG_register_node_types(void);
-/* Free node type registry on exit */
+/** Free node type registry on exit. */
void DEG_free_node_types(void);
-/* Update Tagging -------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Tagging
+ * \{ */
-/* Tag dependency graph for updates when visible scenes/layers changes. */
+/** Tag dependency graph for updates when visible scenes/layers changes. */
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time);
-/* Tag all dependency graphs for update when visible scenes/layers changes. */
+/** Tag all dependency graphs for update when visible scenes/layers changes. */
void DEG_tag_on_visible_update(struct Main *bmain, const bool do_time);
-/* NOTE: Will return NULL if the flag is not known, allowing to gracefully handle situations
- * when recalc flag has been removed. */
+/**
+ * \note Will return NULL if the flag is not known, allowing to gracefully handle situations
+ * when recalc flag has been removed.
+ */
const char *DEG_update_tag_as_string(IDRecalcFlag flag);
+/** Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(struct ID *id, int flag);
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag);
@@ -127,48 +149,68 @@ void DEG_graph_id_tag_update(struct Main *bmain,
struct ID *id,
int flag);
-/* Tag all dependency graphs when time has changed. */
+/** Tag all dependency graphs when time has changed. */
void DEG_time_tag_update(struct Main *bmain);
-/* Tag a dependency graph when time has changed. */
+/** Tag a dependency graph when time has changed. */
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph);
-/* Mark a particular datablock type as having changing. This does
- * not cause any updates but is used by external render engines to detect if for
- * example a datablock was removed. */
+/**
+ * Mark a particular data-block type as having changing.
+ * This does not cause any updates but is used by external
+ * render engines to detect if for example a data-block was removed.
+ */
void DEG_graph_id_type_tag(struct Depsgraph *depsgraph, short id_type);
void DEG_id_type_tag(struct Main *bmain, short id_type);
-/* Set a depsgraph to flush updates to editors. This would be done
- * for viewport depsgraphs, but not render or export depsgraph for example. */
+/**
+ * Set a depsgraph to flush updates to editors. This would be done
+ * for viewport depsgraphs, but not render or export depsgraph for example.
+ */
void DEG_enable_editors_update(struct Depsgraph *depsgraph);
-/* Check if something was changed in the database and inform editors about this. */
+/** Check if something was changed in the database and inform editors about this. */
void DEG_editors_update(struct Depsgraph *depsgraph, bool time);
-/* Clear recalc flags after editors or renderers have handled updates. */
+/** Clear recalc flags after editors or renderers have handled updates. */
void DEG_ids_clear_recalc(Depsgraph *depsgraph, const bool backup);
-/* Restore recalc flags, backed up by a previous call to DEG_ids_clear_recalc.
- * This also clears the backup. */
+/**
+ * Restore recalc flags, backed up by a previous call to #DEG_ids_clear_recalc.
+ * This also clears the backup.
+ */
void DEG_ids_restore_recalc(Depsgraph *depsgraph);
+/** \} */
+
/* ************************************************ */
/* Evaluation Engine API */
-/* Graph Evaluation ----------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Graph Evaluation
+ * \{ */
-/* Frame changed recalculation entry point. */
+/**
+ * Frame changed recalculation entry point.
+ *
+ * \note The frame-change happened for root scene that graph belongs to.
+ */
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame);
-/* Data changed recalculation entry point. */
+/**
+ * Data changed recalculation entry point.
+ * Evaluate all nodes tagged for updating.
+ */
void DEG_evaluate_on_refresh(Depsgraph *graph);
-/* Editors Integration -------------------------- */
+/** \} */
-/* Mechanism to allow editors to be informed of depsgraph updates,
+/* -------------------------------------------------------------------- */
+/** \name Editors Integration
+ *
+ * Mechanism to allow editors to be informed of depsgraph updates,
* to do their own updates based on changes.
- */
+ * \{ */
typedef struct DEGEditorUpdateContext {
struct Main *bmain;
@@ -181,10 +223,14 @@ typedef void (*DEG_EditorUpdateIDCb)(const DEGEditorUpdateContext *update_ctx, s
typedef void (*DEG_EditorUpdateSceneCb)(const DEGEditorUpdateContext *update_ctx,
const bool updated);
-/* Set callbacks which are being called when depsgraph changes. */
+/** Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func);
-/* Evaluation ----------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
bool DEG_is_evaluating(const struct Depsgraph *depsgraph);
@@ -192,7 +238,11 @@ bool DEG_is_active(const struct Depsgraph *depsgraph);
void DEG_make_active(struct Depsgraph *depsgraph);
void DEG_make_inactive(struct Depsgraph *depsgraph);
-/* Evaluation Debug ------------------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation Debug
+ * \{ */
void DEG_debug_print_begin(struct Depsgraph *depsgraph);
@@ -232,6 +282,8 @@ void DEG_debug_print_eval_time(struct Depsgraph *depsgraph,
const void *object_address,
float time);
+/** \} */
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index c029d203574..94cba833096 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -50,17 +50,22 @@ extern "C" {
/* Graph Building -------------------------------- */
-/* Build depsgraph for the given scene, and dump results in given graph container. */
+/** Build depsgraph for the given scene layer, and dump results in given graph container. */
void DEG_graph_build_from_view_layer(struct Depsgraph *graph);
-/* Build depsgraph for all objects (so also invisible ones) in the given view layer. */
+/**
+ * Build depsgraph for all objects (so also invisible ones) in the given view layer.
+ */
void DEG_graph_build_for_all_objects(struct Depsgraph *graph);
-/* Special version of builder which produces dependency graph suitable for the render pipeline.
- * It will contain sequencer and compositor (if needed) and all their dependencies. */
+/**
+ * Special version of builder which produces dependency graph suitable for the render pipeline.
+ * It will contain sequencer and compositor (if needed) and all their dependencies.
+ */
void DEG_graph_build_for_render_pipeline(struct Depsgraph *graph);
-/* Builds minimal dependency graph for compositor preview.
+/**
+ * Builds minimal dependency graph for compositor preview.
*
* Note that compositor editor might have pinned node tree, which is different from scene's node
* tree.
@@ -69,18 +74,19 @@ void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph, struct bNod
void DEG_graph_build_from_ids(struct Depsgraph *graph, struct ID **ids, const int num_ids);
-/* Tag relations from the given graph for update. */
+/** Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
-/* Create or update relations in the specified graph. */
+/** Create or update relations in the specified graph. */
void DEG_graph_relations_update(struct Depsgraph *graph);
-/* Tag all relations in the database for update. */
+/** Tag all relations in the database for update. */
void DEG_relations_tag_update(struct Main *bmain);
/* Add Dependencies ----------------------------- */
-/* Handle for components to define their dependencies from callbacks.
+/**
+ * Handle for components to define their dependencies from callbacks.
* This is generated by the depsgraph and passed to dependency callbacks
* as a symbolic reference to the current DepsNode.
* All relations will be defined in reference to that node.
@@ -159,23 +165,28 @@ void DEG_add_object_cache_relation(struct DepsNodeHandle *handle,
struct CacheFile *cache_file,
eDepsObjectComponentType component,
const char *description);
-/* Adds relation from DEG_OPCODE_GENERIC_DATABLOCK_UPDATE of a given ID.
- * Is used for such entities as textures and images. */
+/**
+ * Adds relation from #DEG_OPCODE_GENERIC_DATABLOCK_UPDATE of a given ID.
+ * Is used for such entities as textures and images.
+ */
void DEG_add_generic_id_relation(struct DepsNodeHandle *node_handle,
struct ID *id,
const char *description);
-/* Special function which is used from modifiers' updateDepsgraph() callback
+/**
+ * Special function which is used from modifiers' #updateDepsgraph() callback
* to indicate that the modifier needs to know transformation of the object
* which that modifier belongs to.
* This function will take care of checking which operation is required to
- * have transformation for the modifier, taking into account possible simulation
- * solvers. */
+ * have transformation for the modifier, taking into account possible simulation solvers.
+ */
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle,
const char *description);
-/* Adds relations from the given component of a given object to the given node
- * handle AND the component to the point cache component of the node's ID. */
+/**
+ * Adds relations from the given component of a given object to the given node
+ * handle AND the component to the point cache component of the node's ID.
+ */
void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle,
struct Object *object,
eDepsObjectComponentType component,
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
index 2aea10fd5b4..5c400a1392f 100644
--- a/source/blender/depsgraph/DEG_depsgraph_debug.h
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -37,7 +37,7 @@ struct ViewLayer;
/* ------------------------------------------------ */
-/* NOTE: Those flags are same bitmask as G.debug_flags */
+/* NOTE: Those flags are same bit-mask as #G.debug_flags */
void DEG_debug_flags_set(struct Depsgraph *depsgraph, int flags);
int DEG_debug_flags_get(const struct Depsgraph *depsgraph);
@@ -47,6 +47,12 @@ const char *DEG_debug_name_get(struct Depsgraph *depsgraph);
/* ------------------------------------------------ */
+/**
+ * Obtain simple statistics about the complexity of the depsgraph.
+ * \param[out] r_outer: The number of outer nodes in the graph.
+ * \param[out] r_operations: The number of operation nodes in the graph.
+ * \param[out] r_relations: The number of relations between (executable) nodes in the graph.
+ */
void DEG_stats_simple(const struct Depsgraph *graph,
size_t *r_outer,
size_t *r_operations,
@@ -64,16 +70,16 @@ void DEG_debug_stats_gnuplot(const struct Depsgraph *graph,
/* ************************************************ */
-/* Compare two dependency graphs. */
+/** Compare two dependency graphs. */
bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *graph2);
-/* Check that dependencies in the graph are really up to date. */
+/** Check that dependencies in the graph are really up to date. */
bool DEG_debug_graph_relations_validate(struct Depsgraph *graph,
struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
-/* Perform consistency check on the graph. */
+/** Perform consistency check on the graph. */
bool DEG_debug_consistency_check(struct Depsgraph *graph);
#ifdef __cplusplus
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index e9195a1eb26..ebb5f4d669c 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -47,87 +47,106 @@ struct ViewLayer;
extern "C" {
#endif
-/* *********************** DEG input data ********************* */
+/* -------------------------------------------------------------------- */
+/** \name DEG input data
+ * \{ */
-/* Get scene that depsgraph was built for. */
+/** Get scene that depsgraph was built for. */
struct Scene *DEG_get_input_scene(const Depsgraph *graph);
-/* Get view layer that depsgraph was built for. */
+/** Get view layer that depsgraph was built for. */
struct ViewLayer *DEG_get_input_view_layer(const Depsgraph *graph);
-/* Get bmain that depsgraph was built for. */
+/** Get bmain that depsgraph was built for. */
struct Main *DEG_get_bmain(const Depsgraph *graph);
-/* Get evaluation mode that depsgraph was built for. */
+/** Get evaluation mode that depsgraph was built for. */
eEvaluationMode DEG_get_mode(const Depsgraph *graph);
-/* Get time that depsgraph is being evaluated or was last evaluated at. */
+/** Get time that depsgraph is being evaluated or was last evaluated at. */
float DEG_get_ctime(const Depsgraph *graph);
-/* ********************* DEG evaluated data ******************* */
+/** \} */
-/* Check if given ID type was tagged for update. */
+/* -------------------------------------------------------------------- */
+/** \name DEG evaluated data
+ * \{ */
+
+/** Check if given ID type was tagged for update. */
bool DEG_id_type_updated(const struct Depsgraph *depsgraph, short id_type);
bool DEG_id_type_any_updated(const struct Depsgraph *depsgraph);
-/* Check if given ID type is present in the depsgraph */
+/** Check if given ID type is present in the depsgraph */
bool DEG_id_type_any_exists(const struct Depsgraph *depsgraph, short id_type);
-/* Get additional evaluation flags for the given ID. */
+/** Get additional evaluation flags for the given ID. */
uint32_t DEG_get_eval_flags_for_id(const struct Depsgraph *graph, struct ID *id);
-/* Get additional mesh CustomData_MeshMasks flags for the given object. */
+/** Get additional mesh CustomData_MeshMasks flags for the given object. */
void DEG_get_customdata_mask_for_object(const struct Depsgraph *graph,
struct Object *object,
struct CustomData_MeshMasks *r_mask);
-/* Get scene at its evaluated state.
+/**
+ * Get scene at its evaluated state.
*
* Technically, this is a copied-on-written and fully evaluated version of the input scene.
* This function will check that the data-block has been expanded (and copied) from the original
- * one. Assert will happen if it's not. */
+ * one. Assert will happen if it's not.
+ */
struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph);
-/* Get view layer at its evaluated state.
- * This is a shortcut for accessing active view layer from evaluated scene. */
+/**
+ * Get view layer at its evaluated state.
+ * This is a shortcut for accessing active view layer from evaluated scene.
+ */
struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph);
-/* Get evaluated version of object for given original one. */
+/** Get evaluated version of object for given original one. */
struct Object *DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object);
-/* Get evaluated version of given ID data-block. */
+/** Get evaluated version of given ID data-block. */
struct ID *DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id);
-/* Get evaluated version of data pointed to by RNA pointer */
+/** Get evaluated version of data pointed to by RNA pointer */
void DEG_get_evaluated_rna_pointer(const struct Depsgraph *depsgraph,
struct PointerRNA *ptr,
struct PointerRNA *r_ptr_eval);
-/* Get original version of object for given evaluated one. */
+/** Get original version of object for given evaluated one. */
struct Object *DEG_get_original_object(struct Object *object);
-/* Get original version of given evaluated ID data-block. */
+/** Get original version of given evaluated ID data-block. */
struct ID *DEG_get_original_id(struct ID *id);
-/* Check whether given ID is an original,
+/**
+ * Check whether given ID is an original,
*
* Original IDs are considered all the IDs which are not covered by copy-on-write system and are
- * not out-of-main localized data-blocks. */
+ * not out-of-main localized data-blocks.
+ */
bool DEG_is_original_id(const struct ID *id);
bool DEG_is_original_object(const struct Object *object);
/* Opposite of the above.
*
* If the data-block is not original it must be evaluated, and vice versa. */
+
bool DEG_is_evaluated_id(const struct ID *id);
bool DEG_is_evaluated_object(const struct Object *object);
-/* Check whether depsgraph is fully evaluated. This includes the following checks:
+/**
+ * Check whether depsgraph is fully evaluated. This includes the following checks:
* - Relations are up-to-date.
- * - Nothing is tagged for update. */
+ * - Nothing is tagged for update.
+ */
bool DEG_is_fully_evaluated(const struct Depsgraph *depsgraph);
-/* ************************ DEG object iterators ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG object iterators
+ * \{ */
enum {
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY = (1 << 0),
@@ -207,7 +226,11 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END DEG_OBJECT_ITER_END
-/* ************************ DEG ID iterators ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG ID iterators
+ * \{ */
typedef struct DEGIDIterData {
struct Depsgraph *graph;
@@ -221,15 +244,20 @@ void DEG_iterator_ids_begin(struct BLI_Iterator *iter, DEGIDIterData *data);
void DEG_iterator_ids_next(struct BLI_Iterator *iter);
void DEG_iterator_ids_end(struct BLI_Iterator *iter);
-/* ************************ DEG traversal ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DEG traversal
+ * \{ */
typedef void (*DEGForeachIDCallback)(ID *id, void *user_data);
typedef void (*DEGForeachIDComponentCallback)(ID *id,
eDepsObjectComponentType component,
void *user_data);
-/* NOTE: Modifies runtime flags in depsgraph nodes, so can not be used in
- * parallel. Keep an eye on that!
+/**
+ * \note Modifies runtime flags in depsgraph nodes,
+ * so can not be used in parallel. Keep an eye on that!
*/
void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
const ID *id,
@@ -240,8 +268,10 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
DEGForeachIDCallback callback,
void *user_data);
-/* Starts traversal from given component of the given ID, invokes callback for every other
- * component which is directly on indirectly dependent on the source one. */
+/**
+ * Starts traversal from given component of the given ID, invokes callback for every other
+ * component which is directly on indirectly dependent on the source one.
+ */
enum {
/* Ignore transform solvers which depends on multiple inputs and affects final transform.
* Is used for cases like snapping objects which are part of a rigid body simulation:
@@ -262,6 +292,8 @@ void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph,
void DEG_foreach_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data);
+/** \} */
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 41512168f57..b2e136c3d3b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -176,7 +176,22 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
for (Relation *rel : op_node->inlinks) {
if (rel->from->type == NodeType::OPERATION) {
OperationNode *op_from = (OperationNode *)rel->from;
- op_from->owner->affects_directly_visible |= op_node->owner->affects_directly_visible;
+ ComponentNode *comp_from = op_from->owner;
+ const bool target_directly_visible = op_node->owner->affects_directly_visible;
+
+ /* Visibility component forces all components of the current ID to be considered as
+ * affecting directly visible. */
+ if (comp_from->type == NodeType::VISIBILITY) {
+ if (target_directly_visible) {
+ IDNode *id_node_from = comp_from->owner;
+ for (ComponentNode *comp_node : id_node_from->components.values()) {
+ comp_node->affects_directly_visible |= target_directly_visible;
+ }
+ }
+ }
+ else {
+ comp_from->affects_directly_visible |= target_directly_visible;
+ }
}
}
/* Schedule parent nodes. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index a09f79ffa39..51582508b6f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -179,15 +179,30 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
id_node->previously_visible_components_mask = previously_visible_components_mask;
id_node->previous_eval_flags = previous_eval_flags;
id_node->previous_customdata_masks = previous_customdata_masks;
+
/* NOTE: Zero number of components indicates that ID node was just created. */
- if (id_node->components.is_empty() && deg_copy_on_write_is_needed(id_type)) {
- ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE);
- OperationNode *op_cow = comp_cow->add_operation(
- [id_node](::Depsgraph *depsgraph) { deg_evaluate_copy_on_write(depsgraph, id_node); },
- OperationCode::COPY_ON_WRITE,
- "",
- -1);
- graph_->operations.append(op_cow);
+ const bool is_newly_created = id_node->components.is_empty();
+
+ if (is_newly_created) {
+ if (deg_copy_on_write_is_needed(id_type)) {
+ ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE);
+ OperationNode *op_cow = comp_cow->add_operation(
+ [id_node](::Depsgraph *depsgraph) { deg_evaluate_copy_on_write(depsgraph, id_node); },
+ OperationCode::COPY_ON_WRITE,
+ "",
+ -1);
+ graph_->operations.append(op_cow);
+ }
+
+ ComponentNode *visibility_component = id_node->add_component(NodeType::VISIBILITY);
+ OperationNode *visibility_operation = visibility_component->add_operation(
+ nullptr, OperationCode::OPERATION, "", -1);
+ /* Pin the node so that it and its relations are preserved by the unused nodes/relations
+ * deletion. This is mainly to make it easier to debug visibility. */
+ /* NOTE: Keep un-pinned for the 3.0 release. This way we are more sure that side effects of the
+ * change is minimal outside of the dependency graph area. */
+ // visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED;
+ graph_->operations.append(visibility_operation);
}
return id_node;
}
@@ -375,8 +390,6 @@ void DepsgraphNodeBuilder::begin_build()
* NOTE: This is split in two, a static function and a public method of the node builder, to allow
* the code to access the builder's data more easily. */
-/* `id_cow_self` is the user of `id_pointer`, see also `LibraryIDLinkCallbackData` struct
- * definition. */
int DepsgraphNodeBuilder::foreach_id_cow_detect_need_for_update_callback(ID *id_cow_self,
ID *id_pointer)
{
@@ -425,21 +438,18 @@ static int foreach_id_cow_detect_need_for_update_callback(LibraryIDLinkCallbackD
return builder->foreach_id_cow_detect_need_for_update_callback(id_cow_self, id);
}
-/* Check for IDs that need to be flushed (COW-updated) because the depsgraph itself created or
- * removed some of their evaluated dependencies.
- *
- * NOTE: Currently the only ID types that depsgraph may decide to not evaluate/generate COW
- * copies for, even though they are referenced by other data-blocks, are Collections and Objects
- * (through their various visibility flags, and the ones from LayerCollections too). However, this
- * code is kept generic as it makes it more future-proof, and optimization here would give
- * negligible performance improvements in typical cases.
- *
- * NOTE: This mechanism may also 'fix' some missing update tagging from non-depsgraph code in
- * some cases. This is slightly unfortunate (as it may hide issues in other parts of Blender
- * code), but cannot really be avoided currently.
- */
void DepsgraphNodeBuilder::update_invalid_cow_pointers()
{
+ /* NOTE: Currently the only ID types that depsgraph may decide to not evaluate/generate COW
+ * copies for, even though they are referenced by other data-blocks, are Collections and Objects
+ * (through their various visibility flags, and the ones from #LayerCollections too). However,
+ * this code is kept generic as it makes it more future-proof, and optimization here would give
+ * negligible performance improvements in typical cases.
+ *
+ * NOTE: This mechanism may also 'fix' some missing update tagging from non-depsgraph code in
+ * some cases. This is slightly unfortunate (as it may hide issues in other parts of Blender
+ * code), but cannot really be avoided currently. */
+
for (const IDNode *id_node : graph_->id_nodes) {
if (id_node->previously_visible_components_mask == 0) {
/* Newly added node/ID, no need to check it. */
@@ -1056,10 +1066,6 @@ void DepsgraphNodeBuilder::build_object_pointcache(Object *object)
});
}
-/**
- * Build graph nodes for AnimData block and any animated images used.
- * \param id: ID-Block which hosts the AnimData
- */
void DepsgraphNodeBuilder::build_animdata(ID *id)
{
/* Special handling for animated images/sequences. */
@@ -1113,9 +1119,6 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
}
}
-/**
- * Build graph nodes to update the current frame in image users.
- */
void DepsgraphNodeBuilder::build_animation_images(ID *id)
{
if (BKE_image_user_id_has_animation(id)) {
@@ -1137,12 +1140,6 @@ void DepsgraphNodeBuilder::build_action(bAction *action)
add_operation_node(&action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL);
}
-/**
- * Build graph node(s) for Driver
- * \param id: ID-Block that driver is attached to
- * \param fcu: Driver-FCurve
- * \param driver_index: Index in animation data drivers list
- */
void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index)
{
/* Create data node for this driver */
@@ -1715,7 +1712,6 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
build_animdata(&ntree->id);
/* Shading update. */
add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
- add_operation_node(&ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index d31290ecbff..2d24dc49802 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -102,6 +102,10 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void begin_build();
virtual void end_build();
+ /**
+ * `id_cow_self` is the user of `id_pointer`,
+ * see also `LibraryIDLinkCallbackData` struct definition.
+ */
int foreach_id_cow_detect_need_for_update_callback(ID *id_cow_self, ID *id_pointer);
IDNode *add_id_node(ID *id);
@@ -199,10 +203,23 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_rigidbody(Scene *scene);
virtual void build_particle_systems(Object *object, bool is_object_visible);
virtual void build_particle_settings(ParticleSettings *part);
+ /**
+ * Build graph nodes for #AnimData block and any animated images used.
+ * \param id: ID-Block which hosts the #AnimData
+ */
virtual void build_animdata(ID *id);
virtual void build_animdata_nlastrip_targets(ListBase *strips);
+ /**
+ * Build graph nodes to update the current frame in image users.
+ */
virtual void build_animation_images(ID *id);
virtual void build_action(bAction *action);
+ /**
+ * Build graph node(s) for Driver
+ * \param id: ID-Block that driver is attached to
+ * \param fcurve: Driver-FCurve
+ * \param driver_index: Index in animation data drivers list
+ */
virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
virtual void build_driver_variables(ID *id, FCurve *fcurve);
virtual void build_driver_id_property(ID *id, const char *rna_path);
@@ -280,6 +297,10 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
void *user_data);
void tag_previously_tagged_nodes();
+ /**
+ * Check for IDs that need to be flushed (COW-updated)
+ * because the depsgraph itself created or removed some of their evaluated dependencies.
+ */
void update_invalid_cow_pointers();
/* State which demotes currently built entities. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index 17c2925b7f4..79f358213d3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -30,7 +30,6 @@
namespace blender::deg {
-/* Debug contents of map */
void RootPChanMap::print_debug()
{
map_.foreach_item([](StringRefNull key, const Set<StringRefNull> &values) {
@@ -42,13 +41,11 @@ void RootPChanMap::print_debug()
});
}
-/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *root)
{
map_.lookup_or_add_default(bone).add(root);
}
-/* Check if there's a common root bone between two bones. */
bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) const
{
const Set<StringRefNull> *bone1_roots = map_.lookup_ptr(bone1);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index 0dd4062c353..42f9ec9cc6a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -29,13 +29,13 @@ namespace blender {
namespace deg {
struct RootPChanMap {
- /* Debug contents of map. */
+ /** Debug contents of map. */
void print_debug();
- /* Add a mapping. */
+ /** Add a mapping. */
void add_bone(const char *bone, const char *root);
- /* Check if there's a common root bone between two bones. */
+ /** Check if there's a common root bone between two bones. */
bool has_common_root(const char *bone1, const char *bone2) const;
protected:
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 55e8c5ed033..b195b2d9e11 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -368,6 +368,13 @@ Relation *DepsgraphRelationBuilder::add_time_relation(TimeSourceNode *timesrc,
return nullptr;
}
+void DepsgraphRelationBuilder::add_visibility_relation(ID *id_from, ID *id_to)
+{
+ ComponentKey from_key(id_from, NodeType::VISIBILITY);
+ ComponentKey to_key(id_to, NodeType::VISIBILITY);
+ add_relation(from_key, to_key, "visibility");
+}
+
Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_from,
OperationNode *node_to,
const char *description,
@@ -2066,7 +2073,8 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key)
* and also for the links coming from the shapekey data-blocks
* - Animation/Drivers affecting the parameters of the geometry are made to
* trigger updates on the obdata geometry component, which then trigger
- * downstream re-evaluation of the individual instances of this geometry. */
+ * downstream re-evaluation of the individual instances of this geometry.
+ */
void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
{
ID *obdata = (ID *)object->data;
@@ -2521,16 +2529,13 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
- OperationKey shading_parameters_key(
- &ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE);
- add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters");
if (check_id_has_anim_component(&ntree->id)) {
ComponentKey animation_key(&ntree->id, NodeType::ANIMATION);
- add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters");
+ add_relation(animation_key, shading_update_key, "NTree Shading Parameters");
}
ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS);
- add_relation(parameters_key, shading_parameters_key, "NTree Shading Parameters");
+ add_relation(parameters_key, shading_update_key, "NTree Shading Parameters");
}
/* Recursively build graph for material */
@@ -2864,7 +2869,8 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations()
}
}
-/* Nested datablocks (node trees, shape keys) requires special relation to
+/**
+ * Nested datablocks (node trees, shape keys) requires special relation to
* ensure owner's datablock remapping happens after node tree itself is ready.
*
* This is similar to what happens in ntree_hack_remap_pointers().
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index f0393544511..09003de3ce4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -336,6 +336,11 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
Node *node_to,
const char *description,
int flags = 0);
+
+ /* Add relation which ensures visibility of `id_from` when `id_to` is visible.
+ * For the more detailed explanation see comment for `NodeType::VISIBILITY`. */
+ void add_visibility_relation(ID *id_from, ID *id_to);
+
Relation *add_operation_relation(OperationNode *node_from,
OperationNode *node_to,
const char *description,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
index bf3af571f0b..6e5c1f05cf3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.cc
@@ -83,7 +83,6 @@ bool DriverDescriptor::is_array() const
return is_array_;
}
-/* Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
bool DriverDescriptor::is_same_array_as(const DriverDescriptor &other) const
{
if (!is_array_ || !other.is_array_) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
index c80c69be9e2..4ad5bdda1ef 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
@@ -37,14 +37,17 @@ namespace deg {
/* Helper class for determining which relations are needed between driver evaluation nodes. */
class DriverDescriptor {
public:
- /* Drivers are grouped by their RNA prefix. The prefix is the part of the RNA
+ /**
+ * Drivers are grouped by their RNA prefix. The prefix is the part of the RNA
* path up to the last dot, the suffix is the remainder of the RNA path:
*
+ * \code{.unparsed}
* fcu->rna_path rna_prefix rna_suffix
* ------------------------------- ---------------------- ----------
* 'color' '' 'color'
* 'rigidbody_world.time_scale' 'rigidbody_world' 'time_scale'
* 'pose.bones["master"].location' 'pose.bones["master"]' 'location'
+ * \endcode
*/
StringRef rna_prefix;
StringRef rna_suffix;
@@ -54,7 +57,7 @@ class DriverDescriptor {
bool driver_relations_needed() const;
bool is_array() const;
- /* Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
+ /** Assumes that 'other' comes from the same RNA group, that is, has the same RNA path prefix. */
bool is_same_array_as(const DriverDescriptor &other) const;
OperationKey depsgraph_key() const;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 4754749e2e5..3039eebe857 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -450,6 +450,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
/* Custom shape. */
if (pchan->custom != nullptr) {
build_object(pchan->custom);
+ add_visibility_relation(&pchan->custom->id, &armature->id);
}
}
}
@@ -506,6 +507,12 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
&proxy_from->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name);
add_relation(from_bone_parameters, bone_parameters, "Proxy Bone Parameters");
}
+
+ /* Custom shape. */
+ if (pchan->custom != nullptr) {
+ build_object(pchan->custom);
+ add_visibility_relation(&pchan->custom->id, &armature->id);
+ }
}
}
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 57c6f062611..7be661d9668 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -105,11 +105,10 @@ static const int deg_debug_node_type_color_map[][2] = {
{NodeType::GEOMETRY, 6},
{NodeType::SEQUENCER, 7},
{NodeType::SHADING, 8},
- {NodeType::SHADING_PARAMETERS, 9},
- {NodeType::CACHE, 10},
- {NodeType::POINT_CACHE, 11},
- {NodeType::LAYER_COLLECTIONS, 12},
- {NodeType::COPY_ON_WRITE, 13},
+ {NodeType::CACHE, 9},
+ {NodeType::POINT_CACHE, 10},
+ {NodeType::LAYER_COLLECTIONS, 11},
+ {NodeType::COPY_ON_WRITE, 12},
{-1, 0},
};
#endif
@@ -411,7 +410,6 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::EVAL_POSE:
case NodeType::BONE:
case NodeType::SHADING:
- case NodeType::SHADING_PARAMETERS:
case NodeType::CACHE:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
@@ -426,6 +424,7 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::AUDIO:
case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK:
+ case NodeType::VISIBILITY:
case NodeType::SIMULATION: {
ComponentNode *comp_node = (ComponentNode *)node;
if (comp_node->operations.is_empty()) {
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 4c036417ba0..b348ab0f432 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -182,7 +182,6 @@ void Depsgraph::clear_id_nodes()
clear_physics_relations(this);
}
-/* Add new relation between two nodes */
Relation *Depsgraph::add_new_relation(Node *from, Node *to, const char *description, int flags)
{
Relation *rel = nullptr;
@@ -228,7 +227,6 @@ Relation *Depsgraph::check_nodes_connected(const Node *from,
/* Low level tagging -------------------------------------- */
-/* Tag a specific node as needing updates. */
void Depsgraph::add_entry_tag(OperationNode *node)
{
/* Sanity check. */
@@ -280,7 +278,6 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const
/* **************** */
/* Public Graph API */
-/* Initialize a new Depsgraph */
Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
{
deg::Depsgraph *deg_depsgraph = new deg::Depsgraph(bmain, scene, view_layer, mode);
@@ -288,10 +285,6 @@ Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEval
return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
-/* Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph.
- * Used for:
- * - Undo steps when we do want to re-use the old depsgraph data as much as possible.
- * - Rendering where we want to re-use objects between different view layers. */
void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
@@ -313,7 +306,6 @@ void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
}
}
-/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
if (graph == nullptr) {
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 913b61ca563..bfe6ed649f6 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -72,7 +72,7 @@ struct Depsgraph {
IDNode *add_id_node(ID *id, ID *id_cow_hint = nullptr);
void clear_id_nodes();
- /* Add new relationship between two nodes. */
+ /** Add new relationship between two nodes. */
Relation *add_new_relation(Node *from, Node *to, const char *description, int flags = 0);
/* Check whether two nodes are connected by relation with given
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 9e9191c5ab9..db00c595383 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -252,7 +252,6 @@ struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *node_handle)
/* ******************** */
/* Graph Building API's */
-/* Build depsgraph for the given scene layer, and dump results in given graph container. */
void DEG_graph_build_from_view_layer(Depsgraph *graph)
{
deg::ViewLayerBuilderPipeline builder(graph);
@@ -283,7 +282,6 @@ void DEG_graph_build_from_ids(Depsgraph *graph, ID **ids, const int num_ids)
builder.build();
}
-/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
DEG_DEBUG_PRINTF(graph, TAG, "%s: Tagging relations for update.\n", __func__);
@@ -301,7 +299,6 @@ void DEG_graph_tag_relations_update(Depsgraph *graph)
}
}
-/* Create or update relations in the specified graph. */
void DEG_graph_relations_update(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = (deg::Depsgraph *)graph;
@@ -312,7 +309,6 @@ void DEG_graph_relations_update(Depsgraph *graph)
DEG_graph_build_from_view_layer(graph);
}
-/* Tag all relations for update. */
void DEG_relations_tag_update(Main *bmain)
{
DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__);
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index 3677f80469c..9e3cbdbec09 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -196,12 +196,6 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
/* ------------------------------------------------ */
-/**
- * Obtain simple statistics about the complexity of the depsgraph.
- * \param[out] r_outer: The number of outer nodes in the graph
- * \param[out] r_operations: The number of operation nodes in the graph
- * \param[out] r_relations: The number of relations between (executable) nodes in the graph
- */
void DEG_stats_simple(const Depsgraph *graph,
size_t *r_outer,
size_t *r_operations,
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 0314219b725..7952f27507f 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -60,7 +60,6 @@ static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph)
deg::deg_evaluate_on_refresh(deg_graph);
}
-/* Evaluate all nodes tagged for updating. */
void DEG_evaluate_on_refresh(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
@@ -77,7 +76,6 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
deg_flush_updates_and_refresh(deg_graph);
}
-/* Frame-change happened for root scene that graph belongs to. */
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index aab4c3ca0f6..6c1947728b5 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -200,7 +200,6 @@ ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
return id_node->id_cow;
}
-/* Get evaluated version of data pointed to by RNA pointer */
void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph,
PointerRNA *ptr,
PointerRNA *r_ptr_eval)
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index 6ce7cc0837b..65a21323258 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -77,6 +77,12 @@ void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
TraversalQueue queue;
Set<OperationNode *> scheduled;
for (ComponentNode *comp_node : target_id_node->components.values()) {
+ if (comp_node->type == NodeType::VISIBILITY) {
+ /* Visibility component is only used internally. It is not to be reporting dependencies to
+ * the outer world. */
+ continue;
+ }
+
if (source_component_type != DEG_OB_COMP_ANY &&
nodeTypeToObjectComponent(comp_node->type) != source_component_type) {
continue;
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index dd96c5a3b2b..2b0d0e6e780 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -193,12 +193,7 @@ void depsgraph_tag_to_component_opcode(const ID *id,
*component_type = NodeType::COPY_ON_WRITE;
break;
case ID_RECALC_SHADING:
- if (id_type == ID_NT) {
- *component_type = NodeType::SHADING_PARAMETERS;
- }
- else {
- *component_type = NodeType::SHADING;
- }
+ *component_type = NodeType::SHADING;
break;
case ID_RECALC_SELECT:
depsgraph_select_tag_to_component_opcode(id, component_type, operation_code);
@@ -760,7 +755,6 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
/* Data-Based Tagging. */
-/* Tag given ID for an update in all the dependency graphs. */
void DEG_id_tag_update(ID *id, int flag)
{
DEG_id_tag_update_ex(G.main, id, flag);
@@ -797,7 +791,6 @@ void DEG_graph_time_tag_update(struct Depsgraph *depsgraph)
deg_graph->tag_time_source();
}
-/* Mark a particular data-block type as having changing. */
void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type)
{
if (id_type == ID_NT) {
@@ -822,7 +815,6 @@ void DEG_id_type_tag(Main *bmain, short id_type)
}
}
-/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
@@ -842,8 +834,6 @@ void DEG_enable_editors_update(Depsgraph *depsgraph)
graph->use_editors_update = true;
}
-/* Check if something was changed in the database and inform
- * editors about this. */
void DEG_editors_update(Depsgraph *depsgraph, bool time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
diff --git a/source/blender/depsgraph/intern/depsgraph_type.cc b/source/blender/depsgraph/intern/depsgraph_type.cc
index 07664cb4f0b..0405a7d90b4 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type.cc
@@ -39,8 +39,7 @@
namespace deg = blender::deg;
-/* Register all node types */
-void DEG_register_node_types(void)
+void DEG_register_node_types()
{
/* register node types */
deg::deg_register_base_depsnodes();
@@ -48,8 +47,7 @@ void DEG_register_node_types(void)
deg::deg_register_operation_depsnodes();
}
-/* Free registry on exit */
-void DEG_free_node_types(void)
+void DEG_free_node_types()
{
}
diff --git a/source/blender/depsgraph/intern/depsgraph_update.cc b/source/blender/depsgraph/intern/depsgraph_update.cc
index bb72320ca67..ec287edbd12 100644
--- a/source/blender/depsgraph/intern/depsgraph_update.cc
+++ b/source/blender/depsgraph/intern/depsgraph_update.cc
@@ -50,7 +50,6 @@ void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool upd
} // namespace blender::deg
-/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func)
{
deg::deg_editor_update_id_cb = id_func;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index d6877adb66b..30aeeee5b2c 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -361,13 +361,6 @@ static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH);
}
-/**
- * Evaluate all nodes tagged for updating,
- * \warning This is usually done as part of main loop, but may also be
- * called from frame-change update.
- *
- * \note Time sources should be all valid!
- */
void deg_evaluate_on_refresh(Depsgraph *graph)
{
/* Nothing to update, early out. */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 68a72638c7d..116dba054fa 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -906,7 +906,9 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
return id_cow;
}
-/* NOTE: Depsgraph is supposed to have ID node already. */
+/**
+ * \note Depsgraph is supposed to have ID node already.
+ */
ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, ID *id_orig)
{
IDNode *id_node = depsgraph->find_id_node(id_orig);
@@ -987,10 +989,12 @@ void discard_edit_mode_pointers(ID *id_cow)
} // namespace
-/* Free content of the CoW data-block
+/**
+ Free content of the CoW data-block.
* Notes:
* - Does not recurse into nested ID data-blocks.
- * - Does not free data-block itself. */
+ * - Does not free data-block itself.
+ */
void deg_free_copy_on_write_datablock(ID *id_cow)
{
if (!check_datablock_expanded(id_cow)) {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
index 70e510b5ef9..bc023766a46 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
@@ -50,34 +50,40 @@ struct Depsgraph;
class DepsgraphNodeBuilder;
struct IDNode;
-/* Makes sure given CoW data-block is brought back to state of the original
+/**
+ * Makes sure given CoW data-block is brought back to state of the original
* data-block.
*/
ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, const IDNode *id_node);
ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, struct ID *id_orig);
-/* Helper function which frees memory used by copy-on-written data-block. */
+/** Helper function which frees memory used by copy-on-written data-block. */
void deg_free_copy_on_write_datablock(struct ID *id_cow);
-/* Callback function for depsgraph operation node which ensures copy-on-write
+/**
+ * Callback function for depsgraph operation node which ensures copy-on-write
* data-block is ready for use by further evaluation routines.
*/
void deg_evaluate_copy_on_write(struct ::Depsgraph *depsgraph, const struct IDNode *id_node);
-/* Check that given ID is properly expanded and does not have any shallow
- * copies inside. */
+/**
+ * Check that given ID is properly expanded and does not have any shallow
+ * copies inside.
+ */
bool deg_validate_copy_on_write_datablock(ID *id_cow);
-/* Tag given ID block as being copy-on-written. */
+/** Tag given ID block as being copy-on-written. */
void deg_tag_copy_on_write_id(struct ID *id_cow, const struct ID *id_orig);
-/* Check whether ID data-block is expanded.
+/**
+ * Check whether ID data-block is expanded.
*
* TODO(sergey): Make it an inline function or a macro.
*/
bool deg_copy_on_write_is_expanded(const struct ID *id_cow);
-/* Check whether copy-on-write data-block is needed for given ID.
+/**
+ * Check whether copy-on-write data-block is needed for given ID.
*
* There are some exceptions on data-blocks which are covered by dependency graph
* but which we don't want to start duplicating.
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index a015491e2d7..7ec77689ba5 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -346,9 +346,6 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph)
} // namespace
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
- */
void deg_graph_flush_updates(Depsgraph *graph)
{
/* Sanity checks. */
@@ -395,7 +392,6 @@ void deg_graph_flush_updates(Depsgraph *graph)
invalidate_tagged_evaluated_data(graph);
}
-/* Clear tags from all operation nodes. */
void deg_graph_clear_tags(Depsgraph *graph)
{
/* Go over all operation nodes, clearing tags. */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
index ec661360fdf..d70df62cb38 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -30,12 +30,14 @@ namespace deg {
struct Depsgraph;
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
+/**
+ * Flush updates from tagged nodes outwards until all affected nodes are tagged.
*/
void deg_graph_flush_updates(struct Depsgraph *graph);
-/* Clear tags from all operation nodes. */
+/**
+ * Clear tags from all operation nodes.
+ */
void deg_graph_clear_tags(struct Depsgraph *graph);
} // namespace deg
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index 16089ba27dd..8bc03d8b736 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -94,8 +94,6 @@ const char *nodeTypeAsString(NodeType type)
return "PARTICLE_SETTINGS";
case NodeType::SHADING:
return "SHADING";
- case NodeType::SHADING_PARAMETERS:
- return "SHADING_PARAMETERS";
case NodeType::CACHE:
return "CACHE";
case NodeType::POINT_CACHE:
@@ -114,6 +112,8 @@ const char *nodeTypeAsString(NodeType type)
return "ARMATURE";
case NodeType::GENERIC_DATABLOCK:
return "GENERIC_DATABLOCK";
+ case NodeType::VISIBILITY:
+ return "VISIBILITY";
case NodeType::SIMULATION:
return "SIMULATION";
@@ -159,7 +159,6 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::GENERIC_DATABLOCK:
case NodeType::PARTICLE_SYSTEM:
case NodeType::PARTICLE_SETTINGS:
- case NodeType::SHADING_PARAMETERS:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
case NodeType::BATCH_CACHE:
@@ -176,6 +175,10 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::PROXY:
case NodeType::SIMULATION:
return DEG_SCENE_COMP_PARAMETERS;
+
+ case NodeType::VISIBILITY:
+ BLI_assert_msg(0, "Visibility component is supposed to be only used internally.");
+ return DEG_SCENE_COMP_PARAMETERS;
}
BLI_assert_msg(0, "Unhandled node type, not supposed to happen.");
return DEG_SCENE_COMP_PARAMETERS;
@@ -242,7 +245,6 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::GENERIC_DATABLOCK:
case NodeType::PARTICLE_SYSTEM:
case NodeType::PARTICLE_SETTINGS:
- case NodeType::SHADING_PARAMETERS:
case NodeType::POINT_CACHE:
case NodeType::IMAGE_ANIMATION:
case NodeType::BATCH_CACHE:
@@ -252,6 +254,10 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
return DEG_OB_COMP_PARAMETERS;
+
+ case NodeType::VISIBILITY:
+ BLI_assert_msg(0, "Visibility component is supposed to be only used internally.");
+ return DEG_OB_COMP_PARAMETERS;
}
BLI_assert_msg(0, "Unhandled node type, not suppsed to happen.");
return DEG_OB_COMP_PARAMETERS;
@@ -305,7 +311,6 @@ Node::~Node()
}
}
-/* Generic identifier for Depsgraph Nodes. */
string Node::identifier() const
{
return string(nodeTypeAsString(type)) + " : " + name;
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index e1469b68b0e..7e093ab8765 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -103,6 +103,22 @@ enum class NodeType {
* not have very distinctive update procedure. */
GENERIC_DATABLOCK,
+ /* Component which is used to define visibility relation between IDs, on the ID level.
+ *
+ * Consider two ID nodes NodeA and NodeB, with the relation between visibility components going
+ * as NodeA -> NodeB. If NodeB is considered visible on screen, then the relation will ensure
+ * that NodeA is also visible. The way how relation is oriented could be seen as a inverted from
+ * visibility dependency point of view, but it follows the same direction as data dependency
+ * which simplifies common algorithms which are dealing with relations and visibility.
+ *
+ * The fact that the visibility operates on the ID level basically means that all components in
+ * NodeA will be considered as affecting directly visible when NodeB's visibility is
+ * affecting directly visible ID.
+ *
+ * This is the way to ensure objects needed for visualization without any actual data dependency
+ * are properly evaluated. Example of this is custom shapes for bones. */
+ VISIBILITY,
+
/* **** Evaluation-Related Outer Types (with Subdata) **** */
/* Pose Component - Owner/Container of Bones Eval */
@@ -114,7 +130,6 @@ enum class NodeType {
PARTICLE_SETTINGS,
/* Material Shading Component */
SHADING,
- SHADING_PARAMETERS,
/* Point cache Component */
POINT_CACHE,
/* Image Animation Component */
@@ -186,6 +201,7 @@ struct Node {
Node();
virtual ~Node();
+ /** Generic identifier for Depsgraph Nodes. */
virtual string identifier() const;
virtual void init(const ID * /*id*/, const char * /*subdata*/)
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index 0947fad7670..b716877902c 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -43,7 +43,9 @@ namespace blender::deg {
/* *********** */
/* Outer Nodes */
-/* Standard Component Methods ============================= */
+/* -------------------------------------------------------------------- */
+/** \name Standard Component Methods
+ * \{ */
ComponentNode::OperationIDKey::OperationIDKey()
: opcode(OperationCode::OPERATION), name(""), name_tag(-1)
@@ -86,7 +88,6 @@ ComponentNode::ComponentNode()
operations_map = new Map<ComponentNode::OperationIDKey, OperationNode *>();
}
-/* Initialize 'component' node - from pointer data given */
void ComponentNode::init(const ID * /*id*/, const char * /*subdata*/)
{
/* hook up eval context? */
@@ -297,9 +298,12 @@ void ComponentNode::finalize_build(Depsgraph * /*graph*/)
operations_map = nullptr;
}
-/* Bone Component ========================================= */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Component
+ * \{ */
-/* Initialize 'bone component' node - from pointer data given */
void BoneComponentNode::init(const ID *id, const char *subdata)
{
/* generic component-node... */
@@ -315,7 +319,11 @@ void BoneComponentNode::init(const ID *id, const char *subdata)
this->pchan = BKE_pose_channel_find_name(object->pose, subdata);
}
-/* Register all components. =============================== */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Register All Components
+ * \{ */
DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION);
/* TODO(sergey): Is this a correct tag? */
@@ -334,7 +342,6 @@ DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY);
DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, 0);
DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_SHADING);
-DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_SHADING);
DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM);
DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0);
DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0);
@@ -342,9 +349,14 @@ DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0);
DEG_COMPONENT_NODE_DEFINE(Audio, AUDIO, 0);
DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
+DEG_COMPONENT_NODE_DEFINE(Visibility, VISIBILITY, 0);
DEG_COMPONENT_NODE_DEFINE(Simulation, SIMULATION, 0);
-/* Node Types Register =================================== */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Types Register
+ * \{ */
void deg_register_component_depsnodes()
{
@@ -364,7 +376,6 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_EVAL_POSE);
register_node_typeinfo(&DNTI_SEQUENCER);
register_node_typeinfo(&DNTI_SHADING);
- register_node_typeinfo(&DNTI_SHADING_PARAMETERS);
register_node_typeinfo(&DNTI_TRANSFORM);
register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER);
register_node_typeinfo(&DNTI_DUPLI);
@@ -372,7 +383,10 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_AUDIO);
register_node_typeinfo(&DNTI_ARMATURE);
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
+ register_node_typeinfo(&DNTI_VISIBILITY);
register_node_typeinfo(&DNTI_SIMULATION);
}
+/** \} */
+
} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 6e31ef268ed..9f108af8012 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -67,6 +67,7 @@ struct ComponentNode : public Node {
ComponentNode();
~ComponentNode();
+ /** Initialize 'component' node - from pointer data given. */
void init(const ID *id, const char *subdata) override;
virtual string identifier() const override;
@@ -188,6 +189,15 @@ struct ComponentNode : public Node {
} \
}
+#define DEG_COMPONENT_NODE_DECLARE_NO_COW(name) \
+ struct name##ComponentNode : public ComponentNode { \
+ DEG_COMPONENT_NODE_DECLARE; \
+ virtual bool depends_on_cow() \
+ { \
+ return false; \
+ } \
+ }
+
DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(BatchCache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache);
@@ -210,10 +220,12 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
+DEG_COMPONENT_NODE_DECLARE_NO_COW(Visibility);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
+ /** Initialize 'bone component' node - from pointer data given. */
void init(const ID *id, const char *subdata);
struct bPoseChannel *pchan; /* the bone that this component represents */
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc
index 2b1ebc663fe..baad8318de2 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_id.cc
@@ -73,7 +73,6 @@ uint64_t IDNode::ComponentIDKey::hash() const
BLI_ghashutil_strhash_p(name));
}
-/* Initialize 'id' node - from pointer data given. */
void IDNode::init(const ID *id, const char *UNUSED(subdata))
{
BLI_assert(id != nullptr);
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index 073469598dc..257e42b8e67 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -58,6 +58,7 @@ struct IDNode : public Node {
const char *name;
};
+ /** Initialize 'id' node - from pointer data given. */
virtual void init(const ID *id, const char *subdata) override;
void init_copy_on_write(ID *id_cow_hint = nullptr);
~IDNode();
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index c25dc6fc8d5..eaae5d2d5dc 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -218,8 +218,6 @@ string OperationNode::identifier() const
return string(operationCodeAsString(opcode)) + "(" + name + ")";
}
-/* Full node identifier, including owner name.
- * used for logging and debug prints. */
string OperationNode::full_identifier() const
{
string owner_str = owner->owner->name;
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index a17186da941..31cbb9702ba 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -233,6 +233,10 @@ struct OperationNode : public Node {
OperationNode();
virtual string identifier() const override;
+ /**
+ * Full node identifier, including owner name.
+ * used for logging and debug prints.
+ */
string full_identifier() const;
virtual void tag_update(Depsgraph *graph, eUpdateSource source) override;
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index b8ca22d33d3..30a3b8087c0 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -223,6 +223,9 @@ set(SRC
engines/external/external_engine.h
engines/image/image_engine.h
engines/image/image_private.hh
+ engines/image/image_drawing_mode_image_space.hh
+ engines/image/image_space_image.hh
+ engines/image/image_space_node.hh
engines/workbench/workbench_engine.h
engines/workbench/workbench_private.h
engines/select/select_engine.h
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index af6c8ea62b2..98e166ac3a7 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -75,9 +75,21 @@ typedef enum eDRWSelectStage {
typedef bool (*DRW_SelectPassFn)(eDRWSelectStage stage, void *user_data);
typedef bool (*DRW_ObjectFilterFn)(struct Object *ob, void *user_data);
+/**
+ * Everything starts here.
+ * This function takes care of calling all cache and rendering functions
+ * for each relevant engine / mode engine.
+ */
void DRW_draw_view(const struct bContext *C);
+/**
+ * Draw render engine info.
+ */
void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height);
+/**
+ * Used for both regular and off-screen drawing.
+ * Need to reset DST before calling this function
+ */
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *region,
@@ -88,6 +100,9 @@ void DRW_draw_render_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * \param viewport: can be NULL, in this case we create one.
+ */
void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *region,
@@ -101,6 +116,9 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
struct ARegion *region,
struct GPUViewport *viewport,
const struct bContext *evil_C);
+/**
+ * object mode select-loop, see: #ED_view3d_draw_select_loop (legacy drawing).
+ */
void DRW_draw_select_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -113,14 +131,23 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
void *select_pass_user_data,
DRW_ObjectFilterFn object_filter_fn,
void *object_filter_user_data);
+/**
+ * object mode select-loop, see: #ED_view3d_draw_depth_loop (legacy drawing).
+ */
void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * Converted from #ED_view3d_draw_depth_gpencil (legacy drawing).
+ */
void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
+/**
+ * Clears the Depth Buffer and draws only the specified object.
+ */
void DRW_draw_depth_object(struct Scene *scene,
struct ARegion *region,
struct View3D *v3d,
@@ -131,11 +158,17 @@ void DRW_draw_select_id(struct Depsgraph *depsgraph,
struct View3D *v3d,
const struct rcti *rect);
-/* grease pencil render */
+/* Grease pencil render. */
+
+/**
+ * Helper to check if exit object type to render.
+ */
bool DRW_render_check_grease_pencil(struct Depsgraph *depsgraph);
void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph);
-/* This is here because GPUViewport needs it */
+/**
+ * This is here because #GPUViewport needs it.
+ */
struct DRWInstanceDataList *DRW_instance_data_list_create(void);
void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist);
void DRW_uniform_attrs_pool_free(struct GHash *table);
@@ -165,11 +198,21 @@ void DRW_opengl_context_disable_ex(bool restore);
void DRW_opengl_render_context_enable(void *re_gl_context);
void DRW_opengl_render_context_disable(void *re_gl_context);
+/**
+ * Needs to be called AFTER #DRW_opengl_render_context_enable().
+ */
void DRW_gpu_render_context_enable(void *re_gpu_context);
+/**
+ * Needs to be called BEFORE #DRW_opengl_render_context_disable().
+ */
void DRW_gpu_render_context_disable(void *re_gpu_context);
void DRW_deferred_shader_remove(struct GPUMaterial *mat);
+/**
+ * Get DrawData from the given ID-block. In order for this to work, we assume that
+ * the DrawData pointer is stored in the struct in the same fashion as in #IdDdtTemplate.
+ */
struct DrawDataList *DRW_drawdatalist_from_id(struct ID *id);
void DRW_drawdata_free(struct ID *id);
@@ -179,7 +222,10 @@ void DRW_viewport_data_free(struct DRWData *drw_data);
bool DRW_opengl_context_release(void);
void DRW_opengl_context_activate(bool drw_state);
-/* We may want to move this into a more general location. */
+/**
+ * We may want to move this into a more general location.
+ * \note This doesn't require the draw context to be in use.
+ */
void DRW_draw_cursor_2d_ex(const struct ARegion *region, const float cursor[2]);
#ifdef __cplusplus
diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h
index 43d4005c3a9..18134558af8 100644
--- a/source/blender/draw/DRW_select_buffer.h
+++ b/source/blender/draw/DRW_select_buffer.h
@@ -81,6 +81,7 @@ typedef struct SELECTID_Context {
} SELECTID_Context;
/* draw_select_buffer.c */
+
bool DRW_select_buffer_elem_get(const uint sel_id,
uint *r_elem,
uint *r_base_index,
@@ -88,22 +89,41 @@ bool DRW_select_buffer_elem_get(const uint sel_id,
uint DRW_select_buffer_context_offset_for_object_elem(struct Depsgraph *depsgraph,
struct Object *object,
char elem_type);
+/**
+ * Main function to read a block of pixels from the select frame buffer.
+ */
uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const rcti *rect,
uint *r_buf_len);
+/**
+ * \param rect: The rectangle to sample indices from (min/max inclusive).
+ * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
+ */
uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const struct rcti *rect,
uint *r_bitmap_len);
+/**
+ * \param center: Circle center.
+ * \param radius: Circle radius.
+ * \param r_bitmap_len: Number of indices in the selection id buffer.
+ * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure.
+ */
uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2],
const int radius,
uint *r_bitmap_len);
+/**
+ * \param poly: The polygon coordinates.
+ * \param poly_len: Length of the polygon.
+ * \param rect: Polygon boundaries.
+ * \returns a #BLI_bitmap.
+ */
uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -111,10 +131,18 @@ uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
const int poly_len,
const struct rcti *rect,
uint *r_bitmap_len);
+/**
+ * Samples a single pixel.
+ */
uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2]);
+/**
+ * Find the selection id closest to \a center.
+ * \param dist: Use to initialize the distance,
+ * when found, this value is set to the distance of the selection that's returned.
+ */
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 8a825a7c81f..228281af2b0 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -265,6 +265,7 @@ DrawEngineType draw_engine_basic_type = {
&basic_data_size,
NULL,
&basic_engine_free,
+ NULL, /* instance_free */
&basic_cache_init,
&basic_cache_populate,
&basic_cache_finish,
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index 1b8e967e38f..80207523a65 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -435,9 +435,6 @@ void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EE
/** \name Update Render Passes
* \{ */
-/* Register the render passes needed for cryptomatte
- * normally this is done in `EEVEE_render_update_passes`, but it has been placed here to keep
- * related code side-by-side for clarity. */
void EEVEE_cryptomatte_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
{
char cryptomatte_pass_name[MAX_NAME];
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index c2f3e3a6d95..3d32b4acd82 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -411,9 +411,6 @@ static void downsample_radiance_cb(void *vedata, int level)
DRW_draw_pass(psl->color_downsample_ps);
}
-/**
- * Simple down-sampling algorithm. Reconstruct mip chain up to mip level.
- */
void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, GPUTexture *texture_src)
{
EEVEE_PassList *psl = vedata->psl;
@@ -430,9 +427,6 @@ void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, GPUTexture *te
DRW_stats_group_end();
}
-/**
- * Simple down-sampling algorithm for cube-map. Reconstruct mip chain up to mip level.
- */
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level)
{
EEVEE_FramebufferList *fbl = vedata->fbl;
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index fad9d21b660..fc9b8b0cde4 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -629,6 +629,7 @@ DrawEngineType draw_engine_eevee_type = {
&eevee_data_size,
&eevee_engine_init,
&eevee_engine_free,
+ NULL, /* instance_free */
&eevee_cache_init,
&EEVEE_cache_populate,
&eevee_cache_finish,
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 9a85037ac77..bcbe17fdabc 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -806,7 +806,6 @@ wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
return wm_job;
}
-/* MUST run on the main thread. */
void *EEVEE_lightbake_job_data_alloc(struct Main *bmain,
struct ViewLayer *view_layer,
struct Scene *scene,
@@ -1484,8 +1483,6 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
EEVEE_volumes_free_smoke_textures();
}
-/* This is to update the world irradiance and reflection contribution from
- * within the viewport drawing (does not have the overhead of a full light cache rebuild.) */
void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
const Scene *scene)
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
index fde0c80ab37..ccd53f6c037 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.h
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -33,7 +33,9 @@ struct Scene;
struct SceneEEVEE;
struct ViewLayer;
-/* Light Bake */
+/**
+ * Light Bake.
+ */
struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
struct wmWindow *win,
struct Main *bmain,
@@ -41,6 +43,9 @@ struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
struct Scene *scene,
int delay,
int frame);
+/**
+ * MUST run on the main thread.
+ */
void *EEVEE_lightbake_job_data_alloc(struct Main *bmain,
struct ViewLayer *view_layer,
struct Scene *scene,
@@ -50,11 +55,17 @@ void EEVEE_lightbake_job_data_free(void *custom_data);
void EEVEE_lightbake_update(void *custom_data);
void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float *progress);
+/**
+ * This is to update the world irradiance and reflection contribution from
+ * within the viewport drawing (does not have the overhead of a full light cache rebuild.)
+ */
void EEVEE_lightbake_update_world_quick(struct EEVEE_ViewLayerData *sldata,
struct EEVEE_Data *vedata,
const Scene *scene);
-/* Light Cache */
+/**
+ * Light Cache.
+ */
struct LightCache *EEVEE_lightcache_create(const int grid_len,
const int cube_len,
const int cube_size,
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index ab083253499..c51fc18a406 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -202,7 +202,6 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
-/* Only init the passes useful for rendering the light cache. */
void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
GPUTexture *rt_color,
@@ -871,7 +870,6 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
DRW_draw_pass(psl->transparent_pass);
}
-/* Render the scene to the probe_rt texture. */
void EEVEE_lightbake_render_scene(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUFrameBuffer *face_fb[6],
@@ -969,13 +967,13 @@ static void eevee_lightbake_render_scene_to_planars(EEVEE_ViewLayerData *sldata,
sldata->probes->planar_data,
sldata->probes->num_planar);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Filtering
* \{ */
-/* Glossy filter rt_color to light_cache->cube_tx.tex at index probe_idx */
void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
@@ -1064,7 +1062,6 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
}
}
-/* Diffuse filter rt_color to light_cache->grid_tx.tex at index grid_offset */
void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
@@ -1117,7 +1114,6 @@ void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
GPU_framebuffer_viewport_reset(fb);
}
-/* Filter rt_depth to light_cache->grid_tx.tex at index grid_offset */
void EEVEE_lightbake_filter_visibility(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *UNUSED(rt_depth),
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index afaf604322c..4ed968e2935 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -28,7 +28,6 @@
#include "eevee_private.h"
-/* Reconstruct local obmat from EEVEE_light. (normalized) */
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4])
{
copy_v3_v3(r_mat[0], evli->rightvec);
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 582540529a6..a0522ad94d2 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -76,9 +76,6 @@ struct GPUTexture *EEVEE_materials_get_util_tex(void)
return e_data.util_tex;
}
-/**
- * ssr_id can be null to disable ssr contribution.
- */
void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
GPUMaterial *gpumat,
EEVEE_ViewLayerData *sldata,
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 1eff2a3af24..703518a32ec 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -29,6 +29,7 @@
#include "BKE_animsys.h"
#include "BKE_camera.h"
+#include "BKE_duplilist.h"
#include "BKE_object.h"
#include "BKE_screen.h"
@@ -318,6 +319,14 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
return;
}
+ const DupliObject *dup = DRW_object_get_dupli(ob);
+ if (dup != NULL && dup->ob->data != dup->ob_data) {
+ /* Geometry instances do not support motion blur correctly yet. The #key used in
+ * #motion_blur_deform_data_get has to take ids of instances (#DupliObject.persistent_id) into
+ * account. Otherwise it can't find matching geometry instances at different points in time. */
+ return;
+ }
+
EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
&effects->motion_blur, ob, false);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index f51b4fa0127..f0d518a58b1 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -992,6 +992,8 @@ typedef struct EEVEE_Data {
EEVEE_TextureList *txl;
EEVEE_PassList *psl;
EEVEE_StorageList *stl;
+ void *instance_data;
+
char info[GPU_INFO_SIZE];
} EEVEE_Data;
@@ -1071,6 +1073,7 @@ typedef struct EEVEE_PrivateData {
} EEVEE_PrivateData; /* Transient data */
/* eevee_data.c */
+
void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb);
void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb);
void EEVEE_view_layer_data_free(void *storage);
@@ -1095,6 +1098,7 @@ EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo);
void eevee_id_update(void *vedata, ID *id);
/* eevee_materials.c */
+
struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
@@ -1119,6 +1123,9 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d
void EEVEE_material_renderpasses_init(EEVEE_Data *vedata);
void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples);
void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * \param ssr_id: Can be null to disable SSR contribution.
+ */
void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
struct GPUMaterial *gpumat,
EEVEE_ViewLayerData *sldata,
@@ -1128,20 +1135,34 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
bool use_ssrefraction,
bool use_alpha_blend);
/* eevee_lights.c */
+
+/**
+ * Reconstruct local `obmat` from EEVEE_light. (normalized).
+ */
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]);
void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/* eevee_shadows.c */
+
void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh);
void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata);
void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * Make that object update shadow casting lights inside its influence bounding box.
+ */
void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
+/**
+ * Return true if sample has changed and light needs to be updated.
+ */
bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs);
void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
+/**
+ * This refresh lights shadow buffers.
+ */
void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view);
void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index);
void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata,
@@ -1152,6 +1173,13 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, u
void EEVEE_shadow_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/* eevee_sampling.c */
+
+/**
+ * Special ball distribution:
+ * Point are distributed in a way that when they are orthogonally
+ * projected into any plane, the resulting distribution is (close to)
+ * a uniform disc distribution.
+ */
void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3]);
void EEVEE_sample_rectangle(int sample_ofs,
const float x_axis[3],
@@ -1168,6 +1196,7 @@ void EEVEE_sample_ellipse(int sample_ofs,
void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]);
/* eevee_shaders.c */
+
void EEVEE_shaders_material_shaders_init(void);
struct DRWShaderLibrary *EEVEE_shader_lib_get(void);
struct GPUShader *EEVEE_shaders_bloom_blit_get(bool high_quality);
@@ -1234,18 +1263,28 @@ struct GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void);
struct GPUShader *EEVEE_shaders_update_noise_sh_get(void);
struct GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void);
struct GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects);
+/**
+ * Configure a default node-tree with the given material.
+ */
struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma);
+/**
+ * Configure a default node-tree with the given world.
+ */
struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo);
Material *EEVEE_material_default_diffuse_get(void);
Material *EEVEE_material_default_glossy_get(void);
Material *EEVEE_material_default_error_get(void);
World *EEVEE_world_default_get(void);
+/**
+ * \note Compilation is not deferred.
+ */
struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options);
struct GPUMaterial *EEVEE_material_get(
EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options);
void EEVEE_shaders_free(void);
/* eevee_lightprobes.c */
+
bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data);
void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -1255,6 +1294,9 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lightprobes_free(void);
+/**
+ * Only initialize the passes useful for rendering the light cache.
+ */
void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
GPUTexture *rt_color,
@@ -1262,12 +1304,18 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
void EEVEE_lightbake_render_world(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUFrameBuffer *face_fb[6]);
+/**
+ * Render the scene to the `probe_rt` texture.
+ */
void EEVEE_lightbake_render_scene(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUFrameBuffer *face_fb[6],
const float pos[3],
float near_clip,
float far_clip);
+/**
+ * Glossy filter `rt_color` to `light_cache->cube_tx.tex` at index `probe_idx`.
+ */
void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
@@ -1277,12 +1325,18 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata,
int maxlevel,
float filter_quality,
float firefly_fac);
+/**
+ * Diffuse filter `rt_color` to `light_cache->grid_tx.tex` at index `grid_offset`.
+ */
void EEVEE_lightbake_filter_diffuse(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_color,
struct GPUFrameBuffer *fb,
int grid_offset,
float intensity);
+/**
+ * Filter `rt_depth` to `light_cache->grid_tx.tex` at index `grid_offset`.
+ */
void EEVEE_lightbake_filter_visibility(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
struct GPUTexture *rt_depth,
@@ -1301,6 +1355,7 @@ void EEVEE_lightprobes_planar_data_from_object(Object *ob,
EEVEE_LightProbeVisTest *vis_test);
/* eevee_depth_of_field.c */
+
int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_depth_of_field_draw(EEVEE_Data *vedata);
@@ -1312,6 +1367,7 @@ int EEVEE_depth_of_field_sample_count_get(EEVEE_EffectsInfo *effects,
int *r_ring_count);
/* eevee_bloom.c */
+
int EEVEE_bloom_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_bloom_draw(EEVEE_Data *vedata);
@@ -1319,6 +1375,7 @@ void EEVEE_bloom_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, ui
void EEVEE_bloom_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/* eevee_cryptomatte.c */
+
void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata);
void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
@@ -1332,6 +1389,11 @@ void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob);
void EEVEE_cryptomatte_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * Register the render passes needed for cryptomatte
+ * normally this is done in `EEVEE_render_update_passes`, but it has been placed here to keep
+ * related code side-by-side for clarity.
+ */
void EEVEE_cryptomatte_update_passes(struct RenderEngine *engine,
struct Scene *scene,
struct ViewLayer *view_layer);
@@ -1407,6 +1469,17 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
bool post_effect);
+/**
+ * Post-process data to construct a specific render-pass
+ *
+ * This method will create a shading group to perform the post-processing for the given
+ * `renderpass_type`. The post-processing will be done and the result will be stored in the
+ * `vedata->txl->renderpass` texture.
+ *
+ * Only invoke this function for passes that need post-processing.
+ *
+ * After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`.
+ */
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
eViewLayerEEVEEPassType renderpass_type,
@@ -1414,6 +1487,10 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
void EEVEE_renderpasses_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata);
bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata);
+/**
+ * Calculate the hash for an AOV. The least significant bit is used to store the AOV
+ * type the rest of the bits are used for the name hash.
+ */
int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov);
/* eevee_temporal_sampling.c */
@@ -1425,11 +1502,16 @@ void EEVEE_temporal_sampling_offset_calc(const double ht_point[2],
const float filter_size,
float r_offset[2]);
void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const double ht_point[2]);
+/**
+ * Update the matrices based on the current sample.
+ * \note `DRW_MAT_PERS` and `DRW_MAT_VIEW` needs to read the original matrices.
+ */
void EEVEE_temporal_sampling_update_matrices(EEVEE_Data *vedata);
void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata);
/* eevee_volumes.c */
+
void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample);
void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -1447,18 +1529,29 @@ void EEVEE_volumes_free_smoke_textures(void);
void EEVEE_volumes_free(void);
/* eevee_effects.c */
+
void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
Object *camera,
const bool minimal);
void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_effects_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * Simple down-sampling algorithm. Reconstruct mip chain up to mip level.
+ */
void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src);
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
+/**
+ * Simple down-sampling algorithm for cube-map. Reconstruct mip chain up to mip level.
+ */
void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level);
void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/* eevee_render.c */
+
+/**
+ * Return true if initialized properly.
+ */
bool EEVEE_render_init(EEVEE_Data *vedata,
struct RenderEngine *engine,
struct Depsgraph *depsgraph);
@@ -1469,6 +1562,9 @@ void EEVEE_render_modules_init(EEVEE_Data *vedata,
struct RenderEngine *engine,
struct Depsgraph *depsgraph);
void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+/**
+ * Used by light cache. in this case engine is NULL.
+ */
void EEVEE_render_cache(void *vedata,
struct Object *ob,
struct RenderEngine *engine,
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 5db0ca70dc9..9e7a67060da 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -46,7 +46,6 @@
#include "eevee_private.h"
-/* Return true if init properly. */
bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph)
{
EEVEE_Data *vedata = (EEVEE_Data *)ved;
@@ -194,7 +193,6 @@ void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_cryptomatte_cache_init(sldata, vedata);
}
-/* Used by light cache. in this case engine is NULL. */
void EEVEE_render_cache(void *vedata,
struct Object *ob,
struct RenderEngine *engine,
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
index aa42deb13fa..3ebfc8a8f0f 100644
--- a/source/blender/draw/engines/eevee/eevee_renderpasses.c
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -75,8 +75,6 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata)
return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0;
}
-/* Calculate the hash for an AOV. The least significant bit is used to store the AOV
- * type the rest of the bits are used for the name hash. */
int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov)
{
int hash = BLI_hash_string(aov->name) << 1;
@@ -257,15 +255,6 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
}
}
-/* Post-process data to construct a specific render-pass
- *
- * This method will create a shading group to perform the post-processing for the given
- * `renderpass_type`. The post-processing will be done and the result will be stored in the
- * `vedata->txl->renderpass` texture.
- *
- * Only invoke this function for passes that need post-processing.
- *
- * After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`. */
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
EEVEE_Data *vedata,
eViewLayerEEVEEPassType renderpass_type,
diff --git a/source/blender/draw/engines/eevee/eevee_sampling.c b/source/blender/draw/engines/eevee/eevee_sampling.c
index da4bd20106c..99d14bd2c82 100644
--- a/source/blender/draw/engines/eevee/eevee_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_sampling.c
@@ -24,12 +24,6 @@
#include "BLI_rand.h"
-/**
- * Special ball distribution:
- * Point are distributed in a way that when they are orthogonally
- * projected into any plane, the resulting distribution is (close to)
- * a uniform disc distribution.
- */
void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3])
{
double ht_point[3];
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 56ae7185b51..adede7676d5 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -830,6 +830,7 @@ struct GPUShader *EEVEE_shaders_subsurface_translucency_sh_get()
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Volumes
* \{ */
@@ -1274,7 +1275,6 @@ Material *EEVEE_material_default_error_get(void)
return e_data.error_mat;
}
-/* Configure a default nodetree with the given material. */
struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma)
{
/* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
@@ -1302,7 +1302,6 @@ struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma)
return e_data.surface.ntree;
}
-/* Configure a default nodetree with the given world. */
struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo)
{
/* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
@@ -1493,7 +1492,6 @@ static struct GPUMaterial *eevee_material_get_ex(
return mat;
}
-/* NOTE: Compilation is not deferred. */
struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options)
{
Material *def_ma = (ma && (options & VAR_MAT_VOLUME)) ? BKE_material_default_volume() :
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
index ee1a6652809..d8a40fd13cc 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -123,7 +123,6 @@ void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
-/* Make that object update shadow casting lights inside its influence bounding box. */
void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
{
EEVEE_LightsInfo *linfo = sldata->lights;
@@ -300,7 +299,6 @@ void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
-/* this refresh lights shadow buffers */
void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view)
{
EEVEE_LightsInfo *linfo = sldata->lights;
diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cube.c b/source/blender/draw/engines/eevee/eevee_shadows_cube.c
index 89caa0dd193..ed9f05df13c 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows_cube.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows_cube.c
@@ -95,7 +95,6 @@ start:
add_v3_v3(ws_sample_pos, jitter);
}
-/* Return true if sample has changed and light needs to be updated. */
bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs)
{
EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index b03172a1270..361fa2704c9 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -196,8 +196,6 @@ void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const dou
DRW_view_update_sub(effects->taa_view, viewmat, winmat);
}
-/* Update the matrices based on the current sample.
- * NOTE: `DRW_MAT_PERS` and `DRW_MAT_VIEW` needs to read the original matrices. */
void EEVEE_temporal_sampling_update_matrices(EEVEE_Data *vedata)
{
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 41d6db7f726..1061b2f91a2 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -283,7 +283,7 @@ void occlusion_eval(OcclusionData data,
bent_normal = N;
}
else {
- /* Note: using pow(visibility, 6.0) produces NaN (see T87369). */
+ /* NOTE: using pow(visibility, 6.0) produces NaN (see T87369). */
float tmp = saturate(pow6(visibility));
bent_normal = normalize(mix(bent_normal, N, tmp));
}
@@ -337,7 +337,7 @@ float diffuse_occlusion(
* radius1 : First cap’s radius (arc length in radians)
* radius2 : Second caps’ radius (in radians)
* dist : Distance between caps (radians between centers of caps)
- * Note: Result is divided by pi to save one multiply.
+ * NOTE: Result is divided by pi to save one multiply.
*/
float spherical_cap_intersection(float radius1, float radius2, float dist)
{
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl
index 5fd00986adc..051a08d25e6 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl
@@ -50,10 +50,10 @@ float circle_to_polygon_angle(float sides_count, float theta)
float ratio = (local_theta - halfside_angle) / halfside_angle;
float halfside_len = polygon_sides_length(sides_count) * 0.5;
- float oposite = ratio * halfside_len;
+ float opposite = ratio * halfside_len;
/* NOTE: atan(y_over_x) has output range [-M_PI_2..M_PI_2]. */
- float final_local_theta = atan(oposite / adjacent);
+ float final_local_theta = atan(opposite / adjacent);
return side * side_angle + final_local_theta;
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl
index c09365cdcb4..db9ae0f7034 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl
@@ -2,8 +2,8 @@
/**
* Gather pass: Convolve foreground and background parts in separate passes.
*
- * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene color.
- * A fast gather path is taken if there is not many CoC variation inside the tile.
+ * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene
+ * color. A fast gather path is taken if there is not many CoC variation inside the tile.
*
* We sample using an octaweb sampling pattern. We randomize the kernel center and each ring
* rotation to ensure maximum coverage.
diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
index 3c49caf11a9..c54621f123d 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
@@ -24,7 +24,7 @@ out vec4 FragColor;
*/
vec3 clip_to_aabb(vec3 color, vec3 minimum, vec3 maximum, vec3 average)
{
- /* note: only clips towards aabb center (but fast!) */
+ /* NOTE: only clips towards aabb center (but fast!) */
vec3 center = 0.5 * (maximum + minimum);
vec3 extents = 0.5 * (maximum - minimum);
vec3 dist = color - center;
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index cc548a53a8e..1d899c3935b 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -88,6 +88,8 @@ typedef struct EXTERNAL_Data {
EXTERNAL_TextureList *txl;
EXTERNAL_PassList *psl;
EXTERNAL_StorageList *stl;
+ void *instance_data;
+
char info[GPU_INFO_SIZE];
} EXTERNAL_Data;
@@ -451,6 +453,7 @@ DrawEngineType draw_engine_external_type = {
&external_data_size,
&external_engine_init,
&external_engine_free,
+ NULL, /* instance_free */
&external_cache_init,
&external_cache_populate,
&external_cache_finish,
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index 4636b9e949a..8aba1090b58 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -176,11 +176,6 @@ static MaterialGPencilStyle *gpencil_viewport_material_overrides(
return gp_style;
}
-/**
- * Creates a linked list of material pool containing all materials assigned for a given object.
- * We merge the material pools together if object does not contain a huge amount of materials.
- * Also return an offset to the first material of the object in the ubo.
- */
GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs)
{
GPENCIL_MaterialPool *matpool = pd->last_material_pool;
@@ -429,9 +424,6 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob)
}
}
-/**
- * Creates a single pool containing all lights assigned (light linked) for a given object.
- */
GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *UNUSED(ob))
{
GPENCIL_LightPool *lightpool = pd->last_light_pool;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 50e32040522..9bc340a2786 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -990,6 +990,7 @@ DrawEngineType draw_engine_gpencil_type = {
&GPENCIL_data_size,
&GPENCIL_engine_init,
&GPENCIL_engine_free,
+ NULL, /* instance_free */
&GPENCIL_cache_init,
&GPENCIL_cache_populate,
&GPENCIL_cache_finish,
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 328e60cf60b..29a9c0211be 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -392,6 +392,11 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
GPENCIL_tObject *tgp_ob);
GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number);
+/**
+ * Creates a linked list of material pool containing all materials assigned for a given object.
+ * We merge the material pools together if object does not contain a huge amount of materials.
+ * Also return an offset to the first material of the object in the UBO.
+ */
GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs);
void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
int mat_id,
@@ -402,6 +407,9 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]);
void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob);
GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd);
+/**
+ * Creates a single pool containing all lights assigned (light linked) for a given object.
+ */
GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *ob);
/* effects */
@@ -436,6 +444,10 @@ void GPENCIL_cache_finish(void *vedata);
void GPENCIL_draw_scene(void *vedata);
/* render */
+
+/**
+ * Initialize render data.
+ */
void GPENCIL_render_init(struct GPENCIL_Data *ved,
struct RenderEngine *engine,
struct RenderLayer *render_layer,
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index b597a786e86..26a14c433b3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -33,7 +33,6 @@
#include "gpencil_engine.h"
-/* init render data */
void GPENCIL_render_init(GPENCIL_Data *vedata,
RenderEngine *engine,
struct RenderLayer *render_layer,
diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode_image_space.hh
index d81b0971982..26f4bc28106 100644
--- a/source/blender/draw/engines/image/image_drawing_mode.hh
+++ b/source/blender/draw/engines/image/image_drawing_mode_image_space.hh
@@ -26,7 +26,7 @@
namespace blender::draw::image_engine {
-class DefaultDrawingMode : public AbstractDrawingMode {
+class ImageSpaceDrawingMode : public AbstractDrawingMode {
private:
DRWPass *create_image_pass() const
{
@@ -50,19 +50,13 @@ class DefaultDrawingMode : public AbstractDrawingMode {
GPUBatch *geom = DRW_cache_quad_get();
- const bool is_tiled_texture = image && image->source == IMA_SRC_TILED;
- if (is_tiled_texture) {
- const float translate_x = image_mat[3][0];
- const float translate_y = image_mat[3][1];
- LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
- const int tile_x = ((tile->tile_number - 1001) % 10);
- const int tile_y = ((tile->tile_number - 1001) / 10);
- image_mat[3][0] = (float)tile_x + translate_x;
- image_mat[3][1] = (float)tile_y + translate_y;
- DRW_shgroup_call_obmat(grp, geom, image_mat);
- }
- }
- else {
+ const float translate_x = image_mat[3][0];
+ const float translate_y = image_mat[3][1];
+ LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) {
+ const int tile_x = ((tile->tile_number - 1001) % 10);
+ const int tile_y = ((tile->tile_number - 1001) / 10);
+ image_mat[3][0] = (float)tile_x + translate_x;
+ image_mat[3][1] = (float)tile_y + translate_y;
DRW_shgroup_call_obmat(grp, geom, image_mat);
}
}
diff --git a/source/blender/draw/engines/image/image_engine.cc b/source/blender/draw/engines/image/image_engine.cc
index 491fbec978b..be5946f34eb 100644
--- a/source/blender/draw/engines/image/image_engine.cc
+++ b/source/blender/draw/engines/image/image_engine.cc
@@ -41,7 +41,7 @@
#include "GPU_batch.h"
-#include "image_drawing_mode.hh"
+#include "image_drawing_mode_image_space.hh"
#include "image_engine.h"
#include "image_private.hh"
#include "image_space_image.hh"
@@ -63,12 +63,18 @@ static std::unique_ptr<AbstractSpaceAccessor> space_accessor_from_context(
return nullptr;
}
+template<
+ /** \brief Drawing mode to use.
+ *
+ * Useful during development to switch between drawing implementations.
+ */
+ typename DrawingMode = ImageSpaceDrawingMode>
class ImageEngine {
private:
const DRWContextState *draw_ctx;
IMAGE_Data *vedata;
std::unique_ptr<AbstractSpaceAccessor> space;
- DefaultDrawingMode drawing_mode;
+ DrawingMode drawing_mode;
public:
ImageEngine(const DRWContextState *draw_ctx, IMAGE_Data *vedata)
@@ -185,6 +191,7 @@ DrawEngineType draw_engine_image_type = {
&IMAGE_data_size, /* vedata_size */
&IMAGE_engine_init, /* engine_init */
&IMAGE_engine_free, /* engine_free */
+ nullptr, /* instance_free */
&IMAGE_cache_init, /* cache_init */
&IMAGE_cache_populate, /* cache_populate */
nullptr, /* cache_finish */
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 1da682ff01b..2345a110134 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -26,6 +26,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
@@ -39,6 +40,7 @@
#include "BKE_armature.h"
#include "BKE_deform.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -52,6 +54,8 @@
#include "overlay_private.h"
+#include "draw_cache_impl.h"
+
#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var))
#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag))
@@ -100,9 +104,6 @@ typedef struct ArmatureDrawContext {
const ThemeWireColor *bcolor; /* pchan color */
} ArmatureDrawContext;
-/**
- * Return true if armature should be handled by the pose mode engine.
- */
bool OVERLAY_armature_is_pose_mode(Object *ob, const DRWContextState *draw_ctx)
{
Object *active_ob = draw_ctx->obact;
@@ -535,13 +536,22 @@ static void drw_shgroup_bone_custom_solid(ArmatureDrawContext *ctx,
const float outline_color[4],
Object *custom)
{
+ /* The custom object is not an evaluated object, so its object->data field hasn't been replaced
+ * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any
+ * other data type, but supporting all evaluated geometry components would require a much larger
+ * refactor of this area. */
+ Mesh *mesh = BKE_object_get_evaluated_mesh(custom);
+ if (mesh == NULL) {
+ return;
+ }
+
/* TODO(fclem): arg... less than ideal but we never iter on this object
* to assure batch cache is valid. */
- drw_batch_cache_validate(custom);
+ DRW_mesh_batch_cache_validate(mesh);
- struct GPUBatch *surf = DRW_cache_object_surface_get(custom);
- struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
- struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom);
+ struct GPUBatch *surf = DRW_mesh_batch_cache_get_surface(mesh);
+ struct GPUBatch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, NULL);
+ struct GPUBatch *ledges = DRW_mesh_batch_cache_get_loose_edges(mesh);
BoneInstanceData inst_data;
DRWCallBuffer *buf;
@@ -578,12 +588,16 @@ static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx,
const float color[4],
Object *custom)
{
+ /* See comments in #drw_shgroup_bone_custom_solid. */
+ Mesh *mesh = BKE_object_get_evaluated_mesh(custom);
+ if (mesh == NULL) {
+ return;
+ }
/* TODO(fclem): arg... less than ideal but we never iter on this object
* to assure batch cache is valid. */
- drw_batch_cache_validate(custom);
-
- struct GPUBatch *geom = DRW_cache_object_all_edges_get(custom);
+ DRW_mesh_batch_cache_validate(mesh);
+ struct GPUBatch *geom = DRW_mesh_batch_cache_get_all_edges(mesh);
if (geom) {
DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, geom);
BoneInstanceData inst_data;
@@ -1906,6 +1920,7 @@ static void draw_bone_name(ArmatureDrawContext *ctx,
DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
color);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2314,3 +2329,5 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata)
DRW_draw_pass(psl->armature_ps[1]);
}
}
+
+/** \} */
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index 2bdceb5f3db..12db2bd02cf 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -703,6 +703,7 @@ DrawEngineType draw_engine_overlay_type = {
&overlay_data_size,
&OVERLAY_engine_init,
&OVERLAY_engine_free,
+ NULL, /* instance_free */
&OVERLAY_cache_init,
&OVERLAY_cache_populate,
&OVERLAY_cache_finish,
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
index 2e9a9bc5c64..0608725d342 100644
--- a/source/blender/draw/engines/overlay/overlay_image.c
+++ b/source/blender/draw/engines/overlay/overlay_image.c
@@ -462,8 +462,6 @@ void OVERLAY_image_cache_finish(OVERLAY_Data *vedata)
DRW_pass_sort_shgroup_z(psl->image_empties_back_ps);
}
-/* This function draws images that needs the view transform applied.
- * It draws these images directly into the scene color buffer. */
void OVERLAY_image_scene_background_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index def278f98df..8e7c3094062 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -510,6 +510,9 @@ void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata);
void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata);
void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata);
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
bool OVERLAY_armature_is_pose_mode(Object *ob, const struct DRWContextState *draw_ctx);
void OVERLAY_armature_cache_init(OVERLAY_Data *vedata);
void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
@@ -631,6 +634,10 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_image_cache_finish(OVERLAY_Data *vedata);
void OVERLAY_image_draw(OVERLAY_Data *vedata);
void OVERLAY_image_background_draw(OVERLAY_Data *vedata);
+/**
+ * This function draws images that needs the view transform applied.
+ * It draws these images directly into the scene color buffer.
+ */
void OVERLAY_image_scene_background_draw(OVERLAY_Data *vedata);
void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata);
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index fde376beeb2..449130c4c5b 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -237,7 +237,21 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
if (dupli && !init_dupli) {
if (dupli->wire_shgrp && dupli->wire_geom) {
if (dupli->base_flag == ob->base_flag) {
- DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
+ /* Check for the special cases used below, assign specific theme colors to the shaders. */
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ if (dupli->wire_shgrp == cb->extra_loose_points) {
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->obmat, color);
+ }
+ else if (dupli->wire_shgrp == cb->extra_wire) {
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ OVERLAY_extra_wire(cb, dupli->wire_geom, ob->obmat, color);
+ }
+ else {
+ DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
+ }
return;
}
}
@@ -268,6 +282,9 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
}
}
+ DRWShadingGroup *shgrp = NULL;
+ struct GPUBatch *geom = NULL;
+
/* Don't do that in edit Mesh mode, unless there is a modifier preview. */
if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) {
const bool is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != NULL);
@@ -275,8 +292,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
!DRW_state_is_image_render();
const bool use_coloring = (use_wire && !is_edit_mode && !is_sculpt_mode &&
!has_edit_mesh_cage);
- DRWShadingGroup *shgrp = NULL;
- struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob);
+ geom = DRW_cache_object_face_wireframe_get(ob);
if (geom || use_sculpt_pbvh) {
if (use_sculpt_pbvh) {
@@ -300,11 +316,6 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
DRW_shgroup_call(shgrp, geom, ob);
}
}
-
- if (dupli) {
- dupli->wire_shgrp = shgrp;
- dupli->wire_geom = geom;
- }
}
else if (is_mesh && (!is_edit_mode || has_edit_mesh_cage)) {
OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
@@ -313,18 +324,25 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
/* Draw loose geometry. */
if (is_mesh_verts_only) {
- struct GPUBatch *geom = DRW_cache_mesh_all_verts_get(ob);
+ geom = DRW_cache_mesh_all_verts_get(ob);
if (geom) {
OVERLAY_extra_loose_points(cb, geom, ob->obmat, color);
+ shgrp = cb->extra_loose_points;
}
}
else {
- struct GPUBatch *geom = DRW_cache_mesh_loose_edges_get(ob);
+ geom = DRW_cache_mesh_loose_edges_get(ob);
if (geom) {
OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+ shgrp = cb->extra_wire;
}
}
}
+
+ if (dupli) {
+ dupli->wire_shgrp = shgrp;
+ dupli->wire_geom = geom;
+ }
}
void OVERLAY_wireframe_draw(OVERLAY_Data *data)
diff --git a/source/blender/draw/engines/select/select_debug_engine.c b/source/blender/draw/engines/select/select_debug_engine.c
index e9437c5ab92..f66eabdcdcc 100644
--- a/source/blender/draw/engines/select/select_debug_engine.c
+++ b/source/blender/draw/engines/select/select_debug_engine.c
@@ -120,6 +120,7 @@ DrawEngineType draw_engine_debug_select_type = {
&select_debug_data_size,
&select_debug_engine_init,
&select_debug_engine_free,
+ NULL, /* instance_free */
NULL,
NULL,
NULL,
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 20edd78597b..7f9645013ce 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -363,6 +363,7 @@ DrawEngineType draw_engine_select_type = {
&select_data_size,
&select_engine_init,
&select_engine_free,
+ NULL, /* instance_free */
&select_cache_init,
&select_cache_populate,
NULL,
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
index fd4d00d96dd..3f113fd4b2e 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl
@@ -11,7 +11,7 @@
layout(location = 0) out vec4 transparentAccum;
layout(location = 1) out vec4 revealageAccum;
-/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */
+/* NOTE: Blending will be skipped on objectId because output is a non-normalized integer buffer. */
layout(location = 2) out uint objectId;
/* Special function only to be used with calculate_transparent_weight(). */
diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
index 8206add7412..f4014fac41f 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
@@ -371,7 +371,6 @@ void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata)
}
}
-/* Return true if render is not cached. */
bool workbench_antialiasing_setup(WORKBENCH_Data *vedata)
{
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index 4706aeb4477..5bc2c53e253 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -473,8 +473,6 @@ void workbench_cache_finish(void *ved)
}
}
-/* Used by viewport rendering & final rendering.
- * Do one render loop iteration (i.e: One TAA sample). */
void workbench_draw_sample(void *ved)
{
WORKBENCH_Data *vedata = ved;
@@ -629,6 +627,7 @@ DrawEngineType draw_engine_workbench = {
&workbench_data_size,
&workbench_engine_init,
&workbench_engine_free,
+ NULL, /* instance_free */
&workbench_cache_init,
&workbench_cache_populate,
&workbench_cache_finish,
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index aaa1a5a6ff6..d70633eaa85 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -244,7 +244,6 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
}
}
-/* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
int mat_nr,
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index e17bd7d9956..42c873c7691 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -414,6 +414,10 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data);
/* workbench_transparent.c */
void workbench_transparent_engine_init(WORKBENCH_Data *data);
void workbench_transparent_cache_init(WORKBENCH_Data *data);
+/**
+ * Redraw the transparent passes but with depth test
+ * to output correct outline IDs and depth.
+ */
void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data);
/* workbench_shadow.c */
@@ -463,6 +467,9 @@ int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd);
void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata);
void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata);
void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata);
+/**
+ * Return true if render is not cached.
+ */
bool workbench_antialiasing_setup(WORKBENCH_Data *vedata);
void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata);
@@ -491,6 +498,9 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
eV3DShadingColorType color_type,
eWORKBENCH_DataType datatype,
bool *r_transp);
+/**
+ * If `ima` is null, search appropriate image node but will fallback to purple texture otherwise.
+ */
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
int mat_nr,
@@ -535,6 +545,10 @@ void workbench_engine_init(void *ved);
void workbench_cache_init(void *ved);
void workbench_cache_populate(void *ved, Object *ob);
void workbench_cache_finish(void *ved);
+/**
+ * Used by viewport rendering & final rendering.
+ * Do one render loop iteration (i.e: One TAA sample).
+ */
void workbench_draw_sample(void *ved);
void workbench_draw_finish(void *ved);
diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c
index ad855cb284c..3be005b43d0 100644
--- a/source/blender/draw/engines/workbench/workbench_transparent.c
+++ b/source/blender/draw/engines/workbench/workbench_transparent.c
@@ -149,8 +149,6 @@ void workbench_transparent_cache_init(WORKBENCH_Data *vedata)
}
}
-/* Redraw the transparent passes but with depth test
- * to output correct outline IDs and depth. */
void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data)
{
WORKBENCH_PrivateData *wpd = data->stl->wpd;
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index c1cab931f6a..961aed3f284 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -121,6 +121,8 @@ typedef struct DrawEngineType {
void (*engine_init)(void *vedata);
void (*engine_free)(void);
+ void (*instance_free)(void *instance_data);
+
void (*cache_init)(void *vedata);
void (*cache_populate)(void *vedata, struct Object *ob);
void (*cache_finish)(void *vedata);
@@ -145,9 +147,11 @@ typedef enum {
DRW_TEX_MIPMAP = (1 << 3),
} DRWTextureFlag;
-/* Textures from DRW_texture_pool_query_* have the options
- * DRW_TEX_FILTER for color float textures, and no options
- * for depth textures and integer textures. */
+/**
+ * Textures from `DRW_texture_pool_query_*` have the options
+ * #DRW_TEX_FILTER for color float textures, and no options
+ * for depth textures and integer textures.
+ */
struct GPUTexture *DRW_texture_pool_query_2d(int w,
int h,
eGPUTextureFormat format,
@@ -286,11 +290,17 @@ void DRW_shader_free(struct GPUShader *shader);
DRWShaderLibrary *DRW_shader_library_create(void);
-/* Warning: Each library must be added after all its dependencies. */
+/**
+ * \warning Each library must be added after all its dependencies.
+ */
void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name);
#define DRW_SHADER_LIB_ADD(lib, lib_name) \
DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl")
+/**
+ * \return an allocN'ed string containing the shader code with its dependencies prepended.
+ * Caller must free the string with #MEM_freeN after use.
+ */
char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib,
const char *shader_code);
@@ -304,11 +314,14 @@ void DRW_shader_library_free(DRWShaderLibrary *lib);
} while (0)
/* Batches */
-/* DRWState is a bitmask that stores the current render state and the desired render state. Based
+
+/**
+ * DRWState is a bit-mask that stores the current render state and the desired render state. Based
* on the differences the minimum state changes can be invoked to setup the desired render state.
*
* The Write Stencil, Stencil test, Depth test and Blend state options are mutual exclusive
- * therefore they aren't ordered as a bit mask. */
+ * therefore they aren't ordered as a bit mask.
+ */
typedef enum {
/** Write mask */
DRW_STATE_WRITE_DEPTH = (1 << 0),
@@ -406,7 +419,9 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material);
-/* return final visibility */
+/**
+ * Return final visibility.
+ */
typedef bool(DRWCallVisibilityFn)(bool vis_in, void *user_data);
void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
@@ -416,11 +431,15 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
bool bypass_culling,
void *user_data);
-/* If ob is NULL, unit modelmatrix is assumed and culling is bypassed. */
+/**
+ * If ob is NULL, unit modelmatrix is assumed and culling is bypassed.
+ */
#define DRW_shgroup_call(shgroup, geom, ob) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, false, NULL)
-/* Same as DRW_shgroup_call but override the obmat. Not culled. */
+/**
+ * Same as #DRW_shgroup_call but override the `obmat`. Not culled.
+ */
#define DRW_shgroup_call_obmat(shgroup, geom, obmat) \
DRW_shgroup_call_ex(shgroup, NULL, obmat, geom, false, NULL)
@@ -429,12 +448,17 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
#define DRW_shgroup_call_with_callback(shgroup, geom, ob, user_data) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, false, user_data)
-/* Same as DRW_shgroup_call but bypass culling even if ob is not NULL. */
+/**
+ * Same as #DRW_shgroup_call but bypass culling even if ob is not NULL.
+ */
#define DRW_shgroup_call_no_cull(shgroup, geom, ob) \
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, true, NULL)
void DRW_shgroup_call_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct);
+/**
+ * A count of 0 instance will use the default number of instance in the batch.
+ */
void DRW_shgroup_call_instance_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct);
@@ -445,12 +469,17 @@ void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_count);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_count);
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count);
-/* Warning: Only use with Shaders that have IN_PLACE_INSTANCES defined. */
+/**
+ * \warning Only use with Shaders that have `IN_PLACE_INSTANCES` defined.
+ * TODO: Should be removed.
+ */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count);
-/* Warning: Only use with Shaders that have INSTANCED_ATTR defined. */
+/**
+ * \warning Only use with Shaders that have INSTANCED_ATTR defined.
+ */
void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
@@ -475,13 +504,20 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint
DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \
} while (0)
-/* Can only be called during iter phase. */
+/**
+ * Can only be called during iteration phase.
+ */
uint32_t DRW_object_resource_id_get(Object *ob);
+/**
+ * State is added to #Pass.state while drawing.
+ * Use to temporarily enable draw options.
+ */
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
-/* Reminders:
+/**
+ * Reminders:
* - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
* stencil_value being the value stored in the stencil buffer.
* - (write-mask & reference) is what gets written if the test condition is fulfilled.
@@ -490,10 +526,14 @@ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
uint write_mask,
uint reference,
uint compare_mask);
-/* TODO: remove this function. Obsolete version. mask is actually reference value. */
+/**
+ * TODO: remove this function. Obsolete version. mask is actually reference value.
+ */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
-/* Issue a clear command. */
+/**
+ * Issue a clear command.
+ */
void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
eGPUFrameBufferBits channels,
uchar r,
@@ -539,7 +579,6 @@ void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup,
const char *name,
const float *value,
int arraysize);
-/* Boolean are expected to be 4bytes longs for opengl! */
void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
const char *name,
const int *value,
@@ -562,10 +601,14 @@ void DRW_shgroup_uniform_ivec4(DRWShadingGroup *shgroup,
int arraysize);
void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float (*value)[3]);
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]);
-/* Only to be used when image load store is supported (GPU_shader_image_load_store_support()). */
+/**
+ * Only to be used when image load store is supported (#GPU_shader_image_load_store_support()).
+ */
void DRW_shgroup_uniform_image(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex);
void DRW_shgroup_uniform_image_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex);
+
/* Store value instead of referencing it. */
+
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgroup, const char *name, const int *value);
void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgroup, const char *name, const int *value);
@@ -585,14 +628,29 @@ void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup,
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
-/* Passes */
+/* Passes. */
+
DRWPass *DRW_pass_create(const char *name, DRWState state);
+/**
+ * Create an instance of the original pass that will execute the same drawcalls but with its own
+ * #DRWState.
+ */
DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state);
+/**
+ * Link two passes so that they are both rendered if the first one is being drawn.
+ */
void DRW_pass_link(DRWPass *first, DRWPass *second);
void DRW_pass_foreach_shgroup(DRWPass *pass,
void (*callback)(void *userData, DRWShadingGroup *shgroup),
void *userData);
+/**
+ * Sort Shading groups by decreasing Z of their first draw call.
+ * This is useful for order dependent effect such as alpha-blending.
+ */
void DRW_pass_sort_shgroup_z(DRWPass *pass);
+/**
+ * Reverse Shading group submission order.
+ */
void DRW_pass_sort_shgroup_reverse(DRWPass *pass);
bool DRW_pass_is_empty(DRWPass *pass);
@@ -601,56 +659,113 @@ bool DRW_pass_is_empty(DRWPass *pass);
#define DRW_PASS_INSTANCE_CREATE(pass, original, state) \
(pass = DRW_pass_create_instance(#pass, (original), state))
-/* Views */
+/* Views. */
+
+/**
+ * Create a view with culling.
+ */
DRWView *DRW_view_create(const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
const float (*culling_winmat)[4],
DRWCallVisibilityFn *visibility_fn);
+/**
+ * Create a view with culling done by another view.
+ */
DRWView *DRW_view_create_sub(const DRWView *parent_view,
const float viewmat[4][4],
const float winmat[4][4]);
+/**
+ * Update matrices of a view created with #DRW_view_create.
+ */
void DRW_view_update(DRWView *view,
const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
const float (*culling_winmat)[4]);
+/**
+ * Update matrices of a view created with #DRW_view_create_sub.
+ */
void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4]);
+/**
+ * \return default view if it is a viewport render.
+ */
const DRWView *DRW_view_default_get(void);
+/**
+ * MUST only be called once per render and only in render mode. Sets default view.
+ */
void DRW_view_default_set(DRWView *view);
+/**
+ * \warning Only use in render AND only if you are going to set view_default again.
+ */
void DRW_view_reset(void);
+/**
+ * Set active view for rendering.
+ */
void DRW_view_set_active(DRWView *view);
const DRWView *DRW_view_get_active(void);
+/**
+ * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
+ * and if the shaders have support for it (see usage of gl_ClipDistance).
+ * \note planes must be in world space.
+ */
void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len);
void DRW_view_camtexco_set(DRWView *view, float texco[4]);
/* For all getters, if view is NULL, default view is assumed. */
+
void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse);
void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse);
+/**
+ * \return world space frustum corners.
+ */
void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners);
+/**
+ * \return world space frustum sides as planes.
+ * See #draw_frustum_culling_planes_calc() for the plane order.
+ */
void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4]);
-/* These are in view-space, so negative if in perspective.
- * Extract near and far clip distance from the projection matrix. */
+/**
+ * These are in view-space, so negative if in perspective.
+ * Extract near and far clip distance from the projection matrix.
+ */
float DRW_view_near_distance_get(const DRWView *view);
float DRW_view_far_distance_get(const DRWView *view);
bool DRW_view_is_persp_get(const DRWView *view);
/* Culling, return true if object is inside view frustum. */
+
+/**
+ * \return True if the given BoundSphere intersect the current view frustum.
+ * bsphere must be in world space.
+ */
bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere);
+/**
+ * \return True if the given BoundBox intersect the current view frustum.
+ * bbox must be in world space.
+ */
bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox);
+/**
+ * \return True if the view frustum is inside or intersect the given plane.
+ * plane must be in world space.
+ */
bool DRW_culling_plane_test(const DRWView *view, const float plane[4]);
+/**
+ * Return True if the given box intersect the current view frustum.
+ * This function will have to be replaced when world space bb per objects is implemented.
+ */
bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3]);
void DRW_culling_frustum_corners_get(const DRWView *view, BoundBox *corners);
void DRW_culling_frustum_planes_get(const DRWView *view, float planes[6][4]);
-/* Viewport */
+/* Viewport. */
const float *DRW_viewport_size_get(void);
const float *DRW_viewport_invert_size_get(void);
@@ -670,18 +785,35 @@ void DRW_render_object_iter(void *vedata,
struct Object *ob,
struct RenderEngine *engine,
struct Depsgraph *depsgraph));
+/**
+ * Must run after all instance datas have been added.
+ */
void DRW_render_instance_buffer_finish(void);
+/**
+ * \warning Changing frame might free the #ViewLayerEngineData.
+ */
void DRW_render_set_time(struct RenderEngine *engine,
struct Depsgraph *depsgraph,
int frame,
float subframe);
+/**
+ * \warning only use for custom pipeline. 99% of the time, you don't want to use this.
+ */
void DRW_render_viewport_size_set(const int size[2]);
+/**
+ * Assume a valid GL context is bound (and that the gl_context_mutex has been acquired).
+ * This function only setup DST and execute the given function.
+ * \warning similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl).
+ */
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
void (*callback)(void *vedata, void *user_data),
void *user_data);
+/**
+ * Used when the render engine want to redo another cache populate inside the same render frame.
+ */
void DRW_cache_restart(void);
/* ViewLayers */
@@ -699,11 +831,26 @@ DrawData *DRW_drawdata_ensure(ID *id,
size_t size,
DrawDataInitCb init_cb,
DrawDataFreeCb free_cb);
+/**
+ * Return NULL if not a dupli or a pointer of pointer to the engine data.
+ */
void **DRW_duplidata_get(void *vedata);
-/* Settings */
+/* Settings. */
+
bool DRW_object_is_renderable(const struct Object *ob);
+/**
+ * Does `ob` needs to be rendered in edit mode.
+ *
+ * When using duplicate linked meshes, objects that are not in edit-mode will be drawn as
+ * it is in edit mode, when another object with the same mesh is in edit mode.
+ * This will not be the case when one of the objects are influenced by modifiers.
+ */
bool DRW_object_is_in_edit_mode(const struct Object *ob);
+/**
+ * Return whether this object is visible depending if
+ * we are rendering or drawing in the viewport.
+ */
int DRW_object_visibility_in_active_context(const struct Object *ob);
bool DRW_object_is_flat_normal(const struct Object *ob);
bool DRW_object_use_hide_faces(const struct Object *ob);
@@ -715,31 +862,76 @@ struct Object *DRW_object_get_dupli_parent(const struct Object *ob);
struct DupliObject *DRW_object_get_dupli(const struct Object *ob);
/* Draw commands */
+
void DRW_draw_pass(DRWPass *pass);
+/**
+ * Draw only a subset of shgroups. Used in special situations as grease pencil strokes.
+ */
void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group);
void DRW_draw_callbacks_pre_scene(void);
void DRW_draw_callbacks_post_scene(void);
+/**
+ * Reset state to not interfere with other UI draw-call.
+ */
void DRW_state_reset_ex(DRWState state);
void DRW_state_reset(void);
+/**
+ * Use with care, intended so selection code can override passes depth settings,
+ * which is important for selection to work properly.
+ *
+ * Should be set in main draw loop, cleared afterwards
+ */
void DRW_state_lock(DRWState state);
-/* Selection */
+/* Selection. */
+
void DRW_select_load_id(uint id);
-/* Draw State */
+/* Draw State. */
+
+/**
+ * When false, drawing doesn't output to a pixel buffer
+ * eg: Occlusion queries, or when we have setup a context to draw in already.
+ */
bool DRW_state_is_fbo(void);
+/**
+ * For when engines need to know if this is drawing for selection or not.
+ */
bool DRW_state_is_select(void);
bool DRW_state_is_material_select(void);
bool DRW_state_is_depth(void);
+/**
+ * Whether we are rendering for an image
+ */
bool DRW_state_is_image_render(void);
+/**
+ * Whether we are rendering only the render engine,
+ * or if we should also render the mode engines.
+ */
bool DRW_state_is_scene_render(void);
+/**
+ * Whether we are rendering simple opengl render
+ */
bool DRW_state_is_opengl_render(void);
bool DRW_state_is_playback(void);
+/**
+ * Is the user navigating the region.
+ */
bool DRW_state_is_navigating(void);
+/**
+ * Should text draw in this mode?
+ */
bool DRW_state_show_text(void);
+/**
+ * Should draw support elements
+ * Objects center, selection outline, probe data, ...
+ */
bool DRW_state_draw_support(void);
+/**
+ * Whether we should render the background
+ */
bool DRW_state_draw_background(void);
/* Avoid too many lookups while drawing */
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 7b66026f7ad..03fb3b92277 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -47,6 +47,10 @@
#include "draw_cache_impl.h"
#include "draw_manager.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Defines
+ * \{ */
+
#define VCLASS_LIGHT_AREA_SHAPE (1 << 0)
#define VCLASS_LIGHT_SPOT_SHAPE (1 << 1)
#define VCLASS_LIGHT_SPOT_BLEND (1 << 2)
@@ -77,6 +81,12 @@
#define DRW_SPHERE_SHAPE_LATITUDE_HIGH 80
#define DRW_SPHERE_SHAPE_LONGITUDE_HIGH 60
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct Vert {
float pos[3];
int class;
@@ -163,6 +173,8 @@ void DRW_shape_cache_free(void)
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Procedural Batches
* \{ */
@@ -354,7 +366,6 @@ static GPUVertBuf *sphere_wire_vbo(const float rad, int flag)
}
/* Quads */
-/* Use this one for rendering fullscreen passes. For 3D objects use DRW_cache_quad_get(). */
GPUBatch *DRW_cache_fullscreen_quad_get(void)
{
if (!SHC.drw_fullscreen_quad) {
@@ -388,7 +399,6 @@ GPUBatch *DRW_cache_fullscreen_quad_get(void)
return SHC.drw_fullscreen_quad;
}
-/* Just a regular quad with 4 vertices. */
GPUBatch *DRW_cache_quad_get(void)
{
if (!SHC.drw_quad) {
@@ -409,7 +419,6 @@ GPUBatch *DRW_cache_quad_get(void)
return SHC.drw_quad;
}
-/* Just a regular quad with 4 vertices - wires. */
GPUBatch *DRW_cache_quad_wires_get(void)
{
if (!SHC.drw_quad_wires) {
@@ -430,7 +439,6 @@ GPUBatch *DRW_cache_quad_wires_get(void)
return SHC.drw_quad_wires;
}
-/* Grid */
GPUBatch *DRW_cache_grid_get(void)
{
if (!SHC.drw_grid) {
@@ -769,6 +777,8 @@ GPUBatch *DRW_cache_normal_arrow_get(void)
return SHC.drw_normal_arrow;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Dummy VBO's
*
@@ -911,7 +921,6 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
}
}
-/* Returns the vertbuf used by shaded surface batch. */
GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob)
{
Mesh *me = BKE_object_get_evaluated_mesh(ob);
@@ -1260,7 +1269,6 @@ GPUBatch *DRW_cache_empty_capsule_cap_get(void)
#undef NSEGMENTS
}
-/* Force Field */
GPUBatch *DRW_cache_field_wind_get(void)
{
#define CIRCLE_RESOL 32
@@ -1336,7 +1344,6 @@ GPUBatch *DRW_cache_field_vortex_get(void)
#undef SPIRAL_RESOL
}
-/* Screen-aligned circle. */
GPUBatch *DRW_cache_field_curve_get(void)
{
#define CIRCLE_RESOL 32
@@ -1425,7 +1432,6 @@ GPUBatch *DRW_cache_field_cone_limit_get(void)
#undef CIRCLE_RESOL
}
-/* Screen-aligned dashed circle */
GPUBatch *DRW_cache_field_sphere_limit_get(void)
{
#define CIRCLE_RESOL 32
@@ -2872,7 +2878,6 @@ GPUBatch *DRW_cache_mesh_surface_edges_get(Object *ob)
return DRW_mesh_batch_cache_get_surface_edges(ob->data);
}
-/* Return list of batches with length equal to max(1, totcol). */
GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
@@ -2881,7 +2886,6 @@ GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
return DRW_mesh_batch_cache_get_surface_shaded(ob->data, gpumat_array, gpumat_array_len);
}
-/* Return list of batches with length equal to max(1, totcol). */
GPUBatch **DRW_cache_mesh_surface_texpaint_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
@@ -3078,7 +3082,6 @@ GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob)
return NULL;
}
-/* Return list of batches */
GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
@@ -3148,6 +3151,8 @@ GPUBatch *DRW_cache_pointcloud_surface_get(Object *object)
return DRW_pointcloud_batch_cache_get_surface(object);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Volume
* \{ */
@@ -3275,7 +3280,6 @@ GPUBatch *DRW_cache_particles_get_prim(int type)
return NULL;
}
-/* 3D cursor */
GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
{
GPUBatch **drw_cursor = crosshair_lines ? &SHC.drw_cursor : &SHC.drw_cursor_only_circle;
@@ -3450,6 +3454,26 @@ void drw_batch_cache_generate_requested(Object *ob)
}
}
+void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob)
+{
+ /* NOTE: Logic here is duplicated from #drw_batch_cache_generate_requested. */
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
+ draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
+ const bool is_paint_mode = ELEM(
+ mode, CTX_MODE_SCULPT, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_WEIGHT);
+
+ const bool use_hide = ((ob->type == OB_MESH) &&
+ ((is_paint_mode && (ob == draw_ctx->obact) &&
+ DRW_object_use_hide_faces(ob)) ||
+ ((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob))));
+
+ Mesh *mesh = BKE_object_get_evaluated_mesh(ob);
+ DRW_mesh_batch_cache_create_requested(DST.task_graph, ob, mesh, scene, is_paint_mode, use_hide);
+}
+
void drw_batch_cache_generate_requested_delayed(Object *ob)
{
BLI_gset_add(DST.delayed_extraction, ob);
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 5863ada2ccf..7fcd86669ec 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -36,7 +36,9 @@ struct Volume;
struct VolumeGrid;
struct bGPDstroke;
-/* Shape resolution level of detail */
+/**
+ * Shape resolution level of detail.
+ */
typedef enum eDRWLevelOfDetail {
DRW_LOD_LOW = 0,
DRW_LOD_MEDIUM = 1,
@@ -52,9 +54,15 @@ struct GPUBatch *DRW_cache_cursor_get(bool crosshair_lines);
/* Common Shapes */
struct GPUBatch *DRW_cache_groundline_get(void);
+/* Grid */
struct GPUBatch *DRW_cache_grid_get(void);
+/**
+ * Use this one for rendering full-screen passes. For 3D objects use #DRW_cache_quad_get().
+ */
struct GPUBatch *DRW_cache_fullscreen_quad_get(void);
+/* Just a regular quad with 4 vertices. */
struct GPUBatch *DRW_cache_quad_get(void);
+/* Just a regular quad with 4 vertices - wires. */
struct GPUBatch *DRW_cache_quad_wires_get(void);
struct GPUBatch *DRW_cache_cube_get(void);
struct GPUBatch *DRW_cache_normal_arrow_get(void);
@@ -62,9 +70,11 @@ struct GPUBatch *DRW_cache_normal_arrow_get(void);
struct GPUBatch *DRW_cache_sphere_get(const eDRWLevelOfDetail level_of_detail);
/* Dummy VBOs */
+
struct GPUBatch *DRW_gpencil_dummy_buffer_get(void);
/* Common Object */
+
struct GPUBatch *DRW_cache_object_all_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_object_edge_detection_get(struct Object *ob, bool *r_is_manifold);
struct GPUBatch *DRW_cache_object_surface_get(struct Object *ob);
@@ -75,6 +85,9 @@ struct GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
struct GPUBatch *DRW_cache_object_face_wireframe_get(struct Object *ob);
int DRW_cache_object_material_count_get(struct Object *ob);
+/**
+ * Returns the vertbuf used by shaded surface batch.
+ */
struct GPUVertBuf *DRW_cache_object_pos_vertbuf_get(struct Object *ob);
/* Empties */
@@ -89,15 +102,23 @@ struct GPUBatch *DRW_cache_empty_capsule_cap_get(void);
struct GPUBatch *DRW_cache_empty_capsule_body_get(void);
/* Force Field */
+
struct GPUBatch *DRW_cache_field_wind_get(void);
struct GPUBatch *DRW_cache_field_force_get(void);
struct GPUBatch *DRW_cache_field_vortex_get(void);
+
+/* Screen-aligned circle. */
+
struct GPUBatch *DRW_cache_field_curve_get(void);
struct GPUBatch *DRW_cache_field_tube_limit_get(void);
struct GPUBatch *DRW_cache_field_cone_limit_get(void);
+
+/* Screen-aligned dashed circle */
+
struct GPUBatch *DRW_cache_field_sphere_limit_get(void);
/* Lights */
+
struct GPUBatch *DRW_cache_light_point_lines_get(void);
struct GPUBatch *DRW_cache_light_sun_lines_get(void);
struct GPUBatch *DRW_cache_light_spot_lines_get(void);
@@ -106,6 +127,7 @@ struct GPUBatch *DRW_cache_light_area_square_lines_get(void);
struct GPUBatch *DRW_cache_light_spot_volume_get(void);
/* Camera */
+
struct GPUBatch *DRW_cache_camera_frame_get(void);
struct GPUBatch *DRW_cache_camera_volume_get(void);
struct GPUBatch *DRW_cache_camera_volume_wire_get(void);
@@ -114,14 +136,17 @@ struct GPUBatch *DRW_cache_camera_tria_get(void);
struct GPUBatch *DRW_cache_camera_distances_get(void);
/* Speaker */
+
struct GPUBatch *DRW_cache_speaker_get(void);
/* Probe */
+
struct GPUBatch *DRW_cache_lightprobe_cube_get(void);
struct GPUBatch *DRW_cache_lightprobe_grid_get(void);
struct GPUBatch *DRW_cache_lightprobe_planar_get(void);
/* Bones */
+
struct GPUBatch *DRW_cache_bone_octahedral_get(void);
struct GPUBatch *DRW_cache_bone_octahedral_wire_get(void);
struct GPUBatch *DRW_cache_bone_box_get(void);
@@ -136,15 +161,22 @@ struct GPUBatch *DRW_cache_bone_dof_sphere_get(void);
struct GPUBatch *DRW_cache_bone_dof_lines_get(void);
/* Meshes */
+
struct GPUBatch *DRW_cache_mesh_all_verts_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_all_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_loose_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_edge_detection_get(struct Object *ob, bool *r_is_manifold);
struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_edges_get(struct Object *ob);
+/**
+ * Return list of batches with length equal to `max(1, totcol)`.
+ */
struct GPUBatch **DRW_cache_mesh_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
+/**
+ * Return list of batches with length equal to `max(1, totcol)`.
+ */
struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_vertpaint_get(struct Object *ob);
@@ -154,19 +186,27 @@ struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob);
/* Curve */
+
struct GPUBatch *DRW_cache_curve_edge_wire_get(struct Object *ob);
+
/* edit-mode */
+
struct GPUBatch *DRW_cache_curve_edge_normal_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_edge_overlay_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_vert_overlay_get(struct Object *ob);
/* Font */
+
struct GPUBatch *DRW_cache_text_edge_wire_get(struct Object *ob);
/* Surface */
+
struct GPUBatch *DRW_cache_surf_surface_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_edge_wire_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_loose_edges_get(struct Object *ob);
+
+/* Return list of batches */
+
struct GPUBatch **DRW_cache_surf_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
@@ -174,11 +214,13 @@ struct GPUBatch *DRW_cache_surf_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_surf_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* Lattice */
+
struct GPUBatch *DRW_cache_lattice_verts_get(struct Object *ob);
struct GPUBatch *DRW_cache_lattice_wire_get(struct Object *ob, bool use_weight);
struct GPUBatch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
/* Particles */
+
struct GPUBatch *DRW_cache_particles_get_hair(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -196,6 +238,7 @@ struct GPUBatch *DRW_cache_particles_get_edit_tip_points(struct Object *object,
struct GPUBatch *DRW_cache_particles_get_prim(int type);
/* Metaball */
+
struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
@@ -204,6 +247,7 @@ struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* Hair */
+
struct GPUBatch *DRW_cache_hair_surface_get(struct Object *ob);
struct GPUBatch **DRW_cache_hair_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
@@ -212,10 +256,12 @@ struct GPUBatch *DRW_cache_hair_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_hair_edge_detection_get(struct Object *ob, bool *r_is_manifold);
/* PointCloud */
+
struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj);
struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj);
/* Volume */
+
typedef struct DRWVolumeGrid {
struct DRWVolumeGrid *next, *prev;
@@ -240,6 +286,7 @@ struct GPUBatch *DRW_cache_volume_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_volume_selection_surface_get(struct Object *ob);
/* GPencil */
+
struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra);
struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra);
@@ -252,6 +299,9 @@ struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob);
struct GPUBatch *DRW_cache_gpencil_face_wireframe_get(struct Object *ob);
struct bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(struct Object *ob);
+/**
+ * Sbuffer batches are temporary. We need to clear it after drawing.
+ */
void DRW_cache_gpencil_sbuffer_clear(struct Object *ob);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index f3b72503907..485b803310c 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -56,6 +56,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract Struct
* \{ */
+
using TaskId = int;
using TaskLen = int;
@@ -158,6 +159,7 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
/* ---------------------------------------------------------------------- */
/** \name ExtractTaskData
* \{ */
+
struct ExtractTaskData {
const MeshRenderData *mr = nullptr;
MeshBatchCache *cache = nullptr;
@@ -495,6 +497,7 @@ static struct TaskNode *extract_task_node_create(struct TaskGraph *task_graph,
/* ---------------------------------------------------------------------- */
/** \name Task Node - Update Mesh Render Data
* \{ */
+
struct MeshRenderDataUpdateTaskData {
MeshRenderData *mr = nullptr;
MeshBufferCache *cache = nullptr;
@@ -778,6 +781,8 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
#endif
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
@@ -814,5 +819,3 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
}
} // extern "C"
-
-/** \} */
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
index abfbeabef6b..8b0fbf86360 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
@@ -174,8 +174,8 @@ void mesh_render_data_update_loose_geom(MeshRenderData *mr,
/** \name Polygons sorted per material
*
* Contains polygon indices sorted based on their material.
- *
* \{ */
+
static void mesh_render_data_polys_sorted_load(MeshRenderData *mr, const MeshBufferCache *cache);
static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferCache *cache);
static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache);
@@ -335,9 +335,6 @@ static int *mesh_render_data_mat_tri_len_build(MeshRenderData *mr)
/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
* \{ */
-/**
- * Part of the creation of the #MeshRenderData that happens in a thread.
- */
void mesh_render_data_update_looptris(MeshRenderData *mr,
const eMRIterType iter_type,
const eMRDataType data_flag)
@@ -440,10 +437,6 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
}
}
-/**
- * \param is_mode_active: When true, use the modifiers from the edit-data,
- * otherwise don't use modifiers as they are not from this object.
- */
MeshRenderData *mesh_render_data_create(Mesh *me,
const bool is_editmode,
const bool is_paint_mode,
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 220a7f37c3d..80b8c0506e7 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -47,7 +47,10 @@ struct bGPdata;
extern "C" {
#endif
-/* Expose via BKE callbacks */
+/* -------------------------------------------------------------------- */
+/** \name Expose via BKE callbacks
+ * \{ */
+
void DRW_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode);
void DRW_mball_batch_cache_validate(struct MetaBall *mb);
void DRW_mball_batch_cache_free(struct MetaBall *mb);
@@ -82,15 +85,34 @@ void DRW_volume_batch_cache_dirty_tag(struct Volume *volume, int mode);
void DRW_volume_batch_cache_validate(struct Volume *volume);
void DRW_volume_batch_cache_free(struct Volume *volume);
-/* Garbage collection */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Garbage Collection
+ * \{ */
+
void DRW_batch_cache_free_old(struct Object *ob, int ctime);
+/**
+ * Thread safety need to be assured by caller. Don't call this during drawing.
+ * \note For now this only free the shading batches / VBO if any cd layers is not needed anymore.
+ */
void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime);
-/* Generic */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic
+ * \{ */
+
void DRW_vertbuf_create_wiredata(struct GPUVertBuf *vbo, const int vert_len);
-/* Curve */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve
+ * \{ */
+
void DRW_curve_batch_cache_create_requested(struct Object *ob, const struct Scene *scene);
int DRW_curve_material_count_get(struct Curve *cu);
@@ -107,7 +129,12 @@ struct GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu,
uint gpumat_array_len);
struct GPUBatch *DRW_curve_batch_cache_get_wireframes_face(struct Curve *cu);
-/* Metaball */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Metaball
+ * \{ */
+
int DRW_metaball_material_count_get(struct MetaBall *mb);
struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob);
@@ -119,7 +146,12 @@ struct GPUBatch *DRW_metaball_batch_cache_get_wireframes_face(struct Object *ob)
struct GPUBatch *DRW_metaball_batch_cache_get_edge_detection(struct Object *ob,
bool *r_is_manifold);
-/* DispList */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DispList
+ * \{ */
+
void DRW_displist_vertbuf_create_pos_and_nor(struct ListBase *lb,
struct GPUVertBuf *vbo,
const struct Scene *scene);
@@ -138,17 +170,32 @@ void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb,
struct GPUIndexBuf *ibo,
bool *r_is_manifold);
-/* Lattice */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lattice
+ * \{ */
+
struct GPUBatch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt,
bool use_weight,
const int actdef);
struct GPUBatch *DRW_lattice_batch_cache_get_all_verts(struct Lattice *lt);
struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
-/* Hair */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hair
+ * \{ */
+
int DRW_hair_material_count_get(struct Hair *hair);
-/* PointCloud */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name PointCloud
+ * \{ */
+
int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud);
struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob);
@@ -157,13 +204,26 @@ struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
-/* Volume */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Volume
+ * \{ */
+
int DRW_volume_material_count_get(struct Volume *volume);
struct GPUBatch *DRW_volume_batch_cache_get_wireframes_face(struct Volume *volume);
struct GPUBatch *DRW_volume_batch_cache_get_selection_surface(struct Volume *volume);
-/* Mesh */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh
+ * \{ */
+
+/**
+ * Can be called for any surface type. Mesh *me is the final mesh.
+ */
void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
struct Object *ob,
struct Mesh *me,
@@ -186,7 +246,13 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(struct Mesh *me);
-/* edit-mesh drawing */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-Mesh Drawing
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_edges(struct Mesh *me);
@@ -194,14 +260,39 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(struct Mesh *me);
-/* edit-mesh selection */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-mesh Selection
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me);
-/* Object mode Wireframe overlays */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Wireframe Overlays
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me);
-/* edit-mesh UV editor */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit-mesh UV Editor
+ * \{ */
+
+/**
+ * Creates the #GPUBatch for drawing the UV Stretching Area Overlay.
+ * Optional retrieves the total area or total uv area of the mesh.
+ *
+ * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
+ * only valid after calling `DRW_mesh_batch_cache_create_requested`.
+ */
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Mesh *me,
float **tot_area,
float **tot_uv_area);
@@ -210,11 +301,22 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me);
-/* For Image UV editor. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name For Image UV Editor
+ * \{ */
+
struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me);
-/* For direct data access. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name For Direct Data Access
+ * \{ */
+
struct GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(struct Mesh *me);
struct GPUVertBuf *DRW_curve_batch_cache_pos_vertbuf_get(struct Curve *cu);
struct GPUVertBuf *DRW_mball_batch_cache_pos_vertbuf_get(struct Object *ob);
@@ -250,7 +352,12 @@ enum {
/* Beware to not go over 1 << 7 (it's a byte flag). */
};
-/* Particles */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Particles
+ * \{ */
+
struct GPUBatch *DRW_particles_batch_cache_get_hair(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -266,6 +373,9 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(struct Object *
struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *object,
struct ParticleSystem *psys,
struct PTCacheEdit *edit);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index e78e41b917a..483e52ed547 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -47,7 +47,10 @@
#define BEZIER_HANDLE (1 << 3)
#define COLOR_SHIFT 5
-/* ---------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct GpencilBatchCache {
/** Instancing Data */
GPUVertBuf *vbo;
@@ -74,6 +77,12 @@ typedef struct GpencilBatchCache {
int cache_frame;
} GpencilBatchCache;
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
{
bool valid = true;
@@ -151,6 +160,12 @@ static GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
return cache;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE Callbacks
+ * \{ */
+
void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
{
gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
@@ -166,7 +181,7 @@ void DRW_gpencil_batch_cache_free(bGPdata *gpd)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vertex Formats.
+/** \name Vertex Formats
* \{ */
/* MUST match the format below. */
@@ -247,7 +262,7 @@ static GPUVertFormat *gpencil_color_format(void)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vertex Buffers.
+/** \name Vertex Buffers
* \{ */
typedef struct gpIterData {
@@ -671,7 +686,6 @@ GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(Object *ob)
return gpd->runtime.sbuffer_fill_batch;
}
-/* Sbuffer batches are temporary. We need to clear it after drawing */
void DRW_cache_gpencil_sbuffer_clear(Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -682,8 +696,9 @@ void DRW_cache_gpencil_sbuffer_clear(Object *ob)
/** \} */
-/* ---------------------------------------------------------------------- */
-/* Edit GPencil Batches */
+/* -------------------------------------------------------------------- */
+/** \name Edit GPencil Batches
+ * \{ */
#define GP_EDIT_POINT_SELECTED (1 << 0)
#define GP_EDIT_STROKE_SELECTED (1 << 1)
diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.c
index 41a0cca8a8f..ed0c46ad45a 100644
--- a/source/blender/draw/intern/draw_cache_impl_hair.c
+++ b/source/blender/draw/intern/draw_cache_impl_hair.c
@@ -333,7 +333,6 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair,
prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
}
-/* Ensure all textures and buffers needed for GPU accelerated drawing. */
bool hair_ensure_procedural_data(Object *object,
ParticleHairCache **r_hair_cache,
GPUMaterial *gpu_material,
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 12c19c671ab..82b3b5aee41 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -535,7 +535,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
AttributeDomain domain = ATTR_DOMAIN_NUM;
if (type == CD_AUTO_FROM_NAME) {
- /* We need to deduct what exact layer is used.
+ /* We need to deduce what exact layer is used.
*
* We do it based on the specified name.
*/
@@ -1372,11 +1372,6 @@ static void edituv_request_active_uv(MeshBatchCache *cache, Mesh *me)
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
-/* Creates the GPUBatch for drawing the UV Stretching Area Overlay.
- * Optional retrieves the total area or total uv area of the mesh.
- *
- * The `cache->tot_area` and cache->tot_uv_area` update are calculation are
- * only valid after calling `DRW_mesh_batch_cache_create_requested`. */
GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
float **tot_area,
float **tot_uv_area)
@@ -1456,9 +1451,6 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Mesh *me)
/** \name Grouped batch generation
* \{ */
-/* Thread safety need to be assured by caller. Don't call this during drawing.
- * NOTE: For now this only free the shading batches / vbo if any cd layers is
- * not needed anymore. */
void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -1526,7 +1518,6 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M
}
#endif
-/* Can be called for any surface type. Mesh *me is the final mesh. */
void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
Object *ob,
Mesh *me,
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
index 4d3a990ec72..63bffed0eaf 100644
--- a/source/blender/draw/intern/draw_cache_impl_metaball.c
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -41,8 +41,9 @@
static void metaball_batch_cache_clear(MetaBall *mb);
-/* ---------------------------------------------------------------------- */
-/* MetaBall GPUBatch Cache */
+/* -------------------------------------------------------------------- */
+/** \name MetaBall GPUBatch Cache
+ * \{ */
typedef struct MetaBallBatchCache {
GPUBatch *batch;
@@ -175,6 +176,8 @@ static GPUIndexBuf *mball_batch_cache_get_edges_adj_lines(Object *ob, MetaBallBa
return cache->edges_adj_lines;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Public Object/MetaBall API
* \{ */
@@ -303,3 +306,5 @@ int DRW_metaball_material_count_get(MetaBall *mb)
{
return max_ii(1, mb->totcol);
}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 96bdca7d935..4583b90b144 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -1674,7 +1674,6 @@ GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(Object *object,
return cache->edit_tip_points;
}
-/* Ensure all textures and buffers needed for GPU accelerated drawing. */
bool particles_ensure_procedural_data(Object *object,
ParticleSystem *psys,
ModifierData *md,
diff --git a/source/blender/draw/intern/draw_color_management.cc b/source/blender/draw/intern/draw_color_management.cc
index 70035c7c6f8..6259236e3cf 100644
--- a/source/blender/draw/intern/draw_color_management.cc
+++ b/source/blender/draw/intern/draw_color_management.cc
@@ -175,7 +175,6 @@ void DRW_viewport_colormanagement_set(GPUViewport *viewport)
blender::draw::color_management::viewport_color_management_set(*viewport);
}
-/* Draw texture to framebuffer without any color transforms */
void DRW_transform_none(GPUTexture *tex)
{
drw_state_set(DRW_STATE_WRITE_COLOR);
diff --git a/source/blender/draw/intern/draw_color_management.h b/source/blender/draw/intern/draw_color_management.h
index 9be105b88ec..7dff17b14c6 100644
--- a/source/blender/draw/intern/draw_color_management.h
+++ b/source/blender/draw/intern/draw_color_management.h
@@ -28,6 +28,9 @@ extern "C" {
struct GPUViewport;
+/**
+ * Draw texture to frame-buffer without any color transforms.
+ */
void DRW_transform_none(struct GPUTexture *tex);
void DRW_viewport_colormanagement_set(struct GPUViewport *viewport);
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index 2cbea2ae6d5..65afc5ed3d8 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -41,7 +41,9 @@
#define UI_COLOR_RGBA_FROM_U8(r, g, b, a, v4) \
ARRAY_SET_ITEMS(v4, (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f)
-/* Colors & Constant */
+/**
+ * Colors & Constant.
+ */
struct DRW_Global G_draw = {{{0}}};
static bool weight_ramp_custom = false;
@@ -287,10 +289,6 @@ DRWView *DRW_view_create_with_zoffset(const DRWView *parent_view,
/* ******************************************** COLOR UTILS ************************************ */
/* TODO: FINISH. */
-/**
- * Get the wire color theme_id of an object based on its state
- * \a r_color is a way to get a pointer to the static color var associated
- */
int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 48a3fb209ba..6c3e0773a15 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -161,6 +161,10 @@ struct DRWView *DRW_view_create_with_zoffset(const struct DRWView *parent_view,
const struct RegionView3D *rv3d,
float offset);
+/**
+ * Get the wire color theme_id of an object based on its state
+ * \a r_color is a way to get a pointer to the static color var associated
+ */
int DRW_object_wire_theme_get(struct Object *ob, struct ViewLayer *view_layer, float **r_color);
float *DRW_color_background_blend_get(int theme_id);
@@ -169,13 +173,18 @@ bool DRW_object_axis_orthogonal_to_view(struct Object *ob, int axis);
/* draw_hair.c */
-/* This creates a shading group with display hairs.
- * The draw call is already added by this function, just add additional uniforms. */
+/**
+ * This creates a shading group with display hairs.
+ * The draw call is already added by this function, just add additional uniforms.
+ */
struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
struct DRWShadingGroup *shgrp,
struct GPUMaterial *gpu_material);
+/**
+ * \note Only valid after #DRW_hair_update().
+ */
struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
@@ -201,6 +210,7 @@ void DRW_smoke_free(struct FluidModifierData *fmd);
void DRW_smoke_free_velocity(struct FluidModifierData *fmd);
/* draw_common.c */
+
struct DRW_Global {
/** If needed, contains all global/Theme colors
* Add needed theme colors / values to DRW_globals_update() and update UBO
diff --git a/source/blender/draw/intern/draw_debug.c b/source/blender/draw/intern/draw_debug.c
index 59c6efe1a61..e0114a6230e 100644
--- a/source/blender/draw/intern/draw_debug.c
+++ b/source/blender/draw/intern/draw_debug.c
@@ -68,7 +68,6 @@ void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float c
}
}
-/* NOTE: g_modelmat is still applied on top. */
void DRW_debug_m4(const float m[4][4])
{
float v0[3] = {0.0f, 0.0f, 0.0f};
diff --git a/source/blender/draw/intern/draw_debug.h b/source/blender/draw/intern/draw_debug.h
index 149825974d4..2f1a082af96 100644
--- a/source/blender/draw/intern/draw_debug.h
+++ b/source/blender/draw/intern/draw_debug.h
@@ -29,6 +29,9 @@ void DRW_debug_modelmat(const float modelmat[4][4]);
void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]);
void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float color[4]);
+/**
+ * \note g_modelmat is still applied on top.
+ */
void DRW_debug_m4(const float m[4][4]);
void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool invert);
void DRW_debug_bbox(const BoundBox *bbox, const float color[4]);
diff --git a/source/blender/draw/intern/draw_fluid.c b/source/blender/draw/intern/draw_fluid.c
index 9cfdbf7c688..616307ca86b 100644
--- a/source/blender/draw/intern/draw_fluid.c
+++ b/source/blender/draw/intern/draw_fluid.c
@@ -589,9 +589,10 @@ void DRW_fluid_ensure_range_field(FluidModifierData *fmd)
#endif /* WITH_FLUID */
}
-/* TODO: Unify with the other #GPU_free_smoke. */
void DRW_smoke_free_velocity(FluidModifierData *fmd)
{
+ /* TODO: Unify with the other #GPU_free_smoke. */
+
if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
if (fmd->domain->tex_velocity_x) {
GPU_texture_free(fmd->domain->tex_velocity_x);
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 5c7eb083fc9..0abb00a71a9 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -203,7 +203,6 @@ static ParticleHairCache *drw_hair_particle_cache_get(Object *object,
return cache;
}
-/* NOTE: Only valid after DRW_hair_update(). */
GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
index 289a1690fc6..d5d9a9fb299 100644
--- a/source/blender/draw/intern/draw_hair_private.h
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -93,6 +93,9 @@ typedef struct ParticleHairCache {
void particle_batch_cache_clear_hair(struct ParticleHairCache *hair_cache);
+/**
+ * Ensure all textures and buffers needed for GPU accelerated drawing.
+ */
bool particles_ensure_procedural_data(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
@@ -101,6 +104,9 @@ bool particles_ensure_procedural_data(struct Object *object,
int subdiv,
int thickness_res);
+/**
+ * Ensure all textures and buffers needed for GPU accelerated drawing.
+ */
bool hair_ensure_procedural_data(struct Object *object,
struct ParticleHairCache **r_hair_cache,
struct GPUMaterial *gpu_material,
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
index 29112ee4788..7e1d1208698 100644
--- a/source/blender/draw/intern/draw_instance_data.c
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -112,14 +112,6 @@ static void instancing_batch_references_remove(GPUBatch *batch)
/** \name Instance Buffer Management
* \{ */
-/**
- * This manager allows to distribute existing batches for instancing
- * attributes. This reduce the number of batches creation.
- * Querying a batch is done with a vertex format. This format should
- * be static so that its pointer never changes (because we are using
- * this pointer as identifier [we don't want to check the full format
- * that would be too slow]).
- */
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
int *vert_len)
@@ -143,8 +135,6 @@ GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
return handle->buf;
}
-/* NOTE: Does not return a valid drawable batch until DRW_instance_buffer_finish has run.
- * Initialization is delayed because instancer or geom could still not be initialized. */
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *instancer,
@@ -185,7 +175,6 @@ GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
return batch;
}
-/* NOTE: Use only with buf allocated via DRW_temp_buffer_request. */
GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUPrimType prim_type)
@@ -301,9 +290,6 @@ static void DRW_instance_data_free(DRWInstanceData *idata)
BLI_mempool_destroy(idata->mempool);
}
-/**
- * Return a pointer to the next instance data space.
- */
void *DRW_instance_data_next(DRWInstanceData *idata)
{
return BLI_mempool_alloc(idata->mempool);
@@ -421,6 +407,7 @@ void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sparse Uniform Buffer
* \{ */
@@ -453,7 +440,6 @@ static void drw_sparse_uniform_buffer_init(DRWSparseUniformBuf *buffer,
buffer->chunk_bytes = item_size * chunk_size;
}
-/** Allocate a chunked UBO with the specified item and chunk size. */
DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size, unsigned int chunk_size)
{
DRWSparseUniformBuf *buf = MEM_mallocN(sizeof(DRWSparseUniformBuf), __func__);
@@ -461,7 +447,6 @@ DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size, unsig
return buf;
}
-/** Flush data from ordinary memory to UBOs. */
void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer)
{
for (int i = 0; i < buffer->num_chunks; i++) {
@@ -474,7 +459,6 @@ void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer)
}
}
-/** Clean all buffers and free unused ones. */
void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all)
{
int max_used_chunk = 0;
@@ -517,14 +501,12 @@ void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all)
BLI_bitmap_set_all(buffer->chunk_used, false, buffer->num_chunks);
}
-/** Frees the buffer. */
void DRW_sparse_uniform_buffer_free(DRWSparseUniformBuf *buffer)
{
DRW_sparse_uniform_buffer_clear(buffer, true);
MEM_freeN(buffer);
}
-/** Checks if the buffer contains any allocated chunks. */
bool DRW_sparse_uniform_buffer_is_empty(DRWSparseUniformBuf *buffer)
{
return buffer->num_chunks == 0;
@@ -538,7 +520,6 @@ static GPUUniformBuf *drw_sparse_uniform_buffer_get_ubo(DRWSparseUniformBuf *buf
return NULL;
}
-/** Bind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty. */
void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int location)
{
GPUUniformBuf *ubo = drw_sparse_uniform_buffer_get_ubo(buffer, chunk);
@@ -547,7 +528,6 @@ void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int
}
}
-/** Unbind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty. */
void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk)
{
GPUUniformBuf *ubo = drw_sparse_uniform_buffer_get_ubo(buffer, chunk);
@@ -556,7 +536,6 @@ void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk)
}
}
-/** Returns a pointer to the given item of the given chunk, allocating memory if necessary. */
void *DRW_sparse_uniform_buffer_ensure_item(DRWSparseUniformBuf *buffer, int chunk, int item)
{
if (chunk >= buffer->num_chunks) {
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index c959a9e19d6..fb88b3dc6ec 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -38,21 +38,41 @@ typedef struct DRWInstanceData DRWInstanceData;
typedef struct DRWInstanceDataList DRWInstanceDataList;
typedef struct DRWSparseUniformBuf DRWSparseUniformBuf;
+/**
+ * Return a pointer to the next instance data space.
+ */
void *DRW_instance_data_next(DRWInstanceData *idata);
DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint attr_size);
+/**
+ * This manager allows to distribute existing batches for instancing
+ * attributes. This reduce the number of batches creation.
+ * Querying a batch is done with a vertex format. This format should
+ * be static so that its pointer never changes (because we are using
+ * this pointer as identifier [we don't want to check the full format
+ * that would be too slow]).
+ */
GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist,
GPUVertFormat *format,
int *vert_len);
+/**
+ * \note Does not return a valid drawable batch until DRW_instance_buffer_finish has run.
+ * Initialization is delayed because instancer or geom could still not be initialized.
+ */
GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUBatch *instancer,
GPUBatch *geom);
+/**
+ * \note Use only with buf allocated via DRW_temp_buffer_request.
+ */
GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist,
GPUVertBuf *buf,
GPUPrimType type);
-/* Upload all instance data to the GPU as soon as possible. */
+/**
+ * Upload all instance data to the GPU as soon as possible.
+ */
void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist);
void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist);
@@ -60,17 +80,43 @@ void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist);
void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist);
/* Sparse chunked UBO manager. */
+
+/**
+ * Allocate a chunked UBO with the specified item and chunk size.
+ */
DRWSparseUniformBuf *DRW_sparse_uniform_buffer_new(unsigned int item_size,
unsigned int chunk_size);
+/**
+ * Flush data from ordinary memory to UBOs.
+ */
void DRW_sparse_uniform_buffer_flush(DRWSparseUniformBuf *buffer);
+/**
+ * Clean all buffers and free unused ones.
+ */
void DRW_sparse_uniform_buffer_clear(DRWSparseUniformBuf *buffer, bool free_all);
+/**
+ * Frees the buffer.
+ */
void DRW_sparse_uniform_buffer_free(DRWSparseUniformBuf *buffer);
+/**
+ * Checks if the buffer contains any allocated chunks.
+ */
bool DRW_sparse_uniform_buffer_is_empty(DRWSparseUniformBuf *buffer);
+/**
+ * Bind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty.
+ */
void DRW_sparse_uniform_buffer_bind(DRWSparseUniformBuf *buffer, int chunk, int location);
+/**
+ * Unbind the UBO for the given chunk, if present. A NULL buffer pointer is handled as empty.
+ */
void DRW_sparse_uniform_buffer_unbind(DRWSparseUniformBuf *buffer, int chunk);
+/**
+ * Returns a pointer to the given item of the given chunk, allocating memory if necessary.
+ */
void *DRW_sparse_uniform_buffer_ensure_item(DRWSparseUniformBuf *buffer, int chunk, int item);
/* Uniform attribute UBO management. */
+
struct GHash *DRW_uniform_attrs_pool_new(void);
void DRW_uniform_attrs_pool_flush_all(struct GHash *table);
void DRW_uniform_attrs_pool_clear_all(struct GHash *table);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 1d9bc607590..930fb6eabef 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -173,7 +173,8 @@ static void drw_task_graph_deinit(void)
{
BLI_task_graph_work_and_wait(DST.task_graph);
- BLI_gset_free(DST.delayed_extraction, (void (*)(void *key))drw_batch_cache_generate_requested);
+ BLI_gset_free(DST.delayed_extraction,
+ (void (*)(void *key))drw_batch_cache_generate_requested_evaluated_mesh);
DST.delayed_extraction = NULL;
BLI_task_graph_work_and_wait(DST.task_graph);
@@ -203,11 +204,6 @@ bool DRW_object_is_renderable(const Object *ob)
return true;
}
-/* Does `ob` needs to be rendered in edit mode.
- *
- * When using duplicate linked meshes, objects that are not in edit-mode will be drawn as
- * it is in edit mode, when another object with the same mesh is in edit mode.
- * This will not be the case when one of the objects are influenced by modifiers. */
bool DRW_object_is_in_edit_mode(const Object *ob)
{
if (BKE_object_is_in_editmode(ob)) {
@@ -235,10 +231,6 @@ bool DRW_object_is_in_edit_mode(const Object *ob)
return false;
}
-/**
- * Return whether this object is visible depending if
- * we are rendering or drawing in the viewport.
- */
int DRW_object_visibility_in_active_context(const Object *ob)
{
const eEvaluationMode mode = DRW_state_is_scene_render() ? DAG_EVAL_RENDER : DAG_EVAL_VIEWPORT;
@@ -321,7 +313,6 @@ struct DupliObject *DRW_object_get_dupli(const Object *UNUSED(ob))
/** \name Viewport (DRW_viewport)
* \{ */
-/* WARNING: only use for custom pipeline. 99% of the time, you don't want to use this. */
void DRW_render_viewport_size_set(const int size[2])
{
DST.size[0] = size[0];
@@ -778,7 +769,6 @@ static void drw_duplidata_free(void)
}
}
-/* Return NULL if not a dupli or a pointer of pointer to the engine data */
void **DRW_duplidata_get(void *vedata)
{
if (DST.dupli_source == NULL) {
@@ -874,9 +864,6 @@ static bool id_can_have_drawdata(const ID *id)
return id_type_can_have_drawdata(GS(id->name));
}
-/* Get DrawData from the given ID-block. In order for this to work, we assume that
- * the DrawData pointer is stored in the struct in the same fashion as in IdDdtTemplate.
- */
DrawDataList *DRW_drawdatalist_from_id(ID *id)
{
/* only some ID-blocks have this info for now, so we cast the
@@ -1148,7 +1135,6 @@ static void drw_engines_draw_text(void)
}
}
-/* Draw render engine info. */
void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height)
{
DRW_ENABLED_ENGINE_ITER (DST.view_data_active, engine, data) {
@@ -1367,6 +1353,61 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
BLI_ticket_mutex_unlock(DST.gl_context_mutex);
}
+/* update a viewport which belongs to a GPUOffscreen */
+static void drw_notify_view_update_offscreen(struct Depsgraph *depsgraph,
+ RenderEngineType *engine_type,
+ ARegion *region,
+ View3D *v3d,
+ GPUViewport *viewport)
+{
+
+ if (viewport && GPU_viewport_do_update(viewport)) {
+
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RegionView3D *rv3d = region->regiondata;
+
+ const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+
+ DST.draw_ctx = (DRWContextState){
+ .region = region,
+ .rv3d = rv3d,
+ .v3d = v3d,
+ .scene = scene,
+ .view_layer = view_layer,
+ .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+ };
+
+ /* Custom lightweight initialize to avoid resetting the memory-pools. */
+ DST.viewport = viewport;
+ DST.vmempool = drw_viewport_data_ensure(DST.viewport);
+
+ /* Separate update for each stereo view. */
+ int view_count = GPU_viewport_is_stereo_get(viewport) ? 2 : 1;
+ for (int view = 0; view < view_count; view++) {
+ DST.view_data_active = DST.vmempool->view_data[view];
+
+ drw_engines_enable(view_layer, engine_type, gpencil_engine_needed);
+ drw_engines_data_validate();
+
+ DRW_ENABLED_ENGINE_ITER (DST.view_data_active, draw_engine, data) {
+ if (draw_engine->view_update) {
+ draw_engine->view_update(data);
+ }
+ }
+
+ drw_engines_disable();
+ }
+
+ drw_manager_exit(&DST);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1549,9 +1590,6 @@ struct DRWTextStore *DRW_text_cache_ensure(void)
/** \name Main Draw Loops (DRW_draw)
* \{ */
-/* Everything starts here.
- * This function takes care of calling all cache and rendering functions
- * for each relevant engine / mode engine. */
void DRW_draw_view(const bContext *C)
{
View3D *v3d = CTX_wm_view3d(C);
@@ -1579,10 +1617,6 @@ void DRW_draw_view(const bContext *C)
}
}
-/**
- * Used for both regular and off-screen drawing.
- * Need to reset DST before calling this function
- */
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *region,
@@ -1729,9 +1763,6 @@ void DRW_draw_render_loop(struct Depsgraph *depsgraph,
DRW_draw_render_loop_ex(depsgraph, engine_type, region, v3d, viewport, NULL);
}
-/**
- * \param viewport: can be NULL, in this case we create one.
- */
void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *region,
@@ -1742,11 +1773,14 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
GPUOffScreen *ofs,
GPUViewport *viewport)
{
- /* Create temporary viewport if needed. */
+ /* Create temporary viewport if needed or update the existing viewport. */
GPUViewport *render_viewport = viewport;
if (viewport == NULL) {
render_viewport = GPU_viewport_create();
}
+ else {
+ drw_notify_view_update_offscreen(depsgraph, engine_type, region, v3d, render_viewport);
+ }
GPU_viewport_bind_from_offscreen(render_viewport, ofs);
@@ -1790,7 +1824,6 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
}
}
-/* Helper to check if exit object type to render. */
bool DRW_render_check_grease_pencil(Depsgraph *depsgraph)
{
if (!drw_gpencil_engine_needed(depsgraph, NULL)) {
@@ -2019,9 +2052,6 @@ void DRW_render_object_iter(
drw_task_graph_deinit();
}
-/* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired).
- * This function only setup DST and execute the given function.
- * Warning: similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl). */
void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
struct Depsgraph *depsgraph,
void (*callback)(void *vedata, void *user_data),
@@ -2067,8 +2097,6 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
drw_manager_exit(&DST);
}
-/* Used when the render engine want to redo another cache populate inside the same render frame.
- */
void DRW_cache_restart(void)
{
drw_manager_init(&DST, DST.viewport, (int[2]){UNPACK2(DST.size)});
@@ -2259,7 +2287,6 @@ static void draw_select_framebuffer_depth_only_setup(const int size[2])
}
}
-/* Must run after all instance datas have been added. */
void DRW_render_instance_buffer_finish(void)
{
BLI_assert_msg(!DST.buffer_finish_called, "DRW_render_instance_buffer_finish called twice!");
@@ -2268,7 +2295,6 @@ void DRW_render_instance_buffer_finish(void)
drw_resource_buffer_finish(DST.vmempool);
}
-/* WARNING: Changing frame might free the ViewLayerEngineData */
void DRW_render_set_time(RenderEngine *engine, Depsgraph *depsgraph, int frame, float subframe)
{
RE_engine_frame_set(engine, frame, subframe);
@@ -2276,9 +2302,6 @@ void DRW_render_set_time(RenderEngine *engine, Depsgraph *depsgraph, int frame,
DST.draw_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph);
}
-/**
- * object mode select-loop, see: ED_view3d_draw_select_loop (legacy drawing).
- */
void DRW_draw_select_loop(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2606,9 +2629,6 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
}
}
-/**
- * object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
- */
void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2636,9 +2656,6 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false);
}
-/**
- * Converted from ED_view3d_draw_depth_gpencil (legacy drawing).
- */
void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2731,9 +2748,6 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons
drw_manager_exit(&DST);
}
-/**
- * Clears the Depth Buffer and draws only the specified object.
- */
void DRW_draw_depth_object(
Scene *scene, ARegion *region, View3D *v3d, GPUViewport *viewport, Object *object)
{
@@ -2814,19 +2828,12 @@ void DRW_draw_depth_object(
/** \name Draw Manager State (DRW_state)
* \{ */
-/**
- * When false, drawing doesn't output to a pixel buffer
- * eg: Occlusion queries, or when we have setup a context to draw in already.
- */
bool DRW_state_is_fbo(void)
{
return ((DST.default_framebuffer != NULL) || DST.options.is_image_render) &&
!DRW_state_is_depth() && !DRW_state_is_select();
}
-/**
- * For when engines need to know if this is drawing for selection or not.
- */
bool DRW_state_is_select(void)
{
return DST.options.is_select;
@@ -2842,27 +2849,17 @@ bool DRW_state_is_depth(void)
return DST.options.is_depth;
}
-/**
- * Whether we are rendering for an image
- */
bool DRW_state_is_image_render(void)
{
return DST.options.is_image_render;
}
-/**
- * Whether we are rendering only the render engine,
- * or if we should also render the mode engines.
- */
bool DRW_state_is_scene_render(void)
{
BLI_assert(DST.options.is_scene_render ? DST.options.is_image_render : true);
return DST.options.is_scene_render;
}
-/**
- * Whether we are rendering simple opengl render
- */
bool DRW_state_is_opengl_render(void)
{
return DST.options.is_image_render && !DST.options.is_scene_render;
@@ -2877,28 +2874,18 @@ bool DRW_state_is_playback(void)
return false;
}
-/**
- * Is the user navigating the region.
- */
bool DRW_state_is_navigating(void)
{
const RegionView3D *rv3d = DST.draw_ctx.rv3d;
return (rv3d) && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING));
}
-/**
- * Should text draw in this mode?
- */
bool DRW_state_show_text(void)
{
return (DST.options.is_select) == 0 && (DST.options.is_depth) == 0 &&
(DST.options.is_scene_render) == 0 && (DST.options.draw_text) == 0;
}
-/**
- * Should draw support elements
- * Objects center, selection outline, probe data, ...
- */
bool DRW_state_draw_support(void)
{
View3D *v3d = DST.draw_ctx.v3d;
@@ -2906,9 +2893,6 @@ bool DRW_state_draw_support(void)
((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0);
}
-/**
- * Whether we should render the background
- */
bool DRW_state_draw_background(void)
{
return DST.options.draw_background;
@@ -3160,6 +3144,8 @@ void DRW_opengl_context_disable_ex(bool restore)
void DRW_opengl_context_enable(void)
{
+ /* TODO: should be replace by a more elegant alternative. */
+
if (G.background && DST.gl_context == NULL) {
WM_init_opengl();
}
@@ -3188,7 +3174,6 @@ void DRW_opengl_render_context_disable(void *re_gl_context)
BLI_ticket_mutex_unlock(DST.gl_context_mutex);
}
-/* Needs to be called AFTER DRW_opengl_render_context_enable() */
void DRW_gpu_render_context_enable(void *re_gpu_context)
{
/* If thread is main you should use DRW_opengl_context_enable(). */
@@ -3197,7 +3182,6 @@ void DRW_gpu_render_context_enable(void *re_gpu_context)
GPU_context_active_set(re_gpu_context);
}
-/* Needs to be called BEFORE DRW_opengl_render_context_disable() */
void DRW_gpu_render_context_disable(void *UNUSED(re_gpu_context))
{
GPU_flush();
@@ -3242,6 +3226,8 @@ void DRW_xr_drawing_end(void)
#endif
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Internal testing API for gtests
* \{ */
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 162fe9b5fd1..a4924711384 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -663,7 +663,12 @@ eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index);
void drw_batch_cache_validate(Object *ob);
void drw_batch_cache_generate_requested(struct Object *ob);
+
+/**
+ * \warning Only evaluated mesh data is handled by this delayed generation.
+ */
void drw_batch_cache_generate_requested_delayed(Object *ob);
+void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob);
void drw_resource_buffer_finish(DRWData *vmempool);
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index c98ecc8ac00..e71a1298812 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -304,6 +304,7 @@ void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
const int *value,
int arraysize)
{
+ /* Boolean are expected to be 4bytes longs for OpenGL! */
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
}
@@ -381,7 +382,6 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, (float *)value, 16, 1);
}
-/* Stores the int instead of a pointer. */
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
{
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
@@ -833,7 +833,6 @@ void DRW_shgroup_call_range(
drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct);
}
-/* A count of 0 instance will use the default number of instance in the batch. */
void DRW_shgroup_call_instance_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct)
{
@@ -888,7 +887,6 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob,
drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tri_count * 3);
}
-/* Should be removed */
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
@@ -1441,10 +1439,6 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
return shgroup;
}
-/**
- * State is added to #Pass.state while drawing.
- * Use to temporarily enable draw options.
- */
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
{
drw_command_set_mutable_state(shgroup, state, 0x0);
@@ -1463,7 +1457,6 @@ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
drw_command_set_stencil_mask(shgroup, write_mask, reference, compare_mask);
}
-/* TODO: remove this function. */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
{
drw_command_set_stencil_mask(shgroup, 0xFF, mask, 0xFF);
@@ -1758,7 +1751,6 @@ static void draw_view_matrix_state_update(DRWViewUboStorage *storage,
storage->viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
}
-/* Create a view with culling. */
DRWView *DRW_view_create(const float viewmat[4][4],
const float winmat[4][4],
const float (*culling_viewmat)[4],
@@ -1785,7 +1777,6 @@ DRWView *DRW_view_create(const float viewmat[4][4],
return view;
}
-/* Create a view with culling done by another view. */
DRWView *DRW_view_create_sub(const DRWView *parent_view,
const float viewmat[4][4],
const float winmat[4][4])
@@ -1807,13 +1798,10 @@ DRWView *DRW_view_create_sub(const DRWView *parent_view,
return view;
}
-/**
- * DRWView Update:
+/* DRWView Update:
* This is meant to be done on existing views when rendering in a loop and there is no
- * need to allocate more DRWViews.
- */
+ * need to allocate more DRWViews. */
-/* Update matrices of a view created with DRW_view_create_sub. */
void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4])
{
BLI_assert(view->parent != NULL);
@@ -1824,7 +1812,6 @@ void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float w
draw_view_matrix_state_update(&view->storage, viewmat, winmat);
}
-/* Update matrices of a view created with DRW_view_create. */
void DRW_view_update(DRWView *view,
const float viewmat[4][4],
const float winmat[4][4],
@@ -1893,13 +1880,11 @@ void DRW_view_update(DRWView *view,
#endif
}
-/* Return default view if it is a viewport render. */
const DRWView *DRW_view_default_get(void)
{
return DST.view_default;
}
-/* WARNING: Only use in render AND only if you are going to set view_default again. */
void DRW_view_reset(void)
{
DST.view_default = NULL;
@@ -1907,18 +1892,12 @@ void DRW_view_reset(void)
DST.view_previous = NULL;
}
-/* MUST only be called once per render and only in render mode. Sets default view. */
void DRW_view_default_set(DRWView *view)
{
BLI_assert(DST.view_default == NULL);
DST.view_default = view;
}
-/**
- * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
- * and if the shaders have support for it (see usage of gl_ClipDistance).
- * NOTE: planes must be in world space.
- */
void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len)
{
BLI_assert(plane_len <= MAX_CLIP_PLANES);
@@ -1933,14 +1912,11 @@ void DRW_view_camtexco_set(DRWView *view, float texco[4])
copy_v4_v4(view->storage.viewcamtexcofac, texco);
}
-/* Return world space frustum corners. */
void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners)
{
memcpy(corners, &view->frustum_corners, sizeof(view->frustum_corners));
}
-/* Return world space frustum sides as planes.
- * See draw_frustum_culling_planes_calc() for the plane order. */
void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4])
{
memcpy(planes, &view->frustum_planes, sizeof(view->frustum_planes));
@@ -2022,8 +1998,6 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
return pass;
}
-/* Create an instance of the original pass that will execute the same drawcalls but with its own
- * DRWState. */
DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state)
{
DRWPass *pass = DRW_pass_create(name, state);
@@ -2032,7 +2006,6 @@ DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState
return pass;
}
-/* Link two passes so that they are both rendered if the first one is being drawn. */
void DRW_pass_link(DRWPass *first, DRWPass *second)
{
BLI_assert(first != second);
@@ -2093,10 +2066,6 @@ static int pass_shgroup_dist_sort(const void *a, const void *b)
#undef SORT_IMPL_LINKTYPE
-/**
- * Sort Shading groups by decreasing Z of their first draw call.
- * This is useful for order dependent effect such as alpha-blending.
- */
void DRW_pass_sort_shgroup_z(DRWPass *pass)
{
const float(*viewinv)[4] = DST.view_active->storage.viewinv;
@@ -2147,9 +2116,6 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass)
pass->shgroups.last = last;
}
-/**
- * Reverse Shading group submission order.
- */
void DRW_pass_sort_shgroup_reverse(DRWPass *pass)
{
pass->shgroups.last = pass->shgroups.first;
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index aa01ca7a262..8dd24c01337 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -273,7 +273,6 @@ static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_
GPU_stencil_compare_mask_set(compare_mask);
}
-/* Reset state to not interfere with other UI draw-call. */
void DRW_state_reset_ex(DRWState state)
{
DST.state = ~state;
@@ -292,12 +291,6 @@ static void drw_state_validate(void)
}
}
-/**
- * Use with care, intended so selection code can override passes depth settings,
- * which is important for selection to work properly.
- *
- * Should be set in main draw loop, cleared afterwards
- */
void DRW_state_lock(DRWState state)
{
DST.state_lock = state;
@@ -361,7 +354,6 @@ static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view)
return (culling->mask & view->culling_mask) != 0;
}
-/* Set active view for rendering. */
void DRW_view_set_active(DRWView *view)
{
DST.view_active = (view) ? view : DST.view_default;
@@ -435,32 +427,24 @@ static bool draw_culling_plane_test(const BoundBox *corners, const float plane[4
return false;
}
-/* Return True if the given BoundSphere intersect the current view frustum.
- * bsphere must be in world space. */
bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere)
{
view = view ? view : DST.view_default;
return draw_culling_sphere_test(&view->frustum_bsphere, view->frustum_planes, bsphere);
}
-/* Return True if the given BoundBox intersect the current view frustum.
- * bbox must be in world space. */
bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox)
{
view = view ? view : DST.view_default;
return draw_culling_box_test(view->frustum_planes, bbox);
}
-/* Return True if the view frustum is inside or intersect the given plane.
- * plane must be in world space. */
bool DRW_culling_plane_test(const DRWView *view, const float plane[4])
{
view = view ? view : DST.view_default;
return draw_culling_plane_test(&view->frustum_corners, plane);
}
-/* Return True if the given box intersect the current view frustum.
- * This function will have to be replaced when world space bb per objects is implemented. */
bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3])
{
view = view ? view : DST.view_default;
@@ -1169,7 +1153,6 @@ void DRW_draw_pass(DRWPass *pass)
}
}
-/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
{
drw_draw_pass_ex(pass, start_group, end_group);
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index 87d4c34b3ed..80ea7bf654d 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -129,8 +129,6 @@ static void drw_stats_timer_start_ex(const char *name, const bool is_query)
}
}
-/* Use this to group the queries. It does NOT keep track
- * of the time, it only sum what the queries inside it. */
void DRW_stats_group_start(const char *name)
{
drw_stats_timer_start_ex(name, false);
@@ -147,7 +145,6 @@ void DRW_stats_group_end(void)
}
}
-/* NOTE: Only call this when no sub timer will be called. */
void DRW_stats_query_start(const char *name)
{
GPU_debug_group_begin(name);
diff --git a/source/blender/draw/intern/draw_manager_profiling.h b/source/blender/draw/intern/draw_manager_profiling.h
index 3842bdffaff..e7c84491bdb 100644
--- a/source/blender/draw/intern/draw_manager_profiling.h
+++ b/source/blender/draw/intern/draw_manager_profiling.h
@@ -28,9 +28,16 @@ void DRW_stats_free(void);
void DRW_stats_begin(void);
void DRW_stats_reset(void);
+/**
+ * Use this to group the queries. It does NOT keep track
+ * of the time, it only sum what the queries inside it.
+ */
void DRW_stats_group_start(const char *name);
void DRW_stats_group_end(void);
+/**
+ * \note Only call this when no sub timer will be called.
+ */
void DRW_stats_query_start(const char *name);
void DRW_stats_query_end(void);
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 83d0030f89b..84440a8effe 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -650,8 +650,6 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const ch
}
}
-/* Return an allocN'ed string containing the shader code with its dependencies prepended.
- * Caller must free the string with MEM_freeN after use. */
char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib, const char *shader_code)
{
uint32_t deps = drw_shader_dependencies_get(lib, shader_code);
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index cfaa22ba7c6..5d7b2c142c2 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -223,7 +223,6 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *region, struct View3D *v3d)
}
}
-/* Copied from drawobject.c */
void DRW_text_edit_mesh_measure_stats(ARegion *region,
View3D *v3d,
Object *ob,
diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h
index 883b37c52af..000a6ab5e6f 100644
--- a/source/blender/draw/intern/draw_manager_text.h
+++ b/source/blender/draw/intern/draw_manager_text.h
@@ -60,6 +60,7 @@ enum {
};
/* draw_manager.c */
+
struct DRWTextStore *DRW_text_cache_ensure(void);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c
index d7438b7e0f0..bae07753336 100644
--- a/source/blender/draw/intern/draw_select_buffer.c
+++ b/source/blender/draw/intern/draw_select_buffer.c
@@ -47,7 +47,6 @@
/** \name Buffer of select ID's
* \{ */
-/* Main function to read a block of pixels from the select frame buffer. */
uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -122,10 +121,6 @@ uint *DRW_select_buffer_read(struct Depsgraph *depsgraph,
*
* \{ */
-/**
- * \param rect: The rectangle to sample indices from (min/max inclusive).
- * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
- */
uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -165,12 +160,6 @@ uint *DRW_select_buffer_bitmap_from_rect(struct Depsgraph *depsgraph,
return bitmap_buf;
}
-/**
- * \param center: Circle center.
- * \param radius: Circle radius.
- * \param r_bitmap_len: Number of indices in the selection id buffer.
- * \returns a #BLI_bitmap the length of \a r_bitmap_len or NULL on failure.
- */
uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -235,12 +224,6 @@ static void drw_select_mask_px_cb(int x, int x_end, int y, void *user_data)
} while (++x != x_end);
}
-/**
- * \param poly: The polygon coordinates.
- * \param poly_len: Length of the polygon.
- * \param rect: Polygon boundaries.
- * \returns a #BLI_bitmap.
- */
uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -309,9 +292,6 @@ uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
*
* \{ */
-/**
- * Samples a single pixel.
- */
uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -357,11 +337,6 @@ static bool select_buffer_test_fn(const void *__restrict value, void *__restrict
return false;
}
-/**
- * Find the selection id closest to \a center.
- * \param dist: Use to initialize the distance,
- * when found, this value is set to the distance of the selection that's returned.
- */
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -522,4 +497,5 @@ void DRW_select_buffer_context_create(Base **bases, const uint bases_len, short
select_ctx->select_mode = select_mode;
memset(select_ctx->persmat, 0, sizeof(select_ctx->persmat));
}
+
/** \} */
diff --git a/source/blender/draw/intern/draw_texture_pool.cc b/source/blender/draw/intern/draw_texture_pool.cc
index 709bf808874..e3882d4acb6 100644
--- a/source/blender/draw/intern/draw_texture_pool.cc
+++ b/source/blender/draw/intern/draw_texture_pool.cc
@@ -40,7 +40,7 @@ struct DRWTexturePool {
int last_user_id = -1;
};
-DRWTexturePool *DRW_texture_pool_create(void)
+DRWTexturePool *DRW_texture_pool_create()
{
return new DRWTexturePool();
}
@@ -53,10 +53,6 @@ void DRW_texture_pool_free(DRWTexturePool *pool)
delete pool;
}
-/**
- * Try to find a texture corresponding to params into the texture pool.
- * If no texture was found, create one and add it to the pool.
- */
GPUTexture *DRW_texture_pool_query(
DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user)
{
@@ -113,7 +109,6 @@ GPUTexture *DRW_texture_pool_query(
return handle.texture;
}
-/* Resets the user bits for each texture in the pool and delete unused ones. */
void DRW_texture_pool_reset(DRWTexturePool *pool)
{
pool->last_user_id = -1;
diff --git a/source/blender/draw/intern/draw_texture_pool.h b/source/blender/draw/intern/draw_texture_pool.h
index f0b8f775c75..920d29b4cca 100644
--- a/source/blender/draw/intern/draw_texture_pool.h
+++ b/source/blender/draw/intern/draw_texture_pool.h
@@ -38,8 +38,15 @@ extern "C" {
DRWTexturePool *DRW_texture_pool_create(void);
void DRW_texture_pool_free(DRWTexturePool *pool);
+/**
+ * Try to find a texture corresponding to params into the texture pool.
+ * If no texture was found, create one and add it to the pool.
+ */
GPUTexture *DRW_texture_pool_query(
DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user);
+/**
+ * Resets the user bits for each texture in the pool and delete unused ones.
+ */
void DRW_texture_pool_reset(DRWTexturePool *pool);
#ifdef __cplusplus
diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c
index de43d2aba0f..6fe0abf1adf 100644
--- a/source/blender/draw/intern/draw_view.c
+++ b/source/blender/draw/intern/draw_view.c
@@ -236,9 +236,6 @@ static bool is_cursor_visible_2d(const DRWContextState *draw_ctx)
/** \name Generic Cursor
* \{ */
-/**
- * \note This doesn't require the draw context to be in use.
- */
void DRW_draw_cursor_2d_ex(const ARegion *region, const float cursor[2])
{
int co[2];
@@ -286,6 +283,7 @@ void DRW_draw_cursor_2d(void)
DRW_draw_cursor_2d_ex(region, sima->cursor);
}
}
+
/** \} */
/* **************************** 3D Gizmo ******************************** */
diff --git a/source/blender/draw/intern/draw_view_data.cc b/source/blender/draw/intern/draw_view_data.cc
index 55ebbf82c29..f7304737830 100644
--- a/source/blender/draw/intern/draw_view_data.cc
+++ b/source/blender/draw/intern/draw_view_data.cc
@@ -50,11 +50,6 @@ struct DRWViewData {
Vector<ViewportEngineData *> enabled_engines;
};
-/**
- * Creates a view data with all possible engines type for this view.
- *
- * `engine_types` contains `DRWRegisteredDrawEngine`.
- * */
DRWViewData *DRW_view_data_create(ListBase *engine_types)
{
DRWViewData *view_data = new DRWViewData();
@@ -120,6 +115,12 @@ static void draw_viewport_engines_data_clear(ViewportEngineData *data)
MEM_SAFE_FREE(data->stl->storage[i]);
}
+ if (data->instance_data) {
+ BLI_assert(engine_type->instance_free != nullptr);
+ engine_type->instance_free(data->instance_data);
+ data->instance_data = nullptr;
+ }
+
MEM_SAFE_FREE(data->fbl);
MEM_SAFE_FREE(data->txl);
MEM_SAFE_FREE(data->psl);
diff --git a/source/blender/draw/intern/draw_view_data.h b/source/blender/draw/intern/draw_view_data.h
index c8176170a61..494c28cc067 100644
--- a/source/blender/draw/intern/draw_view_data.h
+++ b/source/blender/draw/intern/draw_view_data.h
@@ -63,6 +63,12 @@ typedef struct ViewportEngineData {
TextureList *txl;
PassList *psl;
StorageList *stl;
+ /**
+ * \brief Memory block that can be freely used by the draw engine.
+ * When used the draw engine must implement #DrawEngineType.instance_free callback.
+ */
+ void *instance_data;
+
char info[GPU_INFO_SIZE];
/* we may want to put this elsewhere */
@@ -100,6 +106,11 @@ typedef struct DefaultTextureList {
typedef struct DRWViewData DRWViewData;
+/**
+ * Creates a view data with all possible engines type for this view.
+ *
+ * `engine_types` contains #DRWRegisteredDrawEngine.
+ */
DRWViewData *DRW_view_data_create(ListBase *engine_types);
void DRW_view_data_free(DRWViewData *view_data);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index d1ffef4fe92..7d21804c08f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -168,7 +168,9 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract Struct
* \{ */
+
/* TODO(jbakker): move parameters inside a struct. */
+
typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
BMLoop **elt,
const int elt_index,
@@ -241,6 +243,11 @@ typedef struct MeshExtract {
/** \} */
/* draw_cache_extract_mesh_render_data.c */
+
+/**
+ * \param is_mode_active: When true, use the modifiers from the edit-data,
+ * otherwise don't use modifiers as they are not from this object.
+ */
MeshRenderData *mesh_render_data_create(Mesh *me,
const bool is_editmode,
const bool is_paint_mode,
@@ -258,6 +265,9 @@ void mesh_render_data_update_loose_geom(MeshRenderData *mr,
void mesh_render_data_update_polys_sorted(MeshRenderData *mr,
MeshBufferCache *cache,
const eMRDataType data_flag);
+/**
+ * Part of the creation of the #MeshRenderData that happens in a thread.
+ */
void mesh_render_data_update_looptris(MeshRenderData *mr,
const eMRIterType iter_type,
const eMRDataType data_flag);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index d06fb91411e..4cc9a875f79 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
@@ -388,5 +388,3 @@ const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_
const MeshExtract extract_edituv_points = blender::draw::create_extractor_edituv_points();
const MeshExtract extract_edituv_fdots = blender::draw::create_extractor_edituv_fdots();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
index ea58e1aeed8..2e8b85250f3 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc
@@ -110,10 +110,9 @@ constexpr MeshExtract create_extractor_fdots()
}
/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_fdots = blender::draw::create_extractor_fdots();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
index 522afcd44a1..e7dabfa9ee2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
@@ -173,8 +173,6 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
#undef NO_EDGE
-/** \} */
-
constexpr MeshExtract create_extractor_lines_adjacency()
{
MeshExtract extractor = {nullptr};
@@ -189,10 +187,10 @@ constexpr MeshExtract create_extractor_lines_adjacency()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_lines_adjacency = blender::draw::create_extractor_lines_adjacency();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
index 494a43e97d1..f7eb5022cdc 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc
@@ -103,8 +103,6 @@ static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->select_map);
}
-/** \} */
-
constexpr MeshExtract create_extractor_lines_paint_mask()
{
MeshExtract extractor = {nullptr};
@@ -118,10 +116,10 @@ constexpr MeshExtract create_extractor_lines_paint_mask()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_lines_paint_mask = blender::draw::create_extractor_lines_paint_mask();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index b801ba04162..01e14a004ed 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -32,6 +32,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Point Indices
* \{ */
+
static void extract_points_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
@@ -173,10 +174,10 @@ constexpr MeshExtract create_extractor_points()
return extractor;
}
+/** \} */
+
} // namespace blender::draw
extern "C" {
const MeshExtract extract_points = blender::draw::create_extractor_points();
}
-
-/** \} */
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
index fed66f0057d..b2ebff08abf 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc
@@ -28,6 +28,7 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots Normal and edit flag
* \{ */
+
#define NOR_AND_FLAG_DEFAULT 0
#define NOR_AND_FLAG_SELECT 1
#define NOR_AND_FLAG_ACTIVE -1
@@ -114,6 +115,7 @@ constexpr MeshExtract create_extractor_fdots_nor()
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots High Quality Normal and edit flag
* \{ */
+
static void extract_fdots_nor_hq_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
index f9f66c27aaa..3c3ac7a7a0a 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
@@ -121,6 +121,7 @@ constexpr MeshExtract create_extractor_lnor()
}
/** \} */
+
/* ---------------------------------------------------------------------- */
/** \name Extract HQ Loop Normal
* \{ */
diff --git a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
index 0ecfc397e95..bf59972fbaa 100644
--- a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl
@@ -296,7 +296,7 @@ NOTE the other tuning knobs are now in the shader function inputs!
/* (#B1#) */
float FxaaLuma(vec4 rgba)
{
- /* note: sqrt because the sampled colors are in a linear colorspace!
+ /* NOTE: sqrt because the sampled colors are in a linear colorspace!
* this approximates a perceptual conversion, which is good enough for the
* algorithm */
return sqrt(dot(rgba.rgb, vec3(0.2126, 0.7152, 0.0722)));
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index a980b87821a..e9912ba7d9a 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -179,7 +179,7 @@ uniform mat4 ModelMatrixInverse;
* transpose(ViewMatrixInverse) * transpose(ModelMatrixInverse)
*
* Knowing that the view matrix is orthogonal, the transpose is also the inverse.
- * Note: This is only valid because we are only using the mat3 of the ViewMatrixInverse.
+ * NOTE: This is only valid because we are only using the mat3 of the ViewMatrixInverse.
* ViewMatrix * transpose(ModelMatrixInverse)
*/
#define NormalMatrix transpose(mat3(ModelMatrixInverse))
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index d9f52d90766..6fa4d94df3a 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -70,3 +70,15 @@ endif()
blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ keyframes_keylist_test.cc
+ )
+ set(TEST_INC
+ )
+ set(TEST_LIB
+ )
+ include(GTestTesting)
+ blender_add_test_lib(bf_editor_animation_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
+endif()
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 9f2681fbf7a..2eaa42ee578 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -4158,7 +4158,6 @@ static void ANIM_init_channel_typeinfo_data(void)
}
}
-/* Get type info from given channel type */
const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
{
/* Sanity checks. */
@@ -4179,7 +4178,6 @@ const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
/* --------------------------- */
-/* Print debug info string for the given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
{
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -4212,11 +4210,25 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
}
}
+bAction *ANIM_channel_action_get(const bAnimListElem *ale)
+{
+ if (ale->datatype == ALE_ACT) {
+ return (bAction *)ale->key_data;
+ }
+
+ if (ELEM(ale->type, ANIMTYPE_GROUP, ANIMTYPE_FCURVE)) {
+ ID *owner = ale->fcurve_owner_id;
+
+ if (owner && GS(owner->name) == ID_AC) {
+ return (bAction *)owner;
+ }
+ }
+
+ return NULL;
+}
+
/* --------------------------- */
-/* Check if some setting for a channel is enabled
- * Returns: 1 = On, 0 = Off, -1 = Invalid
- */
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -4299,10 +4311,6 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChanne
} \
(void)0
-/* Change value of some setting for a channel
- * - setting: eAnimChannel_Settings
- * - mode: eAnimChannels_SetFlag
- */
void ANIM_channel_setting_set(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting,
@@ -4376,7 +4384,6 @@ static bool achannel_is_being_renamed(const bAnimContext *ac,
return false;
}
-/* Draw the given channel */
void ANIM_channel_draw(
bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
{
@@ -5132,7 +5139,6 @@ static void draw_setting_widget(bAnimContext *ac,
}
}
-/* Draw UI widgets the given channel */
void ANIM_channel_draw_widgets(const bContext *C,
bAnimContext *ac,
bAnimListElem *ale,
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 69fabd004cc..b97837a76b9 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -74,8 +74,6 @@
/* -------------------------- Selection ------------------------------------- */
-/* Set the given animation-channel as the active one for the active context */
-/* TODO: extend for animdata types... */
void ANIM_set_active_channel(bAnimContext *ac,
void *data,
eAnimCont_Types datatype,
@@ -83,6 +81,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
void *channel_data,
eAnim_ChannelType channel_type)
{
+ /* TODO: extend for animdata types. */
+
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -460,7 +460,6 @@ static void anim_channels_select_set(bAnimContext *ac,
}
}
-/* Set selection state of all animation channels in the context. */
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
{
ListBase anim_data = anim_channels_for_selection(ac);
@@ -468,7 +467,6 @@ void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
ANIM_animdata_freelist(&anim_data);
}
-/* Toggle selection state of all animation channels in the context. */
void ANIM_anim_channels_select_toggle(bAnimContext *ac)
{
ListBase anim_data = anim_channels_for_selection(ac);
@@ -588,15 +586,6 @@ static void anim_flush_channel_setting_down(bAnimContext *ac,
}
}
-/* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
- * - anim_data: list of the all the anim channels that can be chosen
- * -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
- * then the channels under closed expanders get ignored...
- * - ale_setting: the anim channel (not in the anim_data list directly, though occurring there)
- * with the new state of the setting that we want flushed up/down the hierarchy
- * - setting: type of setting to set
- * - on: whether the visibility setting has been enabled or disabled
- */
void ANIM_flush_setting_anim_channels(bAnimContext *ac,
ListBase *anim_data,
bAnimListElem *ale_setting,
@@ -652,7 +641,6 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac,
/* -------------------------- F-Curves ------------------------------------- */
-/* Delete the given F-Curve from its AnimData block */
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu)
{
/* - if no AnimData, we've got nowhere to remove the F-Curve from
@@ -708,8 +696,6 @@ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *f
BKE_fcurve_free(fcu);
}
-/* If the action has no F-Curves, unlink it from AnimData if it did not
- * come from a NLA Strip being tweaked. */
bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt)
{
if (adt->action != NULL) {
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 088de80bb65..7a34d8b542a 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -56,9 +56,6 @@
/* **************************** depsgraph tagging ******************************** */
-/* tags the given anim list element for refreshes (if applicable)
- * due to Animation Editor editing
- */
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
{
ID *id;
@@ -114,8 +111,6 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
}
}
-/* tags the given ID block for refreshes (if applicable) due to
- * Animation Editor editing */
void ANIM_id_update(Main *bmain, ID *id)
{
if (id) {
@@ -276,7 +271,6 @@ static void animchan_sync_gplayer(bAnimListElem *ale)
/* ---------------- */
-/* Main call to be exported to animation editors */
void ANIM_sync_animchannels_to_data(const bContext *C)
{
bAnimContext ac;
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 993d10cf303..6589756c526 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -63,7 +63,6 @@
/* *************************************************** */
/* CURRENT FRAME DRAWING */
-/* General call for drawing current frame indicator in animation editor */
void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
{
Scene *scene = CTX_data_scene(C);
@@ -92,7 +91,6 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
/* PREVIEW RANGE 'CURTAINS' */
/* NOTE: 'Preview Range' tools are defined in `anim_ops.c`. */
-/* Draw preview range 'curtains' for highlighting where the animation data is */
void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
{
Scene *scene = CTX_data_scene(C);
@@ -127,11 +125,6 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
/* *************************************************** */
/* SCENE FRAME RANGE */
-/**
- * Draw frame range guides (for scene frame range) in background.
- *
- * TODO: Should we still show these when preview range is enabled?
- */
void ANIM_draw_framerange(Scene *scene, View2D *v2d)
{
/* draw darkened area outside of active timeline frame range */
@@ -168,14 +161,73 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d)
immUnbindProgram();
}
+void ANIM_draw_action_framerange(
+ AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
+{
+ if ((action->flag & ACT_FRAME_RANGE) == 0) {
+ return;
+ }
+
+ /* Compute the dimensions. */
+ CLAMP_MIN(ymin, v2d->cur.ymin);
+ CLAMP_MAX(ymax, v2d->cur.ymax);
+
+ if (ymin > ymax) {
+ return;
+ }
+
+ const float sfra = BKE_nla_tweakedit_remap(adt, action->frame_start, NLATIME_CONVERT_MAP);
+ const float efra = BKE_nla_tweakedit_remap(adt, action->frame_end, NLATIME_CONVERT_MAP);
+
+ /* Diagonal stripe filled area outside of the frame range. */
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES);
+
+ float color[4];
+ UI_GetThemeColorShadeAlpha4fv(TH_BACK, -40, -50, color);
+
+ immUniform4f("color1", color[0], color[1], color[2], color[3]);
+ immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f);
+ immUniform1i("size1", 2 * U.dpi_fac);
+ immUniform1i("size2", 4 * U.dpi_fac);
+
+ if (sfra < efra) {
+ immRectf(pos, v2d->cur.xmin, ymin, sfra, ymax);
+ immRectf(pos, efra, ymin, v2d->cur.xmax, ymax);
+ }
+ else {
+ immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax, ymax);
+ }
+
+ immUnbindProgram();
+
+ GPU_blend(GPU_BLEND_NONE);
+
+ /* Thin lines where the actual frames are. */
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -60);
+
+ GPU_line_width(1.0f);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, sfra, ymin);
+ immVertex2f(pos, sfra, ymax);
+
+ immVertex2f(pos, efra, ymin);
+ immVertex2f(pos, efra, ymax);
+
+ immEnd();
+ immUnbindProgram();
+}
+
/* *************************************************** */
/* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes). */
-/**
- * Obtain the AnimData block providing NLA-mapping for the given channel (if applicable).
- *
- * TODO: do not supply return this if the animdata tells us that there is no mapping to perform.
- */
AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
{
/* sanity checks */
@@ -251,10 +303,6 @@ static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve
- * - restore = whether to map points back to non-mapped time
- * - only_keys = whether to only adjust the location of the center point of beztriples
- */
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
{
KeyframeEditData ked = {{NULL}};
@@ -282,7 +330,6 @@ void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, boo
/* *************************************************** */
/* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
-/* Get flags used for normalization in ANIM_unit_mapping_get_factor. */
short ANIM_get_normalization_flags(bAnimContext *ac)
{
if (ac->sl->spacetype == SPACE_GRAPH) {
@@ -450,7 +497,6 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
return factor;
}
-/* Get unit conversion factor for given ID + F-Curve */
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
{
if (flag & ANIM_UNITCONV_NORMALIZE) {
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index e1d046428a8..c1a09b9d21f 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -362,11 +362,6 @@ static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla)
/* ----------- Public API --------------- */
-/* Obtain current anim-data context,
- * given that context info from Blender context has already been set:
- * - AnimContext to write to is provided as pointer to var on stack so that we don't have
- * allocation/freeing costs (which are not that avoidable with channels).
- */
bool ANIM_animdata_context_getdata(bAnimContext *ac)
{
SpaceLink *sl = ac->sl;
@@ -397,11 +392,6 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac)
return (ok && ac->data);
}
-/* Obtain current anim-data context from Blender Context info
- * - AnimContext to write to is provided as pointer to var on stack so that we don't have
- * allocation/freeing costs (which are not that avoidable with channels).
- * - Clears data and sets the information from Blender Context which is useful
- */
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
{
Main *bmain = CTX_data_main(C);
@@ -1900,7 +1890,8 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* Layer visibility - we check both object and base,
* since these may not be in sync yet. */
- if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0 ||
+ (base->flag & BASE_VISIBLE_VIEWLAYER) == 0) {
continue;
}
@@ -3459,14 +3450,6 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data)
/* ----------- Public API --------------- */
-/**
- * This function filters the active data source to leave only animation channels suitable for
- * usage by the caller. It will return the length of the list
- *
- * \param anim_data: Is a pointer to a #ListBase,
- * to which the filtered animation channels will be placed for use.
- * \param filter_mode: how should the data be filtered - bit-mapping accessed flags.
- */
size_t ANIM_animdata_filter(bAnimContext *ac,
ListBase *anim_data,
eAnimFilter_Flags filter_mode,
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index 05837ed17b9..0315b93508b 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -43,14 +43,6 @@
/* ----------------------- Getter functions ----------------------- */
-/**
- * Write into "name" buffer, the name of the property
- * (retrieved using RNA from the curve's settings),
- * and return the icon used for the struct that this property refers to
- *
- * \warning name buffer we're writing to cannot exceed 256 chars
- * (check anim_channels_defines.c for details).
- */
int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
{
int icon = 0;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index e12433f4d4c..baf3eaae8e2 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -99,13 +99,11 @@ static ListBase *context_get_markers(Scene *scene, ScrArea *area)
/* ............. */
-/* public API for getting markers from context */
ListBase *ED_context_get_markers(const bContext *C)
{
return context_get_markers(CTX_data_scene(C), CTX_wm_area(C));
}
-/* public API for getting markers from "animation" context */
ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
{
if (ac) {
@@ -116,17 +114,6 @@ ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
/* --------------------------------- */
-/**
- * Apply some transformation to markers after the fact
- *
- * \param markers: List of markers to affect - this may or may not be the scene markers list,
- * so don't assume anything.
- * \param scene: Current scene (for getting current frame)
- * \param mode: (TfmMode) transform mode that this transform is for
- * \param value: From the transform code, this is `t->vec[0]`
- * (which is delta transform for grab/extend, and scale factor for scale)
- * \param side: (B/L/R) for 'extend' functionality, which side of current frame to use
- */
int ED_markers_post_apply_transform(
ListBase *markers, Scene *scene, int mode, float value, char side)
{
@@ -168,8 +155,6 @@ int ED_markers_post_apply_transform(
/* --------------------------------- */
-/* Get the marker that is closest to this point */
-/* XXX for select, the min_dist should be small */
TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x)
{
TimeMarker *marker, *nearest = NULL;
@@ -189,7 +174,6 @@ TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x)
return nearest;
}
-/* Return the time of the marker that occurs on a frame closest to the given time */
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
{
TimeMarker *nearest = ED_markers_find_nearest_marker(markers, x);
@@ -323,10 +307,6 @@ static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only
cen->sel = marker->flag;
}
-/* This function makes a list of all the markers. The only_sel
- * argument is used to specify whether only the selected markers
- * are added.
- */
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
{
TimeMarker *marker;
@@ -375,7 +355,6 @@ void ED_markers_deselect_all(ListBase *markers, int action)
/* --------------------------------- */
-/* Get the first selected marker */
TimeMarker *ED_markers_get_first_selected(ListBase *markers)
{
TimeMarker *marker;
@@ -393,12 +372,11 @@ TimeMarker *ED_markers_get_first_selected(ListBase *markers)
/* --------------------------------- */
-/* Print debugging prints of list of markers
- * BSI's: do NOT make static or put in if-defs as "unused code".
- * That's too much trouble when we need to use for quick debugging!
- */
void debug_markers_print_list(ListBase *markers)
{
+ /* NOTE: do NOT make static or put in if-defs as "unused code".
+ * That's too much trouble when we need to use for quick debugging! */
+
TimeMarker *marker;
if (markers == NULL) {
@@ -564,7 +542,6 @@ static void get_marker_clip_frame_range(View2D *v2d, float xscale, int r_range[2
r_range[1] = v2d->cur.xmax + font_width_max;
}
-/* Draw Scene-Markers in time window */
void ED_markers_draw(const bContext *C, int flag)
{
ListBase *markers = ED_context_get_markers(C);
@@ -1699,7 +1676,6 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
/* ************************** registration **********************************/
-/* called in screen_ops.c:ED_operatortypes_screen() */
void ED_operatortypes_marker(void)
{
WM_operatortype_append(MARKER_OT_add);
@@ -1716,7 +1692,6 @@ void ED_operatortypes_marker(void)
#endif
}
-/* called in screen_ops.c:ED_keymap_screen() */
void ED_keymap_marker(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "Markers", 0, 0);
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index 335034fef6e..d4a8e7921d6 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -99,12 +99,10 @@ Depsgraph *animviz_depsgraph_build(Main *bmain,
return depsgraph;
}
-/* get list of motion paths to be baked for the given object
- * - assumes the given list is ready to be used
- */
-/* TODO: it would be nice in future to be able to update objects dependent on these bones too? */
void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
{
+ /* TODO: it would be nice in future to be able to update objects dependent on these bones too? */
+
MPathTarget *mpt;
/* object itself first */
@@ -356,12 +354,6 @@ static void motionpath_free_free_tree_data(ListBase *targets)
}
}
-/* Perform baking of the given object's and/or its bones' transforms to motion paths
- * - scene: current scene
- * - ob: object whose flagged motion-paths should get calculated
- * - recalc: whether we need to
- */
-/* TODO: include reports pointer? */
void animviz_calc_motionpaths(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
@@ -369,6 +361,8 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
eAnimvizCalcRange range,
bool restore)
{
+ /* TODO: include reports pointer? */
+
/* Sanity check. */
if (ELEM(NULL, targets, targets->first)) {
return;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index dbf379971fa..e99e4a63786 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -61,9 +61,6 @@
/* ************************************************** */
/* Animation Data Validation */
-/* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *verify_driver_fcurve(ID *id,
const char rna_path[],
const int array_index,
@@ -295,17 +292,6 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
return (fcu != NULL);
}
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block,
- * and make it be driven by the specified target.
- *
- * This is intended to be used in conjunction with a modal "eyedropper"
- * for picking the variable that is going to be used to drive this one.
- *
- * - flag: eCreateDriverFlags
- * - driver_type: eDriver_Types
- * - mapping_type: eCreateDriver_MappingTypes
- */
int ANIM_add_driver_with_target(ReportList *reports,
ID *dst_id,
const char dst_path[],
@@ -420,10 +406,6 @@ int ANIM_add_driver_with_target(ReportList *reports,
/* --------------------------------- */
-/**
- * Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block
- */
int ANIM_add_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type)
{
@@ -546,9 +528,6 @@ int ANIM_add_driver(
return done_tot;
}
-/* Main Driver Management API calls:
- * Remove the driver for the specified property on the given ID block (if available)
- */
bool ANIM_remove_driver(ReportList *UNUSED(reports),
ID *id,
const char rna_path[],
@@ -603,7 +582,6 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
/* Copy/Paste Buffer for Driver Data... */
static FCurve *channeldriver_copypaste_buf = NULL;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_drivers_copybuf_free(void)
{
/* free the buffer F-Curve if it exists, as if it were just another F-Curve */
@@ -613,7 +591,6 @@ void ANIM_drivers_copybuf_free(void)
channeldriver_copypaste_buf = NULL;
}
-/* Checks if there is a driver in the copy/paste buffer */
bool ANIM_driver_can_paste(void)
{
return (channeldriver_copypaste_buf != NULL);
@@ -621,9 +598,6 @@ bool ANIM_driver_can_paste(void)
/* ------------------- */
-/* Main Driver Management API calls:
- * Make a copy of the driver for the specified property on the given ID block
- */
bool ANIM_copy_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
{
@@ -672,10 +646,6 @@ bool ANIM_copy_driver(
return 0;
}
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block or replace an existing one
- * with the driver + driver-curve data from the buffer
- */
bool ANIM_paste_driver(
ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
{
@@ -733,7 +703,6 @@ bool ANIM_paste_driver(
/* Copy/Paste Buffer for Driver Variables... */
static ListBase driver_vars_copybuf = {NULL, NULL};
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_driver_vars_copybuf_free(void)
{
/* Free the driver variables kept in the buffer */
@@ -750,7 +719,6 @@ void ANIM_driver_vars_copybuf_free(void)
BLI_listbase_clear(&driver_vars_copybuf);
}
-/* Checks if there are driver variables in the copy/paste buffer */
bool ANIM_driver_vars_can_paste(void)
{
return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
@@ -758,7 +726,6 @@ bool ANIM_driver_vars_can_paste(void)
/* -------------------------------------------------- */
-/* Copy the given driver's variables to the buffer */
bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
{
/* sanity checks */
@@ -781,7 +748,6 @@ bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
}
-/* Paste the variables in the buffer to the given FCurve */
bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
{
ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
@@ -837,8 +803,6 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
/* -------------------------------------------------- */
-/* Create a driver & variable that reads the specified property,
- * and store it in the buffers for Paste Driver and Paste Variables. */
void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name)
{
/* Clear copy/paste buffer first (for consistency with other copy/paste buffers). */
@@ -882,13 +846,8 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
/* Add Driver - Enum Defines ------------------------- */
-/**
- * Mapping Types enum for operators.
- * \note Used by #ANIM_OT_driver_button_add and #UI_OT_eyedropper_driver.
- *
- * XXX: These names need reviewing.
- */
EnumPropertyItem prop_driver_create_mapping_types[] = {
+ /* XXX: These names need reviewing. */
{CREATEDRIVER_MAPPING_1_N,
"SINGLE_MANY",
0,
@@ -920,10 +879,10 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
};
/* Filtering callback for driver mapping types enum */
-static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C,
- PointerRNA *UNUSED(owner_ptr),
- PropertyRNA *UNUSED(owner_prop),
- bool *r_free)
+static const EnumPropertyItem *driver_mapping_type_itemf(bContext *C,
+ PointerRNA *UNUSED(owner_ptr),
+ PropertyRNA *UNUSED(owner_prop),
+ bool *r_free)
{
EnumPropertyItem *input = prop_driver_create_mapping_types;
EnumPropertyItem *item = NULL;
@@ -1080,7 +1039,7 @@ static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
0,
"Mapping Type",
"Method used to match target and driven properties");
- RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
+ RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemf);
}
/* Add Driver Button Operator ------------------------ */
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index b94ee68e276..c4d8484e6a8 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -891,9 +891,6 @@ static void panel_register_stepped(ARegionType *region_type,
/** \name Panel Creation
* \{ */
-/**
- * Checks if the panels match the active strip / curve, rebuilds them if they don't.
- */
void ANIM_fmodifier_panels(const bContext *C,
ID *owner_id,
ListBase *fmodifiers,
@@ -969,17 +966,12 @@ static ListBase fmodifier_copypaste_buf = {NULL, NULL};
/* ---------- */
-/* free the copy/paste buffer */
void ANIM_fmodifiers_copybuf_free(void)
{
/* just free the whole buffer */
free_fmodifiers(&fmodifier_copypaste_buf);
}
-/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
- * - active: only copy the active modifier
- */
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
{
bool ok = true;
@@ -1009,9 +1001,6 @@ bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
return ok;
}
-/* 'Paste' the F-Modifier(s) from the buffer to the specified list
- * - replace: free all the existing modifiers to leave only the pasted ones
- */
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
{
FModifier *fcm;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 0923d490110..145d67b7810 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -67,10 +67,6 @@
/* --------------------------- Base Functions ------------------------------------ */
-/* This function is used to loop over BezTriples in the given F-Curve, applying a given
- * operation on them, and optionally applies an F-Curve validation function afterwards.
- */
-/* TODO: make this function work on samples too. */
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
FCurve *fcu,
KeyframeEditFunc key_ok,
@@ -378,7 +374,6 @@ static short summary_keyframes_loop(KeyframeEditData *ked,
/* --- */
-/* This function is used to apply operation to all keyframes, regardless of the type */
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
bDopeSheet *ads,
bAnimListElem *ale,
@@ -416,8 +411,6 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
return 0;
}
-/* This function is used to apply operation to all keyframes,
- * regardless of the type without needed an AnimListElem wrapper */
short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
bDopeSheet *ads,
void *data,
@@ -477,8 +470,6 @@ void ANIM_animdata_keyframe_callback(bAnimContext *ac,
/* ************************************************************************** */
/* Keyframe Integrity Tools */
-/* Rearrange keyframes if some are out of order */
-/* used to be recalc_*_ipos() where * was object or action */
void ANIM_editkeyframes_refresh(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -620,9 +611,6 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/**
- * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
- */
bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
@@ -683,9 +671,6 @@ static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/**
- * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
- */
bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
@@ -787,10 +772,6 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
/* ******************************************* */
/* Assorted Utility Functions */
-/**
- * Helper callback for <animeditor>_cfrasnap_exec() ->
- * used to help get the average time of all selected beztriples
- */
short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
{
/* only if selected */
@@ -810,8 +791,6 @@ short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* helper callback for columnselect_<animeditor>_keys() -> populate
- * list CfraElems with frame numbers from selected beztriples */
short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
{
/* only if selected */
@@ -825,9 +804,6 @@ short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* used to remap times from one range to another
- * requires: ked->data = KeyframeEditCD_Remap
- */
void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
{
KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data;
@@ -1024,8 +1000,6 @@ static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* NOTE: for markers and 'value', the values to use must be supplied as the first float value. */
-/* calchandles_fcurve */
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode)
{
switch (mode) {
@@ -1183,8 +1157,6 @@ static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
-/* Set all selected Bezier Handles to a single type */
-/* calchandles_fcurve */
KeyframeEditFunc ANIM_editkeyframes_handles(short mode)
{
switch (mode) {
@@ -1311,8 +1283,6 @@ static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
-/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
-/* ANIM_editkeyframes_ipocurve_ipotype() ! */
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
{
switch (mode) {
@@ -1391,7 +1361,6 @@ static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *b
return 0;
}
-/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_keytype(short mode)
{
switch (mode) {
@@ -1447,7 +1416,6 @@ static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *b
return 0;
}
-/* Set the easing type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
{
switch (mode) {
@@ -1638,7 +1606,6 @@ static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
-/* Get callback for building selection map */
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
{
switch (mode) {
@@ -1653,7 +1620,6 @@ KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
/* ----------- */
-/* flush selection map values to the given beztriple */
short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
{
const char *map = ked->data;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index ec33a42af3b..dc5d71b5a1e 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -63,11 +63,6 @@
/* **************************************************** */
-/**
- * Only delete the nominated keyframe from provided F-Curve.
- * Not recommended to be used many times successively. For that
- * there is #delete_fcurve_keys().
- */
void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
{
/* sanity check */
@@ -101,7 +96,6 @@ void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
}
}
-/* Delete selected keyframes in given F-Curve */
bool delete_fcurve_keys(FCurve *fcu)
{
bool changed = false;
@@ -140,7 +134,6 @@ void clear_fcurve_keys(FCurve *fcu)
/* ---------------- */
-/* duplicate selected keyframes for the given F-Curve */
void duplicate_fcurve_keys(FCurve *fcu)
{
/* this can only work when there is an F-Curve, and also when there are some BezTriples */
@@ -176,10 +169,6 @@ void duplicate_fcurve_keys(FCurve *fcu)
/* **************************************************** */
/* Various Tools */
-/**
- * Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on
- * linear-segments only optionally clears up curve if one keyframe with default value remains.
- */
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
{
FCurve *fcu = (FCurve *)ale->key_data;
@@ -318,6 +307,44 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
}
}
+/** Find the first segment of consecutive selected curve points, starting from \a start_index.
+ * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected.
+ * \param r_segment_start_idx: returns the start index of the segment.
+ * \param r_segment_len: returns the number of curve points in the segment.
+ * \return whether such a segment was found or not.*/
+static bool find_fcurve_segment(FCurve *fcu,
+ const int start_index,
+ int *r_segment_start_idx,
+ int *r_segment_len)
+{
+ *r_segment_start_idx = 0;
+ *r_segment_len = 0;
+
+ bool in_segment = false;
+
+ for (int i = start_index; i < fcu->totvert; i++) {
+ const bool point_is_selected = fcu->bezt[i].f2 & SELECT;
+ const bool point_is_ignored = fcu->bezt[i].f2 & BEZT_FLAG_IGNORE_TAG;
+
+ if (point_is_selected && !point_is_ignored) {
+ if (!in_segment) {
+ *r_segment_start_idx = i;
+ in_segment = true;
+ }
+ (*r_segment_len)++;
+ }
+ else if (in_segment) {
+ /* If the curve point is not selected then we have reached the end of the selected curve
+ * segment. */
+ return true; /* Segment found. */
+ }
+ }
+
+ /* If the last curve point was in the segment, `r_segment_len` and `r_segment_start_idx`
+ * are already updated and true is returned. */
+ return in_segment;
+}
+
/* ---------------- */
/* Check if the keyframe interpolation type is supported */
@@ -391,17 +418,9 @@ static void decimate_fcurve_segment(FCurve *fcu,
target_fcurve_verts);
}
-/**
- * F-Curve 'decimate' function that removes a certain ratio of curve
- * points that will affect the curves overall shape the least.
- * If you want to remove based on a error margin, set remove_ratio to 1 and
- * simply specify the desired error_sq_max. Otherwise, set the error margin to
- * FLT_MAX.
- */
bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
{
FCurve *fcu = (FCurve *)ale->key_data;
-
/* Check if the curve actually has any points. */
if (fcu == NULL || fcu->bezt == NULL || fcu->totvert == 0) {
return true;
@@ -409,46 +428,26 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
BezTriple *old_bezts = fcu->bezt;
- /* Only decimate the individual selected curve segments. */
- int bezt_segment_start_idx = 0;
- int bezt_segment_len = 0;
-
- bool selected;
bool can_decimate_all_selected = true;
- bool in_segment = false;
for (int i = 0; i < fcu->totvert; i++) {
- selected = fcu->bezt[i].f2 & SELECT;
- /* Make sure that the temp flag is unset as we use it to determine what to remove. */
- fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
-
- if (selected && !prepare_for_decimate(fcu, i)) {
- /* This keyframe is not supported, treat them as if they were unselected. */
- selected = false;
+ /* Ignore keyframes that are not supported. */
+ if (!prepare_for_decimate(fcu, i)) {
can_decimate_all_selected = false;
+ fcu->bezt[i].f2 |= BEZT_FLAG_IGNORE_TAG;
}
-
- if (selected) {
- if (!in_segment) {
- bezt_segment_start_idx = i;
- in_segment = true;
- }
- bezt_segment_len++;
- }
- else if (in_segment) {
- /* If the curve point is not selected then we have reached the end of the selected curve
- * segment. */
- decimate_fcurve_segment(
- fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
- in_segment = false;
- bezt_segment_len = 0;
- }
+ /* Make sure that the temp flag is unset as we use it to determine what to remove. */
+ fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
}
- /* Did the segment run to the end of the curve? */
- if (in_segment) {
- decimate_fcurve_segment(
- fcu, bezt_segment_start_idx, bezt_segment_len, remove_ratio, error_sq_max);
+ /* Only decimate the individual selected curve segments. */
+ int segment_start_idx = 0;
+ int segment_len = 0;
+ int current_index = 0;
+
+ while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
+ decimate_fcurve_segment(fcu, segment_start_idx, segment_len, remove_ratio, error_sq_max);
+ current_index = segment_start_idx + segment_len;
}
uint old_totvert = fcu->totvert;
@@ -457,6 +456,7 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
for (int i = 0; i < old_totvert; i++) {
BezTriple *bezt = (old_bezts + i);
+ bezt->f2 &= ~BEZT_FLAG_IGNORE_TAG;
if ((bezt->f2 & BEZT_FLAG_TEMP_TAG) == 0) {
insert_bezt_fcurve(fcu, bezt, 0);
}
@@ -477,8 +477,6 @@ typedef struct tSmooth_Bezt {
float y1, y2, y3; /* averaged before/new/after y-values */
} tSmooth_Bezt;
-/* Use a weighted moving-means method to reduce intensity of fluctuations */
-/* TODO: introduce scaling factor for weighting falloff */
void smooth_fcurve(FCurve *fcu)
{
int totSel = 0;
@@ -582,7 +580,6 @@ typedef struct TempFrameValCache {
float frame, val;
} TempFrameValCache;
-/* Evaluates the curves between each selected keyframe on each frame, and keys the value. */
void sample_fcurve(FCurve *fcu)
{
BezTriple *bezt, *start = NULL, *end = NULL;
@@ -691,7 +688,6 @@ typedef struct tAnimCopybufItem {
bool is_bone; /* special flag for armature bones */
} tAnimCopybufItem;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ANIM_fcurves_copybuf_free(void)
{
tAnimCopybufItem *aci, *acn;
@@ -722,7 +718,6 @@ void ANIM_fcurves_copybuf_free(void)
/* ------------------- */
-/* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
{
bAnimListElem *ale;
@@ -1081,8 +1076,6 @@ static void paste_animedit_keys_fcurve(
calchandles_fcurve(fcu);
}
-/* ------------------- */
-
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
{KEYFRAME_PASTE_OFFSET_CFRA_START,
"START",
@@ -1115,11 +1108,6 @@ const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
{0, NULL, 0, NULL, NULL},
};
-/**
- * This function pastes data from the keyframes copy/paste buffer
- *
- * \return Status code is whether the method FAILED to do anything
- */
short paste_animedit_keys(bAnimContext *ac,
ListBase *anim_data,
const eKeyPasteOffset offset_mode,
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index 7d08e416d0d..8dae46766fa 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -109,7 +109,7 @@ struct AnimKeylist {
#endif
};
-AnimKeylist *ED_keylist_create(void)
+AnimKeylist *ED_keylist_create()
{
AnimKeylist *keylist = new AnimKeylist();
return keylist;
diff --git a/source/blender/editors/animation/keyframes_keylist_test.cc b/source/blender/editors/animation/keyframes_keylist_test.cc
new file mode 100644
index 00000000000..17a21be5ae8
--- /dev/null
+++ b/source/blender/editors/animation/keyframes_keylist_test.cc
@@ -0,0 +1,144 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_utildefines.h"
+
+#include "ED_keyframes_keylist.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_fcurve.h"
+
+#include <functional>
+#include <optional>
+
+namespace blender::editor::animation::tests {
+
+const float KEYLIST_NEAR_ERROR = 0.1;
+const float FRAME_STEP = 0.005;
+
+static void build_fcurve(FCurve &fcurve)
+{
+ fcurve.totvert = 3;
+ fcurve.bezt = static_cast<BezTriple *>(
+ MEM_callocN(sizeof(BezTriple) * fcurve.totvert, "BezTriples"));
+ fcurve.bezt[0].vec[1][0] = 10.f;
+ fcurve.bezt[0].vec[1][1] = 1.f;
+ fcurve.bezt[1].vec[1][0] = 20.f;
+ fcurve.bezt[1].vec[1][1] = 2.f;
+ fcurve.bezt[2].vec[1][0] = 30.f;
+ fcurve.bezt[2].vec[1][1] = 1.f;
+}
+
+static AnimKeylist *create_test_keylist()
+{
+ FCurve *fcurve = BKE_fcurve_create();
+ build_fcurve(*fcurve);
+
+ AnimKeylist *keylist = ED_keylist_create();
+ fcurve_to_keylist(nullptr, fcurve, keylist, 0);
+ BKE_fcurve_free(fcurve);
+
+ ED_keylist_prepare_for_direct_access(keylist);
+ return keylist;
+}
+
+static void assert_act_key_column(const ActKeyColumn *column,
+ const std::optional<float> expected_frame)
+{
+ if (expected_frame.has_value()) {
+ EXPECT_NE(column, nullptr);
+ EXPECT_NEAR(column->cfra, *expected_frame, KEYLIST_NEAR_ERROR);
+ }
+ else {
+ EXPECT_EQ(column, nullptr);
+ }
+}
+
+using KeylistFindFunction = std::function<const ActKeyColumn *(const AnimKeylist *, float)>;
+
+static float check_keylist_find_range(const AnimKeylist *keylist,
+ KeylistFindFunction keylist_find_func,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ float cfra = frame_from;
+ for (; cfra < frame_to; cfra += FRAME_STEP) {
+ const ActKeyColumn *found = keylist_find_func(keylist, cfra);
+ assert_act_key_column(found, expected_frame);
+ }
+ return cfra;
+}
+
+static float check_keylist_find_next_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_next, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_next)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_next_range(keylist, 0.0f, 9.99f, 10.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 19.99f, 20.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 29.99f, 30.0f);
+ cfra = check_keylist_find_next_range(keylist, cfra, 39.99f, std::nullopt);
+
+ ED_keylist_free(keylist);
+}
+
+static float check_keylist_find_prev_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_prev, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_prev)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_prev_range(keylist, 0.0f, 10.01f, std::nullopt);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 20.01f, 10.0f);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 30.01f, 20.0f);
+ cfra = check_keylist_find_prev_range(keylist, cfra, 49.99f, 30.0f);
+
+ ED_keylist_free(keylist);
+}
+
+static float check_keylist_find_exact_range(const AnimKeylist *keylist,
+ const float frame_from,
+ const float frame_to,
+ const std::optional<float> expected_frame)
+{
+ return check_keylist_find_range(
+ keylist, ED_keylist_find_exact, frame_from, frame_to, expected_frame);
+}
+
+TEST(keylist, find_exact)
+{
+ AnimKeylist *keylist = create_test_keylist();
+
+ float cfra = check_keylist_find_exact_range(keylist, 0.0f, 9.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 10.01f, 10.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 19.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 20.01f, 20.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 29.99f, std::nullopt);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 30.01f, 30.0f);
+ cfra = check_keylist_find_exact_range(keylist, cfra, 49.99f, std::nullopt);
+
+ ED_keylist_free(keylist);
+}
+
+} // namespace blender::editor::animation::tests
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 0a9f1a36a28..25d2f6c510b 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -35,6 +35,7 @@
#include "BLT_translation.h"
+#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
@@ -90,7 +91,6 @@ static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *k
/* ************************************************** */
/* Keyframing Setting Wrangling */
-/* Get the active settings for keyframing settings from context (specifically the given scene) */
eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_mode)
{
eInsertKeyFlags flag = INSERTKEY_NOFLAGS;
@@ -132,9 +132,6 @@ eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_m
/* ******************************************* */
/* Animation Data Validation */
-/* Get (or add relevant data to be able to do so) the Active Action for the given
- * Animation Data block, given an ID block where the Animation Data should reside.
- */
bAction *ED_id_action_ensure(Main *bmain, ID *id)
{
AnimData *adt;
@@ -176,10 +173,6 @@ bAction *ED_id_action_ensure(Main *bmain, ID *id)
return adt->action;
}
-/**
- * Find the F-Curve from the Active Action,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const int array_index)
{
/* Sanity checks. */
@@ -189,10 +182,6 @@ FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const
return BKE_fcurve_find(&act->curves, rna_path, array_index);
}
-/**
- * Get (or add relevant data to be able to do so) F-Curve from the Active Action,
- * for the given Animation Data block. This assumes that all the destinations are valid.
- */
FCurve *ED_action_fcurve_ensure(struct Main *bmain,
struct bAction *act,
const char group[],
@@ -294,9 +283,6 @@ static void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop)
}
}
-/* Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
- * but also through RNA when editing an ID prop, see T37103).
- */
void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, PointerRNA *ptr)
{
PointerRNA tmp_ptr;
@@ -375,6 +361,43 @@ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, fl
return type;
}
+/* Used to make curves newly added to a cyclic Action cycle with the correct period. */
+static void make_new_fcurve_cyclic(const bAction *act, FCurve *fcu)
+{
+ /* The curve must contain one (newly-added) keyframe. */
+ if (fcu->totvert != 1 || !fcu->bezt) {
+ return;
+ }
+
+ const float period = act->frame_end - act->frame_start;
+
+ if (period < 0.1f) {
+ return;
+ }
+
+ /* Move the keyframe into the range. */
+ const float frame_offset = fcu->bezt[0].vec[1][0] - act->frame_start;
+ const float fix = floorf(frame_offset / period) * period;
+
+ fcu->bezt[0].vec[0][0] -= fix;
+ fcu->bezt[0].vec[1][0] -= fix;
+ fcu->bezt[0].vec[2][0] -= fix;
+
+ /* Duplicate and offset the keyframe. */
+ fcu->bezt = MEM_reallocN(fcu->bezt, sizeof(BezTriple) * 2);
+ fcu->totvert = 2;
+
+ fcu->bezt[1] = fcu->bezt[0];
+ fcu->bezt[1].vec[0][0] += period;
+ fcu->bezt[1].vec[1][0] += period;
+ fcu->bezt[1].vec[2][0] += period;
+
+ /* Add the cycles modifier. */
+ if (!fcu->modifiers.first) {
+ add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu);
+ }
+}
+
/* -------------- BezTriple Insertion -------------------- */
/* Change the Y position of a keyframe to match the input, adjusting handles. */
@@ -395,13 +418,6 @@ static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
/* TODO: perform some other operations? */
}
-/* This function adds a given BezTriple to an F-Curve. It will allocate
- * memory for the array if needed, and will insert the BezTriple into a
- * suitable place in chronological order.
- *
- * NOTE: any recalculate of the F-Curve that needs to be done will need to
- * be done by the caller.
- */
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
{
int i = 0;
@@ -537,15 +553,6 @@ static void subdivide_nonauto_handles(const FCurve *fcu,
bezt->h1 = bezt->h2 = HD_ALIGN;
}
-/**
- * This function is a wrapper for #insert_bezt_fcurve(), and should be used when
- * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
- * It returns the index at which the keyframe was added.
- *
- * \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
- * \param flag: Optional flags (eInsertKeyFlags) for controlling how keys get added
- * and/or whether updates get done.
- */
int insert_vert_fcurve(
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
{
@@ -1235,19 +1242,6 @@ static bool insert_keyframe_value(ReportList *reports,
return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0;
}
-/* Secondary Keyframing API call:
- * Use this when validation of necessary animation data is not necessary,
- * since an RNA-pointer to the necessary data being keyframed,
- * and a pointer to the F-Curve to use have both been provided.
- *
- * This function can't keyframe quaternion channels on some NLA strip types.
- *
- * keytype is the "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet.
- *
- * The flag argument is used for special settings that alter the behavior of
- * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
- * and extra keyframe filtering.
- */
bool insert_keyframe_direct(ReportList *reports,
PointerRNA ptr,
PropertyRNA *prop,
@@ -1352,8 +1346,10 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
/* we may not have a F-Curve when we're replacing only... */
if (fcu) {
+ const bool is_new_curve = (fcu->totvert == 0);
+
/* set color mode if the F-Curve is new (i.e. without any keyframes) */
- if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) {
+ if (is_new_curve && (flag & INSERTKEY_XYZ2RGB)) {
/* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor,
* is determined by the array index for the F-Curve
*/
@@ -1366,12 +1362,26 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
}
}
+ /* If the curve has only one key, make it cyclic if appropriate. */
+ const bool is_cyclic_action = (flag & INSERTKEY_CYCLE_AWARE) && BKE_action_is_cyclic(act);
+
+ if (is_cyclic_action && fcu->totvert == 1) {
+ make_new_fcurve_cyclic(act, fcu);
+ }
+
/* update F-Curve flags to ensure proper behavior for property type */
update_autoflags_fcurve_direct(fcu, prop);
/* insert keyframe */
- return insert_keyframe_value(
+ const bool success = insert_keyframe_value(
reports, ptr, prop, fcu, anim_eval_context, curval, keytype, flag);
+
+ /* If the curve is new, make it cyclic if appropriate. */
+ if (is_cyclic_action && is_new_curve) {
+ make_new_fcurve_cyclic(act, fcu);
+ }
+
+ return success;
}
return false;
@@ -1399,19 +1409,6 @@ static AnimationEvalContext nla_time_remap(const AnimationEvalContext *anim_eval
return *anim_eval_context;
}
-/**
- * Main Keyframing API call
- *
- * Use this when validation of necessary animation data is necessary, since it may not exist yet.
- *
- * The flag argument is used for special settings that alter the behavior of
- * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
- * and extra keyframe filtering.
- *
- * index of -1 keys all array indices
- *
- * \return The number of key-frames inserted.
- */
int insert_keyframe(Main *bmain,
ReportList *reports,
ID *id,
@@ -1638,9 +1635,6 @@ static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt)
}
}
-/**
- * \return The number of key-frames deleted.
- */
int delete_keyframe(Main *bmain,
ReportList *reports,
ID *id,
@@ -1962,7 +1956,6 @@ void ANIM_OT_keyframe_insert(wmOperatorType *ot)
ot->prop = prop;
}
-/* Clone of 'ANIM_OT_keyframe_insert' which uses a name for the keying set instead of an enum. */
void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2757,7 +2750,6 @@ bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
/* --------------- API/Per-Datablock Handling ------------------- */
-/* Checks if some F-Curve has a keyframe for a given frame */
bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame, short filter)
{
/* quick sanity check */
@@ -2784,7 +2776,6 @@ bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame, short filter)
return false;
}
-/* Returns whether the current value of a given property differs from the interpolated value. */
bool fcurve_is_changed(PointerRNA ptr,
PropertyRNA *prop,
FCurve *fcu,
@@ -2913,7 +2904,6 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter)
/* --------------- API ------------------- */
-/* Checks whether a keyframe exists for the given ID-block one the given frame */
bool id_frame_has_keyframe(ID *id, float frame, short filter)
{
/* sanity checks */
@@ -2989,9 +2979,6 @@ bool ED_autokeyframe_pchan(
return false;
}
-/**
- * Use for auto-keyframing from the UI.
- */
bool ED_autokeyframe_property(
bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra)
{
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index e1fd3b07f46..59bb60d8fa0 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -529,12 +529,10 @@ void ANIM_OT_keying_set_active_set(wmOperatorType *ot)
/* Keying Set Type Info declarations */
static ListBase keyingset_type_infos = {NULL, NULL};
-/* Built-In Keying Sets (referencing type information). */
ListBase builtin_keyingsets = {NULL, NULL};
/* --------------- */
-/* Find KeyingSet type info given a name. */
KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[])
{
/* sanity checks */
@@ -546,7 +544,6 @@ KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[])
return BLI_findstring(&keyingset_type_infos, name, offsetof(KeyingSetInfo, idname));
}
-/* Find builtin KeyingSet by name. */
KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[])
{
KeyingSet *ks, *first = NULL;
@@ -582,8 +579,6 @@ KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[]
/* --------------- */
-/* Add the given KeyingSetInfo to the list of type infos,
- * and create an appropriate builtin set too. */
void ANIM_keyingset_info_register(KeyingSetInfo *ksi)
{
KeyingSet *ks;
@@ -603,8 +598,6 @@ void ANIM_keyingset_info_register(KeyingSetInfo *ksi)
BLI_addtail(&keyingset_type_infos, ksi);
}
-/* Remove the given KeyingSetInfo from the list of type infos,
- * and also remove the builtin set if appropriate. */
void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi)
{
KeyingSet *ks, *ksn;
@@ -633,8 +626,6 @@ void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi)
BLI_freelinkN(&keyingset_type_infos, ksi);
}
-/* --------------- */
-
void ANIM_keyingset_infos_exit(void)
{
KeyingSetInfo *ksi, *next;
@@ -654,7 +645,6 @@ void ANIM_keyingset_infos_exit(void)
BKE_keyingsets_free(&builtin_keyingsets);
}
-/* Check if the ID appears in the paths specified by the KeyingSet */
bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id)
{
/* sanity checks */
@@ -670,7 +660,6 @@ bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id)
/* Getters for Active/Indices ----------------------------- */
-/* Get the active Keying Set for the Scene provided */
KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene)
{
/* if no scene, we've got no hope of finding the Keying Set */
@@ -689,7 +678,6 @@ KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene)
return BLI_findlink(&builtin_keyingsets, (-scene->active_keyingset) - 1);
}
-/* Get the index of the Keying Set provided, for the given Scene */
int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks)
{
int index;
@@ -721,7 +709,6 @@ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks)
return 0;
}
-/* Get Keying Set to use for Auto-Keyframing some transforms */
KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName)
{
/* get KeyingSet to use
@@ -739,7 +726,6 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *tra
/* Menu of All Keying Sets ----------------------------- */
-/* Dynamically populate an enum of Keying Sets */
const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -808,14 +794,6 @@ const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
return item;
}
-/**
- * Get the keying set from enum values generated in #ANIM_keying_sets_enum_itemf.
- *
- * Type is the Keying Set the user specified to use when calling the operator:
- * - type == 0: use scene's active Keying Set
- * - type > 0: use a user-defined Keying Set from the active scene
- * - type < 0: use a builtin Keying Set
- */
KeyingSet *ANIM_keyingset_get_from_enum_type(Scene *scene, int type)
{
KeyingSet *ks = NULL;
@@ -847,7 +825,6 @@ KeyingSet *ANIM_keyingset_get_from_idname(Scene *scene, const char *idname)
/* Polling API ----------------------------------------------- */
-/* Check if KeyingSet can be used in the current context */
bool ANIM_keyingset_context_ok_poll(bContext *C, KeyingSet *ks)
{
if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
@@ -894,7 +871,6 @@ static void RKS_ITER_overrides_list(KeyingSetInfo *ksi,
}
}
-/* Add new data source for relative Keying Sets */
void ANIM_relative_keyingset_add_source(ListBase *dsources, ID *id, StructRNA *srna, void *data)
{
tRKS_DSource *ds;
@@ -925,14 +901,6 @@ void ANIM_relative_keyingset_add_source(ListBase *dsources, ID *id, StructRNA *s
/* KeyingSet Operations (Insert/Delete Keyframes) ------------ */
-/**
- * Given a KeyingSet and context info, validate Keying Set's paths.
- * This is only really necessary with relative/built-in KeyingSets
- * where their list of paths is dynamically generated based on the
- * current context info.
- *
- * Returns 0 if succeeded, otherwise an error code: eModifyKey_Returns
- */
eModifyKey_Returns ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
{
/* sanity check */
@@ -1017,14 +985,6 @@ static eInsertKeyFlags keyingset_apply_keying_flags(const eInsertKeyFlags base_f
return result;
}
-/**
- * Given a KeyingSet and context info (if required),
- * modify keyframes for the channels specified by the KeyingSet.
- * This takes into account many of the different combinations of using KeyingSets.
- *
- * \returns the number of channels that key-frames were added or
- * an #eModifyKey_Returns value (always a negative number).
- */
int ANIM_apply_keyingset(
bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
{
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 21a5c6c2865..02ecfdb4ea6 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -64,8 +64,6 @@
/* *************** Adding stuff in editmode *************** */
-/* default bone add, returns it selected, but without tail set */
-/* XXX should be used everywhere, now it mallocs bones still locally in functions */
EditBone *ED_armature_ebone_add(bArmature *arm, const char *name)
{
EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
@@ -274,7 +272,6 @@ void ARMATURE_OT_click_extrude(wmOperatorType *ot)
/* props */
}
-/* adds an EditBone between the nominated locations (should be in the right space) */
EditBone *add_points_bone(Object *obedit, float head[3], float tail[3])
{
EditBone *ebo;
@@ -302,7 +299,6 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
return NULL;
}
-/* Call this before doing any duplications. */
void preEditBoneDuplicate(ListBase *editbones)
{
/* clear temp */
@@ -1317,9 +1313,10 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* following conventions from #MESH_OT_symmetrize */
void ARMATURE_OT_symmetrize(wmOperatorType *ot)
{
+ /* NOTE: following conventions from #MESH_OT_symmetrize */
+
/* subset of 'rna_enum_symmetrize_direction_items' */
static const EnumPropertyItem arm_symmetrize_direction_items[] = {
{-1, "NEGATIVE_X", 0, "-X to +X", ""},
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index fd5ae6c7099..b709980cabe 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -66,9 +66,6 @@
/* NOTE: these functions are exported to the Object module to be called from the tools there */
-/**
- * See #BKE_armature_transform for object-mode transform.
- */
void ED_armature_edit_transform(bArmature *arm, const float mat[4][4], const bool do_props)
{
EditBone *ebone;
@@ -116,8 +113,6 @@ void ED_armature_transform(bArmature *arm, const float mat[4][4], const bool do_
}
}
-/* exported for use in editors/object/ */
-/* 0 == do center, 1 == center new, 2 == center cursor */
void ED_armature_origin_set(
Main *bmain, Object *ob, const float cursor[3], int centermode, int around)
{
@@ -186,9 +181,6 @@ void ED_armature_origin_set(
/** \name Bone Roll Calculate Operator
* \{ */
-/* adjust bone roll to align Z axis with vector
- * vec is in local space and is normalized
- */
float ED_armature_ebone_roll_to_vector(const EditBone *bone,
const float align_axis[3],
const bool axis_only)
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 3a6761ba915..97f8c0cf630 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -39,8 +39,10 @@ struct bArmature;
struct LinkData;
struct ListBase;
-/* ******************************************************* */
-/* Armature EditMode Operators */
+/* -------------------------------------------------------------------- */
+/** \name Armature EditMode Operators
+ * \{ */
+
void ARMATURE_OT_bone_primitive_add(struct wmOperatorType *ot);
void ARMATURE_OT_align(struct wmOperatorType *ot);
@@ -82,8 +84,12 @@ void ARMATURE_OT_layers_show_all(struct wmOperatorType *ot);
void ARMATURE_OT_armature_layers(struct wmOperatorType *ot);
void ARMATURE_OT_bone_layers(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose-Mode Operators */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose-Mode Operators
+ * \{ */
+
void POSE_OT_hide(struct wmOperatorType *ot);
void POSE_OT_reveal(struct wmOperatorType *ot);
@@ -131,8 +137,12 @@ void POSE_OT_quaternions_flip(struct wmOperatorType *ot);
void POSE_OT_bone_layers(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose Tool Utilities (for PoseLib, Pose Sliding, etc.) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Tool Utilities (for PoseLib, Pose Sliding, etc.)
+ * \{ */
+
/* pose_utils.c */
/* Temporary data linking PoseChannels with the F-Curves they affect */
@@ -173,21 +183,39 @@ typedef struct tPChanFCurveLink {
/* ----------- */
+/** Returns a valid pose armature for this object, else returns NULL. */
struct Object *poseAnim_object_get(struct Object *ob_);
+/** Get sets of F-Curves providing transforms for the bones in the Pose. */
void poseAnim_mapping_get(struct bContext *C, ListBase *pfLinks);
+/** Free F-Curve <-> PoseChannel links. */
void poseAnim_mapping_free(ListBase *pfLinks);
+/**
+ * Helper for apply() / reset() - refresh the data.
+ */
void poseAnim_mapping_refresh(struct bContext *C, struct Scene *scene, struct Object *ob);
+/**
+ * Reset changes made to current pose.
+ */
void poseAnim_mapping_reset(ListBase *pfLinks);
+/** Perform auto-key-framing after changes were made + confirmed. */
void poseAnim_mapping_autoKeyframe(struct bContext *C,
struct Scene *scene,
ListBase *pfLinks,
float cframe);
+/**
+ * Find the next F-Curve for a PoseChannel with matching path...
+ * - path is not just the pfl rna_path, since that path doesn't have property info yet.
+ */
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path);
-/* ******************************************************* */
-/* PoseLib */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name PoseLib
+ * \{ */
+
/* pose_lib.c */
void POSELIB_OT_new(struct wmOperatorType *ot);
@@ -207,8 +235,12 @@ void POSELIB_OT_apply_pose(struct wmOperatorType *ot);
void POSELIB_OT_apply_pose_asset(struct wmOperatorType *ot);
void POSELIB_OT_blend_pose_asset(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Pose Sliding Tools */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Sliding Tools
+ * \{ */
+
/* pose_slide.c */
void POSE_OT_push(struct wmOperatorType *ot);
@@ -220,8 +252,11 @@ void POSE_OT_blend_to_neighbors(struct wmOperatorType *ot);
void POSE_OT_propagate(struct wmOperatorType *ot);
-/* ******************************************************* */
-/* Various Armature Edit/Pose Editing API's */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Various Armature Edit/Pose Editing API's
+ * \{ */
/* Ideally, many of these defines would not be needed as everything would be strictly
* self-contained within each file,
@@ -232,7 +267,9 @@ struct EditBone *make_boneList(struct ListBase *edbo,
struct ListBase *bones,
struct Bone *actBone);
-/* duplicate method */
+/* Duplicate method. */
+
+/** Call this before doing any duplications. */
void preEditBoneDuplicate(struct ListBase *editbones);
void postEditBoneDuplicate(struct ListBase *editbones, struct Object *ob);
struct EditBone *duplicateEditBone(struct EditBone *cur_bone,
@@ -240,22 +277,37 @@ struct EditBone *duplicateEditBone(struct EditBone *cur_bone,
struct ListBase *editbones,
struct Object *ob);
-/* duplicate method (cross objects) */
-/* editbones is the target list */
+/* Duplicate method (cross objects). */
+
+/**
+ * \param editbones: The target list.
+ */
struct EditBone *duplicateEditBoneObjects(struct EditBone *cur_bone,
const char *name,
struct ListBase *editbones,
struct Object *src_ob,
struct Object *dst_ob);
+/** Adds an EditBone between the nominated locations (should be in the right space). */
struct EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
void armature_tag_select_mirrored(struct bArmature *arm);
+/**
+ * Helper function for tools to work on mirrored parts.
+ * it leaves mirrored bones selected then too, which is a good indication of what happened.
+ */
void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
+/** Only works when tagged. */
void armature_tag_unselect(struct bArmature *arm);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selection Picking
+ * \{ */
+
struct EditBone *ED_armature_pick_ebone(struct bContext *C,
const int xy[2],
bool findunsel,
@@ -291,7 +343,19 @@ struct Bone *ED_armature_pick_bone_from_selectbuffer(struct Base **bases,
bool do_nearest,
struct Base **r_base);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Iteration
+ * \{ */
+
+/**
+ * XXX: bone_looper is only to be used when we want to access settings
+ * (i.e. editability/visibility/selected) that context doesn't offer.
+ */
int bone_looper(struct Object *ob,
struct Bone *bone,
void *data,
int (*bone_func)(struct Object *, struct Bone *, void *));
+
+/** \} */
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index de1c14a15ce..750c64d74a7 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -80,7 +80,6 @@ static bool editbone_unique_check(void *arg, const char *name)
return dupli && dupli != data->bone;
}
-/* If bone is already in list, pass it as param to ignore it. */
void ED_armature_ebone_unique_name(ListBase *ebones, char *name, EditBone *bone)
{
struct {
@@ -154,9 +153,6 @@ static void constraint_bone_name_fix(Object *ob,
}
}
-/* called by UI for renaming a bone */
-/* warning: make sure the original bone was not renamed yet! */
-/* seems messy, but that's what you get with not using pointers but channel names :) */
void ED_armature_bone_rename(Main *bmain,
bArmature *arm,
const char *oldnamep,
@@ -269,6 +265,7 @@ void ED_armature_bone_rename(Main *bmain,
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
}
@@ -325,6 +322,7 @@ void ED_armature_bone_rename(Main *bmain,
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
+ DEG_id_tag_update(ob->data, ID_RECALC_GEOMETRY);
}
}
break;
@@ -393,16 +391,6 @@ typedef struct BoneFlipNameData {
char name_flip[MAXBONENAME];
} BoneFlipNameData;
-/**
- * Renames (by flipping) all selected bones at once.
- *
- * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
- * all the bones are safely renamed, without conflicting with each other.
- *
- * \param arm: Armature the bones belong to
- * \param bones_names: List of BoneConflict elems.
- * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
- */
void ED_armature_bones_flip_names(Main *bmain,
bArmature *arm,
ListBase *bones_names,
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index 75b0455d026..364e778fc2e 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -33,9 +33,10 @@
/* ************************** registration **********************************/
-/* Both operators ARMATURE_OT_xxx and POSE_OT_xxx here */
void ED_operatortypes_armature(void)
{
+ /* Both operators `ARMATURE_OT_*` and `POSE_OT_*` are registered here. */
+
/* EDIT ARMATURE */
WM_operatortype_append(ARMATURE_OT_bone_primitive_add);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index cac6e9965b6..eebe8a447f7 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -269,7 +269,6 @@ static void joined_armature_fix_links(
}
}
-/* join armature exec is exported for use in object->join objects operator... */
int ED_armature_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -929,7 +928,7 @@ static int armature_parent_set_invoke(bContext *C,
enable_connect = true;
break;
}
- else if (!(ebone->flag & BONE_CONNECTED)) {
+ if (!(ebone->flag & BONE_CONNECTED)) {
enable_connect = true;
}
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 937385f9ffa..5e4cb813064 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -139,7 +139,6 @@ Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases,
return base;
}
-/* For callers that don't need the pose channel. */
Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
uint bases_len,
int hit,
@@ -1080,7 +1079,6 @@ bool ED_armature_edit_select_pick_bone(bContext *C,
return true;
}
-/* context: editmode armature in view3d */
bool ED_armature_edit_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
@@ -1175,18 +1173,6 @@ static bool armature_edit_select_op_apply(bArmature *arm,
return changed;
}
-/**
- * Perform a selection operation on elements which have been 'touched',
- * use for lasso & border select but can be used elsewhere too.
- *
- * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
- * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
- * (used when the values are clipped outside the view).
- *
- * \param sel_op: #eSelectOp type.
- *
- * \note Visibility checks must be done by the caller.
- */
bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
{
bool changed = false;
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 4fe4422e4e0..1c48285563d 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -45,10 +45,10 @@
#include "armature_intern.h"
-/* *************************************************************** */
-/* Validation */
+/* -------------------------------------------------------------------- */
+/** \name Validation
+ * \{ */
-/* Sync selection to parent for connected children */
void ED_armature_edit_sync_selection(ListBase *edbo)
{
EditBone *ebo;
@@ -86,10 +86,6 @@ void ED_armature_edit_validate_active(struct bArmature *arm)
}
}
-/* Update the layers_used variable after bones are moved between layer
- * NOTE: Used to be done in drawing code in 2.7, but that won't work with
- * Copy-on-Write, as drawing uses evaluated copies.
- */
void ED_armature_edit_refresh_layer_used(bArmature *arm)
{
arm->layer_used = 0;
@@ -98,11 +94,12 @@ void ED_armature_edit_refresh_layer_used(bArmature *arm)
}
}
-/* *************************************************************** */
-/* Bone Operations */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Operations
+ * \{ */
-/* XXX bone_looper is only to be used when we want to access settings
- * (i.e. editability/visibility/selected) that context doesn't offer */
int bone_looper(Object *ob, Bone *bone, void *data, int (*bone_func)(Object *, Bone *, void *))
{
/* We want to apply the function bone_func to every bone
@@ -129,8 +126,11 @@ int bone_looper(Object *ob, Bone *bone, void *data, int (*bone_func)(Object *, B
return count;
}
-/* *************************************************************** */
-/* Bone Removal */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Removal
+ * \{ */
void bone_free(bArmature *arm, EditBone *bone)
{
@@ -155,9 +155,6 @@ void bone_free(bArmature *arm, EditBone *bone)
BLI_freelinkN(arm->edbo, bone);
}
-/**
- * \param clear_connected: When false caller is responsible for keeping the flag in a valid state.
- */
void ED_armature_ebone_remove_ex(bArmature *arm, EditBone *exBone, bool clear_connected)
{
EditBone *curBone;
@@ -190,13 +187,6 @@ bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebon
return false;
}
-/**
- * Finds the first parent shared by \a ebone_child
- *
- * \param ebone_child: Children bones to search
- * \param ebone_child_tot: Size of the ebone_child array
- * \return The shared parent or NULL.
- */
EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[], const uint ebone_child_tot)
{
#define EBONE_TEMP_UINT(ebone) (*((uint *)(&((ebone)->temp))))
@@ -284,20 +274,17 @@ void ED_armature_ebone_from_mat4(EditBone *ebone, const float mat[4][4])
ED_armature_ebone_from_mat3(ebone, mat3);
}
-/**
- * Return a pointer to the bone of the given name
- */
EditBone *ED_armature_ebone_find_name(const ListBase *edbo, const char *name)
{
return BLI_findstring(edbo, name, offsetof(EditBone, name));
}
-/* *************************************************************** */
-/* Mirroring */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mirroring
+ * \{ */
-/**
- * \see #BKE_pose_channel_get_mirrored (pose-mode, matching function)
- */
EditBone *ED_armature_ebone_get_mirrored(const ListBase *edbo, EditBone *ebo)
{
char name_flip[MAXBONENAME];
@@ -317,8 +304,6 @@ EditBone *ED_armature_ebone_get_mirrored(const ListBase *edbo, EditBone *ebo)
/* ------------------------------------- */
-/* helper function for tools to work on mirrored parts.
- * it leaves mirrored bones selected then too, which is a good indication of what happened */
void armature_select_mirrored_ex(bArmature *arm, const int flag)
{
BLI_assert((flag & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) == 0);
@@ -375,7 +360,6 @@ void armature_tag_select_mirrored(bArmature *arm)
}
}
-/* only works when tagged */
void armature_tag_unselect(bArmature *arm)
{
EditBone *curBone;
@@ -465,8 +449,6 @@ void ED_armature_ebone_transform_mirror_update(bArmature *arm, EditBone *ebo, bo
}
}
-/* if editbone (partial) selected, copy data */
-/* context; editmode armature, with mirror editing enabled */
void ED_armature_edit_transform_mirror_update(Object *obedit)
{
bArmature *arm = obedit->data;
@@ -475,8 +457,11 @@ void ED_armature_edit_transform_mirror_update(Object *obedit)
}
}
-/* *************************************************************** */
-/* Armature EditMode Conversions */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Armature EditMode Conversions
+ * \{ */
/* converts Bones to EditBone list, used for tools as well */
static EditBone *make_boneList_recursive(ListBase *edbo,
@@ -688,7 +673,6 @@ static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelis
}
}
-/* put EditMode back in Object */
void ED_armature_from_edit(Main *bmain, bArmature *arm)
{
EditBone *eBone, *neBone;
@@ -838,7 +822,6 @@ void ED_armature_edit_free(struct bArmature *arm)
}
}
-/* Put armature in EditMode */
void ED_armature_to_edit(bArmature *arm)
{
ED_armature_edit_free(arm);
@@ -846,10 +829,11 @@ void ED_armature_to_edit(bArmature *arm)
arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, arm->act_bone);
}
-/* *************************************************************** */
-/* Used by Undo for Armature EditMode. */
+/** \} */
-/* free's bones and their properties */
+/* -------------------------------------------------------------------- */
+/** \name Used by Undo for Armature EditMode
+ * \{ */
void ED_armature_ebone_listbase_free(ListBase *lb, const bool do_id_user)
{
@@ -908,10 +892,14 @@ void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
}
}
-/* *************************************************************** */
-/* Low level selection functions which hide connected-parent
- * flag behavior which gets tricky to handle in selection operators.
- * (no flushing in ED_armature_ebone_select.*, that should be explicit) */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Low Level Selection Functions
+ *
+ * which hide connected-parent flag behavior which gets tricky to handle in selection operators.
+ * (no flushing in `ED_armature_ebone_select.*`, that should be explicit).
+ * \{ */
int ED_armature_ebone_selectflag_get(const EditBone *ebone)
{
@@ -964,3 +952,5 @@ void ED_armature_ebone_select_set(EditBone *ebone, bool select)
}
ED_armature_ebone_selectflag_set(ebone, flag);
}
+
+/** \} */
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 832e75b2a8b..9117dfe892f 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -244,7 +244,6 @@ static void armature_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_armature_undosys_type(UndoType *ut)
{
ut->name = "Edit Armature";
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 20d7baa39ed..772fe8f3196 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -72,9 +72,10 @@
# include "PIL_time_utildefines.h"
#endif
-/* matches logic with ED_operator_posemode_context() */
Object *ED_pose_object_from_context(bContext *C)
{
+ /* NOTE: matches logic with #ED_operator_posemode_context(). */
+
ScrArea *area = CTX_wm_area(C);
Object *ob;
@@ -90,7 +91,6 @@ Object *ED_pose_object_from_context(bContext *C)
return ob;
}
-/* This function is used to process the necessary updates for */
bool ED_object_posemode_enter_ex(struct Main *bmain, Object *ob)
{
BLI_assert(!ID_IS_LINKED(ob));
@@ -195,11 +195,6 @@ static eAnimvizCalcRange pose_path_convert_range(ePosePathCalcRange range)
return ANIMVIZ_CALC_RANGE_FULL;
}
-/* For the object with pose/action: update paths for those that have got them
- * This should selectively update paths that exist...
- *
- * To be called from various tools that do incremental updates
- */
void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index e5b8983af93..17347aa57fe 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -108,7 +108,6 @@ void ED_pose_bone_select_tag_update(Object *ob)
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
}
-/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
bArmature *arm;
@@ -238,10 +237,6 @@ void ED_armature_pose_select_pick_bone(ViewLayer *view_layer,
}
}
-/**
- * Called for mode-less pose selection.
- * assumes the active object is still on old situation.
- */
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
View3D *v3d,
Base *base,
@@ -269,14 +264,6 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
return nearBone != NULL;
}
-/**
- * While in weight-paint mode, a single pose may be active as well.
- * While not common, it's possible we have multiple armatures deforming a mesh.
- *
- * This function de-selects all other objects, and selects the new base.
- * It can't be set to the active object because we need
- * to keep this set to the weight paint object.
- */
void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select)
{
BLI_assert(base_select && (base_select->object->type == OB_ARMATURE));
@@ -323,9 +310,6 @@ void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_se
}
}
-/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
- * When true, 'ignore_visibility' makes this func also affect invisible bones
- * (hidden or on hidden layers). */
bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
{
bArmature *arm = ob->data;
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 70d6fa93104..7c52e4fafdd 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -787,7 +787,7 @@ static int pose_copy_exec(bContext *C, wmOperator *op)
* any datablock expansion?
*/
Main *temp_bmain = BKE_main_new();
- STRNCPY(temp_bmain->name, BKE_main_blendfile_path_from_global());
+ STRNCPY(temp_bmain->filepath, BKE_main_blendfile_path_from_global());
Object ob_copy = *ob;
ob_copy.adt = NULL;
@@ -856,7 +856,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
/* Read copy buffer .blend file. */
char str[FILE_MAX];
Main *tmp_bmain = BKE_main_new();
- STRNCPY(tmp_bmain->name, BKE_main_blendfile_path_from_global());
+ STRNCPY(tmp_bmain->filepath, BKE_main_blendfile_path_from_global());
BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend");
if (!BKE_copybuffer_read(tmp_bmain, str, op->reports, FILTER_ID_OB)) {
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 500b9663a6c..19a5348dbc0 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -132,9 +132,6 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks,
}
}
-/**
- * Returns a valid pose armature for this object, else returns NULL.
- */
Object *poseAnim_object_get(Object *ob_)
{
Object *ob = BKE_object_pose_armature_get(ob_);
@@ -144,9 +141,6 @@ Object *poseAnim_object_get(Object *ob_)
return NULL;
}
-/**
- * Get sets of F-Curves providing transforms for the bones in the Pose.
- */
void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
{
/* for each Pose-Channel which gets affected, get the F-Curves for that channel
@@ -192,7 +186,6 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
}
}
-/* Free F-Curve <-> PoseChannel links. */
void poseAnim_mapping_free(ListBase *pfLinks)
{
tPChanFCurveLink *pfl, *pfln = NULL;
@@ -219,7 +212,6 @@ void poseAnim_mapping_free(ListBase *pfLinks)
/* ------------------------- */
-/* helper for apply() / reset() - refresh the data */
void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob)
{
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -231,7 +223,6 @@ void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob)
}
}
-/* reset changes made to current pose */
void poseAnim_mapping_reset(ListBase *pfLinks)
{
tPChanFCurveLink *pfl;
@@ -268,7 +259,6 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
}
}
-/* perform auto-key-framing after changes were made + confirmed */
void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -337,9 +327,6 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
/* ------------------------- */
-/* find the next F-Curve for a PoseChannel with matching path...
- * - path is not just the pfl rna_path, since that path doesn't have property info yet
- */
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path)
{
LinkData *first = (prev) ? prev->next : (fcuLinks) ? fcuLinks->first : NULL;
diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt
index b9ef8e82bba..2391f4af14d 100644
--- a/source/blender/editors/asset/CMakeLists.txt
+++ b/source/blender/editors/asset/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
)
@@ -34,6 +35,7 @@ set(SRC
intern/asset_catalog.cc
intern/asset_filter.cc
intern/asset_handle.cc
+ intern/asset_indexer.cc
intern/asset_library_reference.cc
intern/asset_library_reference_enum.cc
intern/asset_list.cc
diff --git a/source/blender/editors/asset/ED_asset_catalog.h b/source/blender/editors/asset/ED_asset_catalog.h
index 451ec0d5984..be99de01173 100644
--- a/source/blender/editors/asset/ED_asset_catalog.h
+++ b/source/blender/editors/asset/ED_asset_catalog.h
@@ -16,6 +16,8 @@
/** \file
* \ingroup edasset
+ *
+ * Supplement for `ED_asset_catalog.hh`. Part of the same API but usable in C.
*/
#pragma once
diff --git a/source/blender/editors/asset/ED_asset_catalog.hh b/source/blender/editors/asset/ED_asset_catalog.hh
index 8da8fc0d6c9..d4df15561d0 100644
--- a/source/blender/editors/asset/ED_asset_catalog.hh
+++ b/source/blender/editors/asset/ED_asset_catalog.hh
@@ -16,10 +16,17 @@
/** \file
* \ingroup edasset
+ *
+ * UI/Editor level API for catalog operations, creating richer functionality than the BKE catalog
+ * API provides (which this uses internally).
+ *
+ * Note that `ED_asset_catalog.h` is part of this API.
*/
#pragma once
+#include <optional>
+
#include "BKE_asset_catalog.hh"
#include "BLI_string_ref.hh"
@@ -37,6 +44,18 @@ void ED_asset_catalog_remove(AssetLibrary *library, const blender::bke::CatalogI
void ED_asset_catalog_rename(AssetLibrary *library,
blender::bke::CatalogID catalog_id,
blender::StringRefNull new_name);
-void ED_asset_catalog_move(AssetLibrary *library,
- blender::bke::CatalogID src_catalog_id,
- blender::bke::CatalogID dst_parent_catalog_id);
+/**
+ * Reinsert catalog identified by \a src_catalog_id as child to catalog identified by \a
+ * dst_parent_catalog_id. If \a dst_parent_catalog_id is not set, the catalog is moved to the root
+ * level of the tree.
+ * The name of the reinserted catalog is made unique within the parent. Note that moving a catalog
+ * to the same level it was before will also change its name, since the name uniqueness check isn't
+ * smart enough to ignore the item to be reinserted. So the caller is expected to handle this case
+ * to avoid unwanted renames.
+ *
+ * Nothing is done (debug builds run into an assert) if the given catalog IDs can't be identified.
+ */
+void ED_asset_catalog_move(
+ AssetLibrary *library,
+ blender::bke::CatalogID src_catalog_id,
+ std::optional<blender::bke::CatalogID> dst_parent_catalog_id = std::nullopt);
diff --git a/source/blender/editors/asset/ED_asset_filter.h b/source/blender/editors/asset/ED_asset_filter.h
index 340c4c9dbe7..3b92baea117 100644
--- a/source/blender/editors/asset/ED_asset_filter.h
+++ b/source/blender/editors/asset/ED_asset_filter.h
@@ -16,6 +16,8 @@
/** \file
* \ingroup edasset
+ *
+ * Functions for filtering assets.
*/
#pragma once
@@ -27,6 +29,18 @@ extern "C" {
struct AssetFilterSettings;
struct AssetHandle;
+/**
+ * Compare \a asset against the settings of \a filter.
+ *
+ * Individual filter parameters are ORed with the asset properties. That means:
+ * * The asset type must be one of the ID types filtered by, and
+ * * The asset must contain at least one of the tags filtered by.
+ * However for an asset to be matching it must have one match in each of the parameters. I.e. one
+ * matching type __and__ at least one matching tag.
+ *
+ * \returns True if the asset should be visible with these filter settings (parameters match).
+ * Otherwise returns false (mismatch).
+ */
bool ED_asset_filter_matches_asset(const struct AssetFilterSettings *filter,
const struct AssetHandle *asset);
diff --git a/source/blender/editors/asset/ED_asset_handle.h b/source/blender/editors/asset/ED_asset_handle.h
index efb99410d3d..dce851164a5 100644
--- a/source/blender/editors/asset/ED_asset_handle.h
+++ b/source/blender/editors/asset/ED_asset_handle.h
@@ -16,6 +16,12 @@
/** \file
* \ingroup edasset
+ *
+ * Asset-handle is a temporary design, not part of the core asset system design.
+ *
+ * Currently asset-list items are just file directory items (#FileDirEntry). So an asset-handle
+ * just wraps a pointer to this. We try to abstract away the fact that it's just a file entry,
+ * although that doesn't always work (see #rna_def_asset_handle()).
*/
#pragma once
diff --git a/source/blender/editors/asset/ED_asset_indexer.h b/source/blender/editors/asset/ED_asset_indexer.h
new file mode 100644
index 00000000000..33558d8cda5
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_indexer.h
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ED_file_indexer.h"
+
+/**
+ * File Indexer Service for indexing asset files.
+ *
+ * Opening and parsing a large collection of asset files inside a library can take a lot of time.
+ * To reduce the time it takes the files are indexed.
+ *
+ * - Index files are created for each blend file in the asset library, even when the blend file
+ * doesn't contain any assets.
+ * - Indexes are stored in an persistent cache folder (`BKE_appdir_folder_caches` +
+ * `asset_library_indexes/{asset_library_dir}/{asset_index_file.json}`).
+ * - The content of the indexes are used when:
+ * - Index exists and can be opened
+ * - Last modification date is earlier than the file it represents.
+ * - The index file version is the latest.
+ * - Blend files without any assets can be determined by the size of the index file for some
+ * additional performance.
+ */
+extern const FileIndexerType file_indexer_asset;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/ED_asset_library.h b/source/blender/editors/asset/ED_asset_library.h
index 905d097d223..62a7d6ffa9b 100644
--- a/source/blender/editors/asset/ED_asset_library.h
+++ b/source/blender/editors/asset/ED_asset_library.h
@@ -26,9 +26,27 @@
extern "C" {
#endif
+/**
+ * Return an index that can be used to uniquely identify \a library, assuming
+ * that all relevant indices were created with this function.
+ */
int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library);
+/**
+ * Return an asset library reference matching the index returned by
+ * #ED_asset_library_reference_to_enum_value().
+ */
AssetLibraryReference ED_asset_library_reference_from_enum_value(int value);
-const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(void);
+/**
+ * Translate all available asset libraries to an RNA enum, whereby the enum values match the result
+ * of #ED_asset_library_reference_to_enum_value() for any given library.
+ *
+ * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an
+ * empty name or path.
+ *
+ * \param include_local_library: Whether to include the "Current File" library or not.
+ */
+const struct EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(
+ bool include_local_library);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h
index 61d7729b651..669bb6dbe36 100644
--- a/source/blender/editors/asset/ED_asset_list.h
+++ b/source/blender/editors/asset/ED_asset_list.h
@@ -31,21 +31,47 @@ struct ID;
struct bContext;
struct wmNotifier;
+/**
+ * Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done,
+ * and may return earlier.
+ */
void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
const struct bContext *C);
void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
struct bContext *C);
void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C);
bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference);
+/**
+ * Tag all asset lists in the storage that show main data as needing an update (re-fetch).
+ *
+ * This only tags the data. If the asset list is visible on screen, the space is still responsible
+ * for ensuring the necessary redraw. It can use #ED_assetlist_listen() to check if the asset-list
+ * needs a redraw for a given notifier.
+ */
void ED_assetlist_storage_tag_main_data_dirty(void);
+/**
+ * Remapping of ID pointers within the asset lists. Typically called when an ID is deleted to clear
+ * all references to it (\a id_new is null then).
+ */
void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
+/**
+ * Can't wait for static deallocation to run. There's nested data allocated with our guarded
+ * allocator, it will complain about unfreed memory on exit.
+ */
void ED_assetlist_storage_exit(void);
struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);
+/**
+ * \return True if the region needs a UI redraw.
+ */
bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference,
const struct wmNotifier *notifier);
+/**
+ * \return The number of assets stored in the asset list for \a library_reference, or -1 if there
+ * is no list fetched for it.
+ */
int ED_assetlist_size(const struct AssetLibraryReference *library_reference);
#ifdef __cplusplus
diff --git a/source/blender/editors/asset/ED_asset_temp_id_consumer.h b/source/blender/editors/asset/ED_asset_temp_id_consumer.h
index 9a47e435612..0848f4225bd 100644
--- a/source/blender/editors/asset/ED_asset_temp_id_consumer.h
+++ b/source/blender/editors/asset/ED_asset_temp_id_consumer.h
@@ -16,6 +16,11 @@
/** \file
* \ingroup edasset
+ *
+ * API to abstract away details for temporary loading of an ID from an asset. If the ID is stored
+ * in the current file (or more precisely, in the #Main given when requesting an ID) no loading is
+ * performed and the ID is returned. Otherwise it's imported for temporary access using the
+ * `BLO_library_temp` API.
*/
#pragma once
diff --git a/source/blender/editors/asset/intern/asset_catalog.cc b/source/blender/editors/asset/intern/asset_catalog.cc
index 9634665be7b..f6c02f86f0a 100644
--- a/source/blender/editors/asset/intern/asset_catalog.cc
+++ b/source/blender/editors/asset/intern/asset_catalog.cc
@@ -122,7 +122,7 @@ void ED_asset_catalog_rename(::AssetLibrary *library,
void ED_asset_catalog_move(::AssetLibrary *library,
const CatalogID src_catalog_id,
- const CatalogID dst_parent_catalog_id)
+ const std::optional<CatalogID> dst_parent_catalog_id)
{
bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
if (!catalog_service) {
@@ -131,9 +131,24 @@ void ED_asset_catalog_move(::AssetLibrary *library,
}
AssetCatalog *src_catalog = catalog_service->find_catalog(src_catalog_id);
- AssetCatalog *dst_catalog = catalog_service->find_catalog(dst_parent_catalog_id);
+ if (!src_catalog) {
+ BLI_assert_unreachable();
+ return;
+ }
+ AssetCatalog *dst_catalog = dst_parent_catalog_id ?
+ catalog_service->find_catalog(*dst_parent_catalog_id) :
+ nullptr;
+ if (!dst_catalog && dst_parent_catalog_id) {
+ BLI_assert_unreachable();
+ return;
+ }
- const AssetCatalogPath new_path = dst_catalog->path / StringRef(src_catalog->path.name());
+ std::string unique_name = catalog_name_ensure_unique(
+ *catalog_service, src_catalog->path.name(), dst_catalog ? dst_catalog->path.c_str() : "");
+ /* If a destination catalog was given, construct the path using that. Otherwise, the path is just
+ * the name of the catalog to be moved, which means it ends up at the root level. */
+ const AssetCatalogPath new_path = dst_catalog ? (dst_catalog->path / unique_name) :
+ AssetCatalogPath{unique_name};
const AssetCatalogPath clean_new_path = new_path.cleanup();
if (new_path == src_catalog->path || clean_new_path == src_catalog->path) {
@@ -158,7 +173,7 @@ void ED_asset_catalogs_save_from_main_path(::AssetLibrary *library, const Main *
/* Since writing to disk also means loading any on-disk changes, it may be a good idea to store
* an undo step. */
catalog_service->undo_push();
- catalog_service->write_to_disk(bmain->name);
+ catalog_service->write_to_disk(bmain->filepath);
}
void ED_asset_catalogs_set_save_catalogs_when_file_is_saved(const bool should_save)
diff --git a/source/blender/editors/asset/intern/asset_filter.cc b/source/blender/editors/asset/intern/asset_filter.cc
index c22bbc923eb..70e3e2f55ea 100644
--- a/source/blender/editors/asset/intern/asset_filter.cc
+++ b/source/blender/editors/asset/intern/asset_filter.cc
@@ -27,18 +27,6 @@
#include "ED_asset_filter.h"
#include "ED_asset_handle.h"
-/**
- * Compare \a asset against the settings of \a filter.
- *
- * Individual filter parameters are ORed with the asset properties. That means:
- * * The asset type must be one of the ID types filtered by, and
- * * The asset must contain at least one of the tags filtered by.
- * However for an asset to be matching it must have one match in each of the parameters. I.e. one
- * matching type __and__ at least one matching tag.
- *
- * \returns True if the asset should be visible with these filter settings (parameters match).
- * Otherwise returns false (mismatch).
- */
bool ED_asset_filter_matches_asset(const AssetFilterSettings *filter, const AssetHandle *asset)
{
ID_Type asset_type = ED_asset_handle_get_id_type(asset);
diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc
index 363bd9226da..a2029d3cc50 100644
--- a/source/blender/editors/asset/intern/asset_handle.cc
+++ b/source/blender/editors/asset/intern/asset_handle.cc
@@ -16,12 +16,6 @@
/** \file
* \ingroup edasset
- *
- * Asset-handle is a temporary design, not part of the core asset system design.
- *
- * Currently asset-list items are just file directory items (#FileDirEntry). So an asset-handle is
- * just wraps a pointer to this. We try to abstract away the fact that it's just a file entry,
- * although that doesn't always work (see #rna_def_asset_handle()).
*/
#include <string>
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
new file mode 100644
index 00000000000..4107d28b5e3
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -0,0 +1,781 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#include <fstream>
+#include <iomanip>
+#include <optional>
+
+#include "ED_asset_indexer.h"
+
+#include "DNA_asset_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_fileops.h"
+#include "BLI_hash.hh"
+#include "BLI_linklist.h"
+#include "BLI_path_util.h"
+#include "BLI_serialize.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_uuid.h"
+
+#include "BKE_appdir.h"
+#include "BKE_asset.h"
+#include "BKE_asset_catalog.hh"
+#include "BKE_preferences.h"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"ed.asset"};
+
+namespace blender::ed::asset::index {
+
+using namespace blender::io::serialize;
+using namespace blender::bke;
+
+/**
+ * \file asset_indexer.cc
+ * \brief Indexer for asset libraries.
+ *
+ * Indexes are stored per input file. Each index can contain zero to multiple asset entries.
+ * The indexes are grouped together per asset library. They are stored in
+ * #BKE_appdir_folder_caches +
+ * /asset-library-indices/<asset-library-hash>/<asset-index-hash>_<asset_file>.index.json.
+ *
+ * The structure of an index file is
+ * \code
+ * {
+ * "version": <file version number>,
+ * "entries": [{
+ * "name": "<asset name>",
+ * "catalog_id": "<catalog_id>",
+ * "catalog_name": "<catalog_name>",
+ * "description": "<description>",
+ * "author": "<author>",
+ * "tags": ["<tag>"]
+ * }]
+ * }
+ * \endcode
+ *
+ * NOTE: entries, author, description and tags are optional attributes.
+ *
+ * NOTE: File browser uses name and idcode separate. Inside the index they are joined together like
+ * #ID.name.
+ * NOTE: File browser group name isn't stored in the index as it is a translatable name.
+ */
+constexpr StringRef ATTRIBUTE_VERSION("version");
+constexpr StringRef ATTRIBUTE_ENTRIES("entries");
+constexpr StringRef ATTRIBUTE_ENTRIES_NAME("name");
+constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_ID("catalog_id");
+constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name");
+constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description");
+constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author");
+constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags");
+
+/** Abstract class for #BlendFile and #AssetIndexFile. */
+class AbstractFile {
+ public:
+ virtual ~AbstractFile() = default;
+
+ virtual const char *get_file_path() const = 0;
+
+ bool exists() const
+ {
+ return BLI_exists(get_file_path());
+ }
+
+ size_t get_file_size() const
+ {
+ return BLI_file_size(get_file_path());
+ }
+};
+
+/**
+ * \brief Reference to a blend file that can be indexed.
+ */
+class BlendFile : public AbstractFile {
+ StringRefNull file_path_;
+
+ public:
+ BlendFile(StringRefNull file_path) : file_path_(file_path)
+ {
+ }
+
+ uint64_t hash() const
+ {
+ DefaultHash<StringRefNull> hasher;
+ return hasher(file_path_);
+ }
+
+ std::string get_filename() const
+ {
+ char filename[FILE_MAX];
+ BLI_split_file_part(get_file_path(), filename, sizeof(filename));
+ return std::string(filename);
+ }
+
+ const char *get_file_path() const override
+ {
+ return file_path_.c_str();
+ }
+};
+
+/**
+ * \brief Single entry inside a #AssetIndexFile for reading.
+ */
+struct AssetEntryReader {
+ private:
+ /**
+ * \brief Lookup table containing the elements of the entry.
+ */
+ ObjectValue::Lookup lookup;
+
+ StringRefNull get_name_with_idcode() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_NAME)->as_string_value()->value();
+ }
+
+ public:
+ AssetEntryReader(const ObjectValue &entry) : lookup(entry.create_lookup())
+ {
+ }
+
+ ID_Type get_idcode() const
+ {
+ const StringRefNull name_with_idcode = get_name_with_idcode();
+ return GS(name_with_idcode.c_str());
+ }
+
+ StringRef get_name() const
+ {
+ const StringRefNull name_with_idcode = get_name_with_idcode();
+ return name_with_idcode.substr(2);
+ }
+
+ bool has_description() const
+ {
+ return lookup.contains(ATTRIBUTE_ENTRIES_DESCRIPTION);
+ }
+
+ StringRefNull get_description() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_DESCRIPTION)->as_string_value()->value();
+ }
+
+ bool has_author() const
+ {
+ return lookup.contains(ATTRIBUTE_ENTRIES_AUTHOR);
+ }
+
+ StringRefNull get_author() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_AUTHOR)->as_string_value()->value();
+ }
+
+ StringRefNull get_catalog_name() const
+ {
+ return lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_NAME)->as_string_value()->value();
+ }
+
+ CatalogID get_catalog_id() const
+ {
+ const std::string &catalog_id =
+ lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_ID)->as_string_value()->value();
+ CatalogID catalog_uuid(catalog_id);
+ return catalog_uuid;
+ }
+
+ void add_tags_to_meta_data(AssetMetaData *asset_data) const
+ {
+ const ObjectValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
+ if (value_ptr == nullptr) {
+ return;
+ }
+
+ const ArrayValue *array_value = (*value_ptr)->as_array_value();
+ const ArrayValue::Items &elements = array_value->elements();
+ for (const ArrayValue::Item &item : elements) {
+ const StringRefNull tag_name = item->as_string_value()->value();
+ BKE_asset_metadata_tag_add(asset_data, tag_name.c_str());
+ }
+ }
+};
+
+struct AssetEntryWriter {
+ private:
+ ObjectValue::Items &attributes;
+
+ public:
+ AssetEntryWriter(ObjectValue &entry) : attributes(entry.elements())
+ {
+ }
+
+ /**
+ * \brief add id + name to the attributes.
+ *
+ * NOTE: id and name are encoded like #ID.name
+ */
+ void add_id_name(const short idcode, const StringRefNull name)
+ {
+ char idcode_prefix[2];
+ /* Similar to `BKE_libblock_alloc`. */
+ *((short *)idcode_prefix) = idcode;
+ std::string name_with_idcode = std::string(idcode_prefix, sizeof(idcode_prefix)) + name;
+
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_NAME, new StringValue(name_with_idcode)));
+ }
+
+ void add_catalog_id(const CatalogID &catalog_id)
+ {
+ char catalog_id_str[UUID_STRING_LEN];
+ BLI_uuid_format(catalog_id_str, catalog_id);
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_CATALOG_ID, new StringValue(catalog_id_str)));
+ }
+
+ void add_catalog_name(const StringRefNull catalog_name)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_CATALOG_NAME, new StringValue(catalog_name)));
+ }
+
+ void add_description(const StringRefNull description)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_DESCRIPTION, new StringValue(description)));
+ }
+
+ void add_author(const StringRefNull author)
+ {
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_AUTHOR, new StringValue(author)));
+ }
+
+ void add_tags(const ListBase /* AssetTag */ *asset_tags)
+ {
+ ArrayValue *tags = new ArrayValue();
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_TAGS, tags));
+ ArrayValue::Items &tag_items = tags->elements();
+
+ LISTBASE_FOREACH (AssetTag *, tag, asset_tags) {
+ tag_items.append_as(new StringValue(tag->name));
+ }
+ }
+};
+
+static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
+ const FileIndexerEntry *indexer_entry)
+{
+ const BLODataBlockInfo &datablock_info = indexer_entry->datablock_info;
+
+ result.add_id_name(indexer_entry->idcode, datablock_info.name);
+
+ const AssetMetaData &asset_data = *datablock_info.asset_data;
+ result.add_catalog_id(asset_data.catalog_id);
+ result.add_catalog_name(asset_data.catalog_simple_name);
+
+ if (asset_data.description != nullptr) {
+ result.add_description(asset_data.description);
+ }
+ if (asset_data.author != nullptr) {
+ result.add_author(asset_data.author);
+ }
+
+ if (!BLI_listbase_is_empty(&asset_data.tags)) {
+ result.add_tags(&asset_data.tags);
+ }
+
+ /* TODO: asset_data.IDProperties */
+}
+
+static void init_value_from_file_indexer_entries(ObjectValue &result,
+ const FileIndexerEntries &indexer_entries)
+{
+ ArrayValue *entries = new ArrayValue();
+ ArrayValue::Items &items = entries->elements();
+
+ for (LinkNode *ln = indexer_entries.entries; ln; ln = ln->next) {
+ const FileIndexerEntry *indexer_entry = static_cast<const FileIndexerEntry *>(ln->link);
+ /* We also get non asset types (brushes, workspaces), when browsing using the asset browser. */
+ if (indexer_entry->datablock_info.asset_data == nullptr) {
+ continue;
+ }
+ ObjectValue *entry_value = new ObjectValue();
+ AssetEntryWriter entry(*entry_value);
+ init_value_from_file_indexer_entry(entry, indexer_entry);
+ items.append_as(entry_value);
+ }
+
+ /* When no entries to index, we should not store the entries attribute as this would make the
+ * size bigger than the #MIN_FILE_SIZE_WITH_ENTRIES. */
+ if (items.is_empty()) {
+ delete entries;
+ return;
+ }
+
+ ObjectValue::Items &attributes = result.elements();
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries));
+}
+
+static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
+ const AssetEntryReader &entry)
+{
+ indexer_entry.idcode = entry.get_idcode();
+
+ const std::string &name = entry.get_name();
+ BLI_strncpy(
+ indexer_entry.datablock_info.name, name.c_str(), sizeof(indexer_entry.datablock_info.name));
+
+ AssetMetaData *asset_data = BKE_asset_metadata_create();
+ indexer_entry.datablock_info.asset_data = asset_data;
+
+ if (entry.has_description()) {
+ const std::string &description = entry.get_description();
+ char *description_c_str = static_cast<char *>(MEM_mallocN(description.length() + 1, __func__));
+ BLI_strncpy(description_c_str, description.c_str(), description.length() + 1);
+ asset_data->description = description_c_str;
+ }
+ if (entry.has_author()) {
+ const std::string &author = entry.get_author();
+ char *author_c_str = static_cast<char *>(MEM_mallocN(author.length() + 1, __func__));
+ BLI_strncpy(author_c_str, author.c_str(), author.length() + 1);
+ asset_data->author = author_c_str;
+ }
+
+ const std::string &catalog_name = entry.get_catalog_name();
+ BLI_strncpy(asset_data->catalog_simple_name,
+ catalog_name.c_str(),
+ sizeof(asset_data->catalog_simple_name));
+
+ asset_data->catalog_id = entry.get_catalog_id();
+
+ entry.add_tags_to_meta_data(asset_data);
+}
+
+static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
+ const ObjectValue &value)
+{
+ const ObjectValue::Lookup attributes = value.create_lookup();
+ const ObjectValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
+ BLI_assert(entries_value != nullptr);
+
+ if (entries_value == nullptr) {
+ return 0;
+ }
+
+ int num_entries_read = 0;
+ const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements();
+ for (ArrayValue::Item element : elements) {
+ const AssetEntryReader asset_entry(*element->as_object_value());
+
+ FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
+ MEM_callocN(sizeof(FileIndexerEntry), __func__));
+ init_indexer_entry_from_value(*entry, asset_entry);
+
+ BLI_linklist_prepend(&indexer_entries.entries, entry);
+ num_entries_read += 1;
+ }
+
+ return num_entries_read;
+}
+
+/**
+ * \brief References the asset library directory.
+ *
+ * The #AssetLibraryIndex instance is used to keep track of unused file indices. When reading any
+ * used indices are removed from the list and when reading is finished the unused
+ * indices are removed.
+ */
+struct AssetLibraryIndex {
+ /**
+ * Tracks indices that haven't been used yet.
+ *
+ * Contains absolute paths to the indices.
+ */
+ Set<std::string> unused_file_indices;
+
+ /**
+ * \brief Absolute path where the indices of `library` are stored.
+ *
+ * \NOTE: includes trailing directory separator.
+ */
+ std::string indices_base_path;
+
+ std::string library_path;
+
+ public:
+ AssetLibraryIndex(const StringRef library_path) : library_path(library_path)
+ {
+ init_indices_base_path();
+ }
+
+ uint64_t hash() const
+ {
+ DefaultHash<StringRefNull> hasher;
+ return hasher(get_library_file_path());
+ }
+
+ StringRefNull get_library_file_path() const
+ {
+ return library_path;
+ }
+
+ /**
+ * \brief Initializes #AssetLibraryIndex.indices_base_path.
+ *
+ * `BKE_appdir_folder_caches/asset-library-indices/<asset-library-name-hash>/`
+ */
+ void init_indices_base_path()
+ {
+ char index_path[FILE_MAX];
+ BKE_appdir_folder_caches(index_path, sizeof(index_path));
+
+ BLI_path_append(index_path, sizeof(index_path), "asset-library-indices");
+
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(16) << std::hex << hash() << "/";
+ BLI_path_append(index_path, sizeof(index_path), ss.str().c_str());
+
+ indices_base_path = std::string(index_path);
+ }
+
+ /**
+ * \return absolute path to the index file of the given `asset_file`.
+ *
+ * `{indices_base_path}/{asset-file_hash}_{asset-file-filename}.index.json`.
+ */
+ std::string index_file_path(const BlendFile &asset_file) const
+ {
+ std::stringstream ss;
+ ss << indices_base_path;
+ ss << std::setfill('0') << std::setw(16) << std::hex << asset_file.hash() << "_"
+ << asset_file.get_filename() << ".index.json";
+ return ss.str();
+ }
+
+ /**
+ * Initialize to keep track of unused file indices.
+ */
+ void init_unused_index_files()
+ {
+ const char *index_path = indices_base_path.c_str();
+ if (!BLI_is_dir(index_path)) {
+ return;
+ }
+ struct direntry *dir_entries = nullptr;
+ int num_entries = BLI_filelist_dir_contents(index_path, &dir_entries);
+ for (int i = 0; i < num_entries; i++) {
+ struct direntry *entry = &dir_entries[i];
+ if (BLI_str_endswith(entry->relname, ".index.json")) {
+ unused_file_indices.add_as(std::string(entry->path));
+ }
+ }
+
+ BLI_filelist_free(dir_entries, num_entries);
+ }
+
+ void mark_as_used(const std::string &filename)
+ {
+ unused_file_indices.remove(filename);
+ }
+
+ int remove_unused_index_files() const
+ {
+ int num_files_deleted = 0;
+ for (const std::string &unused_index : unused_file_indices) {
+ const char *file_path = unused_index.c_str();
+ CLOG_INFO(&LOG, 2, "Remove unused index file [%s].", file_path);
+ BLI_delete(file_path, false, false);
+ num_files_deleted++;
+ }
+
+ return num_files_deleted;
+ }
+};
+
+/**
+ * Instance of this class represents the contents of an asset index file.
+ *
+ * \code
+ * {
+ * "version": {version},
+ * "entries": ...
+ * }
+ * \endcode
+ */
+struct AssetIndex {
+ /**
+ * \brief Version to store in new index files.
+ *
+ * Versions are written to each index file. When reading the version is checked against
+ * `CURRENT_VERSION` to make sure we can use the index. Developer should increase
+ * `CURRENT_VERSION` when changes are made to the structure of the stored index.
+ */
+ static const int CURRENT_VERSION = 1;
+
+ /**
+ * Version number to use when version couldn't be read from an index file.
+ */
+ const int UNKNOWN_VERSION = -1;
+
+ /**
+ * `blender::io::serialize::Value` representing the contents of an index file.
+ *
+ * Value is used over #ObjectValue as the contents of the index could be corrupted and doesn't
+ * represent an object. In case corrupted files are detected the `get_version` would return
+ * `UNKNOWN_VERSION`.
+ */
+ std::unique_ptr<Value> contents;
+
+ /**
+ * Constructor for when creating/updating an asset index file.
+ * #AssetIndex.contents are filled from the given \p indexer_entries.
+ */
+ AssetIndex(const FileIndexerEntries &indexer_entries)
+ {
+ std::unique_ptr<ObjectValue> root = std::make_unique<ObjectValue>();
+ ObjectValue::Items &root_attributes = root->elements();
+ root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION)));
+ init_value_from_file_indexer_entries(*root, indexer_entries);
+
+ contents = std::move(root);
+ }
+
+ /**
+ * Constructor when reading an asset index file.
+ * #AssetIndex.contents are read from the given \p value.
+ */
+ AssetIndex(std::unique_ptr<Value> &value) : contents(std::move(value))
+ {
+ }
+
+ int get_version() const
+ {
+ const ObjectValue *root = contents->as_object_value();
+ if (root == nullptr) {
+ return UNKNOWN_VERSION;
+ }
+ const ObjectValue::Lookup attributes = root->create_lookup();
+ const ObjectValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
+ if (version_value == nullptr) {
+ return UNKNOWN_VERSION;
+ }
+ return (*version_value)->as_int_value()->value();
+ }
+
+ bool is_latest_version() const
+ {
+ return get_version() == CURRENT_VERSION;
+ }
+
+ /**
+ * Extract the contents of this index into the given \p indexer_entries.
+ *
+ * \return The number of entries read from the given entries.
+ */
+ int extract_into(FileIndexerEntries &indexer_entries) const
+ {
+ const ObjectValue *root = contents->as_object_value();
+ const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root);
+ return num_entries_read;
+ }
+};
+
+class AssetIndexFile : public AbstractFile {
+ public:
+ AssetLibraryIndex &library_index;
+ /**
+ * Asset index files with a size smaller than this attribute would be considered to not contain
+ * any entries.
+ */
+ const size_t MIN_FILE_SIZE_WITH_ENTRIES = 32;
+ std::string filename;
+
+ AssetIndexFile(AssetLibraryIndex &library_index, BlendFile &asset_filename)
+ : library_index(library_index), filename(library_index.index_file_path(asset_filename))
+ {
+ }
+
+ void mark_as_used()
+ {
+ library_index.mark_as_used(filename);
+ }
+
+ const char *get_file_path() const override
+ {
+ return filename.c_str();
+ }
+
+ /**
+ * Returns whether the index file is older than the given asset file.
+ */
+ bool is_older_than(BlendFile &asset_file) const
+ {
+ return BLI_file_older(get_file_path(), asset_file.get_file_path());
+ }
+
+ /**
+ * Check whether the index file contains entries without opening the file.
+ */
+ bool constains_entries() const
+ {
+ const size_t file_size = get_file_size();
+ return file_size >= MIN_FILE_SIZE_WITH_ENTRIES;
+ }
+
+ std::unique_ptr<AssetIndex> read_contents() const
+ {
+ JsonFormatter formatter;
+ std::ifstream is;
+ is.open(filename);
+ std::unique_ptr<Value> read_data = formatter.deserialize(is);
+ is.close();
+
+ return std::make_unique<AssetIndex>(read_data);
+ }
+
+ bool ensure_parent_path_exists() const
+ {
+ /* `BLI_make_existing_file` only ensures parent path, otherwise than expected from the name of
+ * the function. */
+ return BLI_make_existing_file(get_file_path());
+ }
+
+ void write_contents(AssetIndex &content)
+ {
+ JsonFormatter formatter;
+ if (!ensure_parent_path_exists()) {
+ CLOG_ERROR(&LOG, "Index not created: couldn't create folder [%s].", get_file_path());
+ return;
+ }
+
+ std::ofstream os;
+ os.open(filename, std::ios::out | std::ios::trunc);
+ formatter.serialize(os, *content.contents);
+ os.close();
+ }
+};
+
+static eFileIndexerResult read_index(const char *filename,
+ FileIndexerEntries *entries,
+ int *r_read_entries_len,
+ void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ BlendFile asset_file(filename);
+ AssetIndexFile asset_index_file(library_index, asset_file);
+
+ if (!asset_index_file.exists()) {
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ /* Mark index as used, even when it will be recreated. When not done it would remove the index
+ * when the indexing has finished (see `AssetLibraryIndex.remove_unused_index_files`), thereby
+ * removing the newly created index.
+ */
+ asset_index_file.mark_as_used();
+
+ if (asset_index_file.is_older_than(asset_file)) {
+ CLOG_INFO(
+ &LOG,
+ 3,
+ "Asset index file [%s] needs to be refreshed as it is older than the asset file [%s].",
+ asset_index_file.filename.c_str(),
+ filename);
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ if (!asset_index_file.constains_entries()) {
+ CLOG_INFO(&LOG,
+ 3,
+ "Asset file index is to small to contain any entries. [%s]",
+ asset_index_file.filename.c_str());
+ *r_read_entries_len = 0;
+ return FILE_INDEXER_ENTRIES_LOADED;
+ }
+
+ std::unique_ptr<AssetIndex> contents = asset_index_file.read_contents();
+ if (!contents->is_latest_version()) {
+ CLOG_INFO(&LOG,
+ 3,
+ "Asset file index is ignored; expected version %d but file is version %d [%s].",
+ AssetIndex::CURRENT_VERSION,
+ contents->get_version(),
+ asset_index_file.filename.c_str());
+ return FILE_INDEXER_NEEDS_UPDATE;
+ }
+
+ const int read_entries_len = contents->extract_into(*entries);
+ CLOG_INFO(&LOG, 1, "Read %d entries from asset index for [%s].", read_entries_len, filename);
+ *r_read_entries_len = read_entries_len;
+
+ return FILE_INDEXER_ENTRIES_LOADED;
+}
+
+static void update_index(const char *filename, FileIndexerEntries *entries, void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ BlendFile asset_file(filename);
+ AssetIndexFile asset_index_file(library_index, asset_file);
+ CLOG_INFO(&LOG,
+ 1,
+ "Update asset index for [%s] store index in [%s].",
+ asset_file.get_file_path(),
+ asset_index_file.get_file_path());
+
+ AssetIndex content(*entries);
+ asset_index_file.write_contents(content);
+}
+
+static void *init_user_data(const char *root_directory, size_t root_directory_maxlen)
+{
+ AssetLibraryIndex *library_index = OBJECT_GUARDED_NEW(
+ AssetLibraryIndex,
+ StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
+ library_index->init_unused_index_files();
+ return library_index;
+}
+
+static void free_user_data(void *user_data)
+{
+ OBJECT_GUARDED_DELETE(user_data, AssetLibraryIndex);
+}
+
+static void filelist_finished(void *user_data)
+{
+ AssetLibraryIndex &library_index = *static_cast<AssetLibraryIndex *>(user_data);
+ const int num_indices_removed = library_index.remove_unused_index_files();
+ if (num_indices_removed > 0) {
+ CLOG_INFO(&LOG, 1, "Removed %d unused indices.", num_indices_removed);
+ }
+}
+
+constexpr FileIndexerType asset_indexer()
+{
+ FileIndexerType indexer = {nullptr};
+ indexer.read_index = read_index;
+ indexer.update_index = update_index;
+ indexer.init_user_data = init_user_data;
+ indexer.free_user_data = free_user_data;
+ indexer.filelist_finished = filelist_finished;
+ return indexer;
+}
+
+} // namespace blender::ed::asset::index
+
+extern "C" {
+const FileIndexerType file_indexer_asset = blender::ed::asset::index::asset_indexer();
+}
diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
index 1a2d3f5837a..05526f222a5 100644
--- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc
+++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc
@@ -35,10 +35,6 @@
#include "ED_asset_library.h"
-/**
- * Return an index that can be used to uniquely identify \a library, assuming
- * that all relevant indices were created with this function.
- */
int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library)
{
/* Simple case: Predefined repository, just set the value. */
@@ -57,10 +53,6 @@ int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *librar
return ASSET_LIBRARY_LOCAL;
}
-/**
- * Return an asset library reference matching the index returned by
- * #ED_asset_library_reference_to_enum_value().
- */
AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
{
AssetLibraryReference library;
@@ -92,31 +84,27 @@ AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
return library;
}
-/**
- * Translate all available asset libraries to an RNA enum, whereby the enum values match the result
- * of #ED_asset_library_reference_to_enum_value() for any given library.
- *
- * Since this is meant for UI display, skips non-displayable libraries, that is, libraries with an
- * empty name or path.
- */
-const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf()
+const EnumPropertyItem *ED_asset_library_reference_to_rna_enum_itemf(
+ const bool include_local_library)
{
- const EnumPropertyItem predefined_items[] = {
- /* For the future. */
- // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
- {ASSET_LIBRARY_LOCAL,
- "LOCAL",
- ICON_BLENDER,
- "Current File",
- "Show the assets currently available in this Blender session"},
- {0, nullptr, 0, nullptr, nullptr},
- };
-
EnumPropertyItem *item = nullptr;
int totitem = 0;
- /* Add predefined items. */
- RNA_enum_items_add(&item, &totitem, predefined_items);
+ if (include_local_library) {
+ const EnumPropertyItem predefined_items[] = {
+ /* For the future. */
+ // {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
+ {ASSET_LIBRARY_LOCAL,
+ "LOCAL",
+ ICON_CURRENT_FILE,
+ "Current File",
+ "Show the assets currently available in this Blender session"},
+ {0, nullptr, 0, nullptr, nullptr},
+ };
+
+ /* Add predefined items. */
+ RNA_enum_items_add(&item, &totitem, predefined_items);
+ }
/* Add separator if needed. */
if (!BLI_listbase_is_empty(&U.asset_libraries)) {
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index c1b1e33d428..1bfdd83b8e3 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -44,10 +44,15 @@
#include "../space_file/filelist.h"
#include "ED_asset_handle.h"
+#include "ED_asset_indexer.h"
#include "ED_asset_list.h"
#include "ED_asset_list.hh"
#include "asset_library_reference.hh"
+/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for
+ * object snapping. See {D12990}. */
+//#define SPACE_FILE_ENABLE_ASSET_INDEXING
+
namespace blender::ed::asset {
/* -------------------------------------------------------------------- */
@@ -169,6 +174,10 @@ void AssetList::setup()
"",
"");
+#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING
+ filelist_setindexer(files, &file_indexer_asset);
+#endif
+
char path[FILE_MAXDIR] = "";
if (user_library) {
BLI_strncpy(path, user_library->path, sizeof(path));
@@ -309,6 +318,7 @@ StringRef AssetList::filepath() const
{
return filelist_dir(filelist_);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -425,10 +435,6 @@ AssetListStorage::AssetListMap &AssetListStorage::global_storage()
using namespace blender::ed::asset;
-/**
- * Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done,
- * and may return earlier.
- */
void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
{
AssetListStorage::fetch_library(*library_reference, *C);
@@ -523,9 +529,6 @@ const char *ED_assetlist_library_path(const AssetLibraryReference *library_refer
return nullptr;
}
-/**
- * \return True if the region needs a UI redraw.
- */
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
{
@@ -536,10 +539,6 @@ bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
return false;
}
-/**
- * \return The number of assets stored in the asset list for \a library_reference, or -1 if there
- * is no list fetched for it.
- */
int ED_assetlist_size(const AssetLibraryReference *library_reference)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
@@ -549,31 +548,16 @@ int ED_assetlist_size(const AssetLibraryReference *library_reference)
return -1;
}
-/**
- * Tag all asset lists in the storage that show main data as needing an update (re-fetch).
- *
- * This only tags the data. If the asset list is visible on screen, the space is still responsible
- * for ensuring the necessary redraw. It can use #ED_assetlist_listen() to check if the asset-list
- * needs a redraw for a given notifier.
- */
void ED_assetlist_storage_tag_main_data_dirty()
{
AssetListStorage::tagMainDataDirty();
}
-/**
- * Remapping of ID pointers within the asset lists. Typically called when an ID is deleted to clear
- * all references to it (\a id_new is null then).
- */
void ED_assetlist_storage_id_remap(ID *id_old, ID *id_new)
{
AssetListStorage::remapID(id_old, id_new);
}
-/**
- * Can't wait for static deallocation to run. There's nested data allocated with our guarded
- * allocator, it will complain about unfreed memory on exit.
- */
void ED_assetlist_storage_exit()
{
AssetListStorage::destruct();
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index f7c567c89f6..e4edff19a21 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -19,12 +19,23 @@
*/
#include "BKE_asset_library.hh"
+#include "BKE_bpath.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_preferences.h"
#include "BKE_report.h"
+#include "BLI_fileops.h"
+#include "BLI_fnmatch.h"
+#include "BLI_path_util.h"
+#include "BLI_set.hh"
+
#include "ED_asset.h"
+#include "ED_asset_catalog.hh"
+#include "ED_screen.h"
+#include "ED_util.h"
/* XXX needs access to the file list, should all be done via the asset system in future. */
#include "ED_fileselect.h"
@@ -33,6 +44,10 @@
#include "WM_api.h"
+#include "DNA_space_types.h"
+
+#include "BLO_writefile.h"
+
using namespace blender;
/* -------------------------------------------------------------------- */
@@ -377,8 +392,14 @@ static void ASSET_OT_clear(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-static bool asset_list_refresh_poll(bContext *C)
+static bool asset_library_refresh_poll(bContext *C)
{
+ if (ED_operator_asset_browsing_active(C)) {
+ return true;
+ }
+
+ /* While not inside an Asset Browser, check if there's a asset list stored for the active asset
+ * library (stored in the workspace, obtained via context). */
const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
if (!library) {
return false;
@@ -387,23 +408,38 @@ static bool asset_list_refresh_poll(bContext *C)
return ED_assetlist_storage_has_list_for_library(library);
}
-static int asset_list_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
+static int asset_library_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
{
- const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
- ED_assetlist_clear(library, C);
+ /* Execution mode #1: Inside the Asset Browser. */
+ if (ED_operator_asset_browsing_active(C)) {
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ ED_fileselect_clear(CTX_wm_manager(C), sfile);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, nullptr);
+ }
+ else {
+ /* Execution mode #2: Outside the Asset Browser, use the asset list. */
+ const AssetLibraryReference *library = CTX_wm_asset_library_ref(C);
+ ED_assetlist_clear(library, C);
+ }
+
return OPERATOR_FINISHED;
}
-static void ASSET_OT_list_refresh(struct wmOperatorType *ot)
+/**
+ * This operator currently covers both cases, the File/Asset Browser file list and the asset list
+ * used for the asset-view template. Once the asset list design is used by the Asset Browser, this
+ * can be simplified to just that case.
+ */
+static void ASSET_OT_library_refresh(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Refresh Asset List";
- ot->description = "Trigger a reread of the assets";
- ot->idname = "ASSET_OT_list_refresh";
+ ot->name = "Refresh Asset Library";
+ ot->description = "Reread assets and asset catalogs from the asset library on disk";
+ ot->idname = "ASSET_OT_library_refresh";
/* api callbacks */
- ot->exec = asset_list_refresh_exec;
- ot->poll = asset_list_refresh_poll;
+ ot->exec = asset_library_refresh_exec;
+ ot->poll = asset_library_refresh_poll;
}
/* -------------------------------------------------------------------- */
@@ -601,7 +637,7 @@ static bool asset_catalogs_save_poll(bContext *C)
}
const Main *bmain = CTX_data_main(C);
- if (!bmain->name[0]) {
+ if (!bmain->filepath[0]) {
CTX_wm_operator_poll_msg_set(C, "Cannot save asset catalogs before the Blender file is saved");
return false;
}
@@ -643,7 +679,274 @@ static void ASSET_OT_catalogs_save(struct wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-void ED_operatortypes_asset(void)
+static bool could_be_asset_bundle(const Main *bmain);
+static const bUserAssetLibrary *selected_asset_library(struct wmOperator *op);
+static bool is_contained_in_selected_asset_library(struct wmOperator *op, const char *filepath);
+static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op);
+static bool has_external_files(Main *bmain, struct ReportList *reports);
+
+static bool asset_bundle_install_poll(bContext *C)
+{
+ /* This operator only works when the asset browser is set to Current File. */
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ if (sfile == nullptr) {
+ return false;
+ }
+ if (!ED_fileselect_is_local_asset_library(sfile)) {
+ return false;
+ }
+
+ const Main *bmain = CTX_data_main(C);
+ if (!could_be_asset_bundle(bmain)) {
+ return false;
+ }
+
+ /* Check whether this file is already located inside any asset library. */
+ const struct bUserAssetLibrary *asset_lib = BKE_preferences_asset_library_containing_path(
+ &U, bmain->filepath);
+ if (asset_lib) {
+ return false;
+ }
+
+ return true;
+}
+
+static int asset_bundle_install_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const struct wmEvent * /*event*/)
+{
+ Main *bmain = CTX_data_main(C);
+ if (has_external_files(bmain, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_fileselect(C, op);
+
+ /* Make the "Save As" dialog box default to "${ASSET_LIB_ROOT}/${CURRENT_FILE}.blend". */
+ if (!set_filepath_for_asset_lib(bmain, op)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int asset_bundle_install_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ if (has_external_files(bmain, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Check file path, copied from #wm_file_write(). */
+ char filepath[PATH_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+ const size_t len = strlen(filepath);
+
+ if (len == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Path is empty, cannot save");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (len >= FILE_MAX) {
+ BKE_report(op->reports, RPT_ERROR, "Path too long, cannot save");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Check that the destination is actually contained in the selected asset library. */
+ if (!is_contained_in_selected_asset_library(op, filepath)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Selected path is outside of the selected asset library");
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_cursor_wait(true);
+ bke::AssetCatalogService *cat_service = get_catalog_service(C);
+ /* Store undo step, such that on a failed save the 'prepare_to_merge_on_write' call can be
+ * un-done. */
+ cat_service->undo_push();
+ cat_service->prepare_to_merge_on_write();
+
+ const int operator_result = WM_operator_name_call(
+ C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, op->ptr);
+ WM_cursor_wait(false);
+
+ if (operator_result != OPERATOR_FINISHED) {
+ cat_service->undo();
+ return operator_result;
+ }
+
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ BLI_assert_msg(lib, "If the asset library is not known, how did we get here?");
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ R"(Saved "%s" to asset library "%s")",
+ BLI_path_basename(bmain->filepath),
+ lib->name);
+ return OPERATOR_FINISHED;
+}
+
+static const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(false);
+ if (!items) {
+ *r_free = false;
+ }
+
+ *r_free = true;
+ return items;
+}
+
+static void ASSET_OT_bundle_install(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy to Asset Library";
+ ot->description =
+ "Copy the current .blend file into an Asset Library. Only works on standalone .blend files "
+ "(i.e. when no other files are referenced)";
+ ot->idname = "ASSET_OT_bundle_install";
+
+ /* api callbacks */
+ ot->exec = asset_bundle_install_exec;
+ ot->invoke = asset_bundle_install_invoke;
+ ot->poll = asset_bundle_install_poll;
+
+ ot->prop = RNA_def_property(ot->srna, "asset_library_ref", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN);
+ RNA_def_enum_funcs(ot->prop, rna_asset_library_reference_itemf);
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_BLENDER,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
+}
+
+/* Cheap check to see if this is an "asset bundle" just by checking main file name.
+ * A proper check will be done in the exec function, to ensure that no external files will be
+ * referenced. */
+static bool could_be_asset_bundle(const Main *bmain)
+{
+ return fnmatch("*_bundle.blend", bmain->filepath, FNM_CASEFOLD) == 0;
+}
+
+static const bUserAssetLibrary *selected_asset_library(struct wmOperator *op)
+{
+ const int enum_value = RNA_enum_get(op->ptr, "asset_library_ref");
+ const AssetLibraryReference lib_ref = ED_asset_library_reference_from_enum_value(enum_value);
+ const bUserAssetLibrary *lib = BKE_preferences_asset_library_find_from_index(
+ &U, lib_ref.custom_library_index);
+ return lib;
+}
+
+static bool is_contained_in_selected_asset_library(struct wmOperator *op, const char *filepath)
+{
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ if (!lib) {
+ return false;
+ }
+ return BLI_path_contains(lib->path, filepath);
+}
+
+/**
+ * Set the "filepath" RNA property based on selected "asset_library_ref".
+ * \return true if ok, false if error.
+ */
+static bool set_filepath_for_asset_lib(const Main *bmain, struct wmOperator *op)
+{
+ /* Find the directory path of the selected asset library. */
+ const bUserAssetLibrary *lib = selected_asset_library(op);
+ if (lib == nullptr) {
+ return false;
+ }
+
+ /* Concatenate the filename of the current blend file. */
+ const char *blend_filename = BLI_path_basename(bmain->filepath);
+ if (blend_filename == nullptr || blend_filename[0] == '\0') {
+ return false;
+ }
+
+ char file_path[PATH_MAX];
+ BLI_join_dirfile(file_path, sizeof(file_path), lib->path, blend_filename);
+ RNA_string_set(op->ptr, "filepath", file_path);
+
+ return true;
+}
+
+struct FileCheckCallbackInfo {
+ struct ReportList *reports;
+ Set<std::string> external_files;
+};
+
+static bool external_file_check_callback(BPathForeachPathData *bpath_data,
+ char * /*path_dst*/,
+ const char *path_src)
+{
+ FileCheckCallbackInfo *callback_info = static_cast<FileCheckCallbackInfo *>(
+ bpath_data->user_data);
+ callback_info->external_files.add(std::string(path_src));
+ return false;
+}
+
+/**
+ * Do a check on any external files (.blend, textures, etc.) being used.
+ * The ASSET_OT_bundle_install operator only works on standalone .blend files
+ * (catalog definition files are fine, though).
+ *
+ * \return true when there are external files, false otherwise.
+ */
+static bool has_external_files(Main *bmain, struct ReportList *reports)
+{
+ struct FileCheckCallbackInfo callback_info = {reports, Set<std::string>()};
+
+ eBPathForeachFlag flag = static_cast<eBPathForeachFlag>(
+ BKE_BPATH_FOREACH_PATH_SKIP_PACKED /* Packed files are fine. */
+ | BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE /* Only report multi-files once, it's enough. */
+ | BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES); /* Only care about actually used files. */
+
+ BPathForeachPathData bpath_data = {
+ /* bmain */ bmain,
+ /* callback_function */ &external_file_check_callback,
+ /* flag */ flag,
+ /* user_data */ &callback_info,
+ /* absolute_base_path */ nullptr,
+ };
+ BKE_bpath_foreach_path_main(&bpath_data);
+
+ if (callback_info.external_files.is_empty()) {
+ /* No external dependencies. */
+ return false;
+ }
+
+ if (callback_info.external_files.size() == 1) {
+ /* Only one external dependency, report it directly. */
+ BKE_reportf(callback_info.reports,
+ RPT_ERROR,
+ "Unable to copy bundle due to external dependency: \"%s\"",
+ callback_info.external_files.begin()->c_str());
+ return true;
+ }
+
+ /* Multiple external dependencies, report the aggregate and put details on console. */
+ BKE_reportf(
+ callback_info.reports,
+ RPT_ERROR,
+ "Unable to copy bundle due to %ld external dependencies; more details on the console",
+ callback_info.external_files.size());
+ printf("Unable to copy bundle due to %ld external dependencies:\n",
+ callback_info.external_files.size());
+ for (const std::string &path : callback_info.external_files) {
+ printf(" \"%s\"\n", path.c_str());
+ }
+ return true;
+}
+
+/* -------------------------------------------------------------------- */
+
+void ED_operatortypes_asset()
{
WM_operatortype_append(ASSET_OT_mark);
WM_operatortype_append(ASSET_OT_clear);
@@ -654,6 +957,7 @@ void ED_operatortypes_asset(void)
WM_operatortype_append(ASSET_OT_catalog_undo);
WM_operatortype_append(ASSET_OT_catalog_redo);
WM_operatortype_append(ASSET_OT_catalog_undo_push);
+ WM_operatortype_append(ASSET_OT_bundle_install);
- WM_operatortype_append(ASSET_OT_list_refresh);
+ WM_operatortype_append(ASSET_OT_library_refresh);
}
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 8ecf41162e9..03ddeebde42 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -71,7 +71,13 @@ typedef enum eCurveElem_Types {
} eCurveElem_Types;
/* internal select utils */
+/**
+ * Returns 1 in case (de)selection was successful.
+ */
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden);
+/**
+ * Returns 1 in case (de)selection was successful.
+ */
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden);
void FONT_OT_text_insert(struct wmOperatorType *ot);
@@ -146,7 +152,14 @@ void ed_editnurb_translate_flag(struct ListBase *editnurb,
uint8_t flag,
const float vec[3],
bool is_2d);
+/**
+ * Only for #OB_SURF.
+ */
bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const uint8_t flag);
+/**
+ * \param axis: is in world-space.
+ * \param cent: is in object-space.
+ */
bool ed_editnurb_spin(float viewmat[4][4],
struct View3D *v3d,
struct Object *obedit,
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 3b05975d22d..a034e4bb10e 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1074,7 +1074,6 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
}
}
-/* return 0 if animation data wasn't changed, 1 otherwise */
int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
{
AnimData *adt = BKE_animdata_from_id(&cu->id);
@@ -1247,7 +1246,6 @@ static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit)
}
}
-/* load editNurb in object */
void ED_curve_editnurb_load(Main *bmain, Object *obedit)
{
ListBase *editnurb = object_editcurve_get(obedit);
@@ -1285,7 +1283,6 @@ void ED_curve_editnurb_load(Main *bmain, Object *obedit)
}
}
-/* make copy in cu->editnurb */
void ED_curve_editnurb_make(Object *obedit)
{
Curve *cu = (Curve *)obedit->data;
@@ -1991,7 +1988,6 @@ static void ed_curve_delete_selected(Object *obedit, View3D *v3d)
}
}
-/* only for OB_SURF */
bool ed_editnurb_extrude_flag(EditNurb *editnurb, const uint8_t flag)
{
BPoint *bp, *bpn, *newbp;
@@ -3859,11 +3855,6 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
const bool use_handles = RNA_boolean_get(op->ptr, "use_handles");
const int type = RNA_enum_get(op->ptr, "type");
- if (ELEM(type, CU_CARDINAL, CU_BSPLINE)) {
- BKE_report(op->reports, RPT_ERROR, "Not yet implemented");
- continue;
- }
-
LISTBASE_FOREACH (Nurb *, nu, editnurb) {
if (ED_curve_nurb_select_check(v3d, nu)) {
const int pntsu_prev = nu->pntsu;
@@ -3907,8 +3898,6 @@ void CURVE_OT_spline_type_set(wmOperatorType *ot)
static const EnumPropertyItem type_items[] = {
{CU_POLY, "POLY", 0, "Poly", ""},
{CU_BEZIER, "BEZIER", 0, "Bezier", ""},
- // {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
- // {CU_BSPLINE, "B_SPLINE", 0, "B-Spline", ""},
{CU_NURBS, "NURBS", 0, "NURBS", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -4909,10 +4898,6 @@ bool ED_curve_editnurb_select_pick(
/** \name Spin Operator
* \{ */
-/**
- * \param axis: is in world-space.
- * \param cent: is in object-space.
- */
bool ed_editnurb_spin(
float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3])
{
@@ -6804,10 +6789,6 @@ void CURVE_OT_shade_flat(wmOperatorType *ot)
/** \name Join Operator
* \{ */
-/**
- * This is used externally, by #OBJECT_OT_join.
- * TODO: shape keys - as with meshes.
- */
int ED_curve_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -6856,9 +6837,9 @@ int ED_curve_join_objects_exec(bContext *C, wmOperator *op)
/* Compensate for different bevel depth. */
bool do_radius = false;
float compensate_radius = 0.0f;
- if (cu->ext2 != 0.0f && cu_active->ext2 != 0.0f) {
+ if (cu->bevel_radius != 0.0f && cu_active->bevel_radius != 0.0f) {
float compensate_scale = mat4_to_scale(cmat);
- compensate_radius = cu->ext2 / cu_active->ext2 * compensate_scale;
+ compensate_radius = cu->bevel_radius / cu_active->bevel_radius * compensate_scale;
do_radius = true;
}
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 784f67ac4f1..403ace56e3b 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -144,7 +144,7 @@ static float stroke_elem_radius_from_pressure(const struct CurveDrawData *cdd,
const float pressure)
{
const Curve *cu = cdd->vc.obedit->data;
- return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->ext2;
+ return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->bevel_radius;
}
static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem)
@@ -364,7 +364,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C),
Object *obedit = cdd->vc.obedit;
Curve *cu = obedit->data;
- if (cu->ext2 > 0.0f) {
+ if (cu->bevel_radius > 0.0f) {
BLI_mempool_iter iter;
const struct StrokeElem *selem;
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index a76e73d3cf1..1229b7eacc8 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -60,7 +60,6 @@
/** \name Utilities
* \{ */
-/* returns 1 in case (de)selection was successful */
bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Types hidden)
{
if ((bezt->hide == 0) || (hidden == HIDDEN)) {
@@ -80,7 +79,6 @@ bool select_beztriple(BezTriple *bezt, bool selstatus, uint8_t flag, eVisible_Ty
return false;
}
-/* returns 1 in case (de)selection was successful */
bool select_bpoint(BPoint *bp, bool selstatus, uint8_t flag, bool hidden)
{
if ((bp->hide == 0) || (hidden == 1)) {
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 210411c6eb5..5619e2efc36 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -305,7 +305,6 @@ static void curve_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_curve_undosys_type(UndoType *ut)
{
ut->name = "Edit Curve";
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 6f18798bd2a..6e0aeb87318 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -71,8 +71,6 @@
static int kill_selection(Object *obedit, int ins);
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
@@ -2199,9 +2197,6 @@ void FONT_OT_unlink(wmOperatorType *ot)
ot->exec = font_unlink_exec;
}
-/**
- * TextBox selection
- */
bool ED_curve_editfont_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 21a6564edf4..45448f18675 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -405,7 +405,6 @@ static void font_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
}
-/* Export for ED_undo_sys. */
void ED_font_undosys_type(UndoType *ut)
{
ut->name = "Edit Font";
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 702fd2e375a..8d32eba1766 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -619,6 +619,7 @@ set(ICON_NAMES
outliner_ob_volume
outliner_data_volume
volume_data
+ current_file
home
documents
temp
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index 2ec287a62e9..1179c9140e2 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -44,9 +44,6 @@
/* own includes */
#include "gizmo_library_intern.h"
-/**
- * Main draw call for GizmoGeomInfo data
- */
void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info,
const bool UNUSED(select),
const float color[4])
diff --git a/source/blender/editors/gizmo_library/gizmo_library_intern.h b/source/blender/editors/gizmo_library/gizmo_library_intern.h
index f3670708543..a75a6b9a6ef 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_intern.h
+++ b/source/blender/editors/gizmo_library/gizmo_library_intern.h
@@ -78,6 +78,10 @@ void gizmo_property_value_reset(bContext *C,
void gizmo_color_get(const struct wmGizmo *gz, const bool highlight, float r_color[4]);
+/**
+ * Takes mouse coordinates and returns them in relation to the gizmo.
+ * Both 2D & 3D supported, use so we can use 2D gizmos in the 3D view.
+ */
bool gizmo_window_project_2d(bContext *C,
const struct wmGizmo *gz,
const float mval[2],
@@ -93,6 +97,9 @@ bool gizmo_window_project_3d(
#include "gizmo_geometry.h"
+/**
+ * Main draw call for #GizmoGeomInfo data
+ */
void wm_gizmo_geometryinfo_draw(const struct GizmoGeomInfo *info,
const bool select,
const float color[4]);
diff --git a/source/blender/editors/gizmo_library/gizmo_library_utils.c b/source/blender/editors/gizmo_library/gizmo_library_utils.c
index a0db2a8e627..0237c6062d1 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_library_utils.c
@@ -175,10 +175,6 @@ void gizmo_color_get(const wmGizmo *gz, const bool highlight, float r_col[4])
/* -------------------------------------------------------------------- */
-/**
- * Takes mouse coordinates and returns them in relation to the gizmo.
- * Both 2D & 3D supported, use so we can use 2D gizmos in the 3D view.
- */
bool gizmo_window_project_2d(bContext *C,
const struct wmGizmo *gz,
const float mval[2],
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index d506af4450a..3362cf9732e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -448,11 +448,6 @@ static void gizmo_arrow_exit(bContext *C, wmGizmo *gz, const bool cancel)
/** \name Arrow Gizmo API
* \{ */
-/**
- * Define a custom property UI range
- *
- * \note Needs to be called before WM_gizmo_target_property_def_rna!
- */
void ED_gizmo_arrow3d_set_ui_range(wmGizmo *gz, const float min, const float max)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
@@ -467,11 +462,6 @@ void ED_gizmo_arrow3d_set_ui_range(wmGizmo *gz, const float min, const float max
arrow->data.is_custom_range_set = true;
}
-/**
- * Define a custom factor for arrow min/max distance
- *
- * \note Needs to be called before WM_gizmo_target_property_def_rna!
- */
void ED_gizmo_arrow3d_set_range_fac(wmGizmo *gz, const float range_fac)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index f286d3930e2..553ea4bbb6e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -59,6 +59,10 @@
#include "../gizmo_geometry.h"
#include "../gizmo_library_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
typedef struct ButtonGizmo2D {
wmGizmo gizmo;
bool is_init;
@@ -69,7 +73,11 @@ typedef struct ButtonGizmo2D {
#define CIRCLE_RESOLUTION 32
+/** \} */
+
/* -------------------------------------------------------------------- */
+/** \name Internal API
+ * \{ */
static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float color[4],
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 7795eed7c21..3705ea38e11 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -788,7 +788,6 @@ static void annotation_draw_data_all(Scene *scene,
/* ----- Annotation Sketches Drawing API ------ */
-/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
void ED_annotation_draw_2dimage(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -857,13 +856,6 @@ void ED_annotation_draw_2dimage(const bContext *C)
annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, area->spacetype);
}
-/**
- * Draw grease-pencil sketches to specified 2d-view
- * assuming that matrices are already set correctly.
- *
- * \note This gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
- * second time with onlyv2d=false for screen-aligned strokes.
- */
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -900,9 +892,6 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype);
}
-/* draw annotations sketches to specified 3d-view assuming that matrices are already set
- * correctly NOTE: this gets called twice - first time with only3d=true to draw 3d-strokes,
- * second time with only3d=false for screen-aligned strokes */
void ED_annotation_draw_view3d(
Scene *scene, struct Depsgraph *depsgraph, View3D *v3d, ARegion *region, bool only3d)
{
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index bf53241a947..fbc44ed58d8 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -78,6 +78,8 @@
/* ******************************************* */
/* 'Globals' and Defines */
+#define DEPTH_INVALID 1.0f
+
/* values for tGPsdata->status */
typedef enum eGPencil_PaintStatus {
GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
@@ -324,6 +326,9 @@ static void annotation_stroke_convertcoords(tGPsdata *p,
float *depth)
{
bGPdata *gpd = p->gpd;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
/* in 3d-space - pt->x/y/z are 3 side-by-side floats */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
@@ -1003,14 +1008,14 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
int last_valid = 0;
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
first_valid = i;
for (i = gpd->runtime.sbuffer_used - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1018,14 +1023,14 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* invalidate non-endpoints, so only blend between first and last */
for (i = first_valid + 1; i < last_valid; i++) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, FLT_MAX);
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, DEPTH_INVALID);
}
}
}
@@ -1661,6 +1666,7 @@ static void annotation_paint_initstroke(tGPsdata *p,
static void annotation_paint_strokeend(tGPsdata *p)
{
ToolSettings *ts = p->scene->toolsettings;
+ const bool is_eraser = (p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) != 0;
/* for surface sketching, need to set the right OpenGL context stuff so that
* the conversions will project the values correctly...
*/
@@ -1676,11 +1682,11 @@ static void annotation_paint_strokeend(tGPsdata *p)
(ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ?
V3D_DEPTH_GPENCIL_ONLY :
V3D_DEPTH_NO_GPENCIL,
- NULL);
+ is_eraser ? NULL : &p->depths);
}
/* check if doing eraser or not */
- if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ if (!is_eraser) {
/* transfer stroke to frame */
annotation_stroke_newfrombuffer(p);
}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 2160aaf705f..6f63529298c 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -412,7 +412,6 @@ static void gpencil_draw_strokes(tGPDdraw *tgpw)
/* ----- General Drawing ------ */
-/* wrapper to draw strokes for filling operator */
void ED_gpencil_draw_fill(tGPDdraw *tgpw)
{
gpencil_draw_strokes(tgpw);
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index fbdb7c8e520..046b3088360 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -55,7 +55,6 @@
/* ***************************************** */
/* Generics - Loopers */
-/* Loops over the gp-frames for a gp-layer, and applies the given callback */
bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl,
Scene *scene,
bool (*gpf_cb)(bGPDframe *, Scene *))
@@ -80,7 +79,6 @@ bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl,
/* ****************************************** */
/* Data Conversion Tools */
-/* make a listing all the gp-frames in a layer as cfraelems */
void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
{
CfraElem *ce;
@@ -106,7 +104,6 @@ void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlys
/* ***************************************** */
/* Selection Tools */
-/* check if one of the frames in this layer is selected */
bool ED_gpencil_layer_frame_select_check(const bGPDlayer *gpl)
{
/* error checking */
@@ -145,7 +142,6 @@ static void gpencil_frame_select(bGPDframe *gpf, short select_mode)
}
}
-/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
{
/* error checking */
@@ -159,7 +155,6 @@ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
}
}
-/* set all/none/invert select */
void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
{
/* error checking */
@@ -171,7 +166,6 @@ void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
ED_gpencil_select_frames(gpl, mode);
}
-/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
{
bGPDframe *gpf;
@@ -187,7 +181,6 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
}
}
-/* select the frames in this layer that occur within the bounds specified */
void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
{
if (gpl == NULL) {
@@ -202,7 +195,6 @@ void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, sh
}
}
-/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
bGPDlayer *gpl,
short tool,
@@ -239,7 +231,6 @@ void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
/* ***************************************** */
/* Frame Editing Tools */
-/* Delete selected frames */
bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl)
{
bool changed = false;
@@ -260,7 +251,6 @@ bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl)
return changed;
}
-/* Duplicate selected frames from given gp-layer */
void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
{
/* error checking */
@@ -284,11 +274,6 @@ void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
}
}
-/**
- * Set keyframe type for selected frames from given gp-layer
- *
- * \param type: The type of keyframe (#eBezTriple_KeyframeType) to set selected frames to.
- */
void ED_gpencil_layer_frames_keytype_set(bGPDlayer *gpl, short type)
{
if (gpl == NULL) {
@@ -320,7 +305,6 @@ static int gpencil_anim_copy_firstframe = 999999999;
static int gpencil_anim_copy_lastframe = -999999999;
static int gpencil_anim_copy_cfra = 0;
-/* This function frees any MEM_calloc'ed copy/paste buffer data */
void ED_gpencil_anim_copybuf_free(void)
{
BKE_gpencil_free_layers(&gpencil_anim_copybuf);
@@ -331,11 +315,6 @@ void ED_gpencil_anim_copybuf_free(void)
gpencil_anim_copy_cfra = 0;
}
-/* This function adds data to the copy/paste buffer, freeing existing data first
- * Only the selected GP-layers get their selected keyframes copied.
- *
- * Returns whether the copy operation was successful or not
- */
bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -404,7 +383,6 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
return true;
}
-/* Pastes keyframes from buffer, and reports success */
bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
{
ListBase anim_data = {NULL, NULL};
@@ -547,7 +525,6 @@ static bool gpencil_frame_snap_nearmarker(bGPDframe *gpf, Scene *scene)
return false;
}
-/* snap selected frames to ... */
void ED_gpencil_layer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
switch (mode) {
@@ -648,8 +625,6 @@ static bool gpencil_frame_mirror_marker(bGPDframe *gpf, Scene *scene)
return false;
}
-/* mirror selected gp-frames on... */
-/* TODO: mirror over a specific time */
void ED_gpencil_layer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
switch (mode) {
diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c
index 3aa16e54597..4e4650e575c 100644
--- a/source/blender/editors/gpencil/gpencil_add_blank.c
+++ b/source/blender/editors/gpencil/gpencil_add_blank.c
@@ -76,7 +76,6 @@ static const ColorTemplate gp_stroke_material_black = {
/* ***************************************************************** */
/* Blank API */
-/* Add a Simple empty object with one layer and one color. */
void ED_gpencil_create_blank(bContext *C, Object *ob, float UNUSED(mat[4][4]))
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_lineart.c b/source/blender/editors/gpencil/gpencil_add_lineart.c
index ac0da0ad1db..aad2d978bfb 100644
--- a/source/blender/editors/gpencil/gpencil_add_lineart.c
+++ b/source/blender/editors/gpencil/gpencil_add_lineart.c
@@ -83,7 +83,6 @@ static const ColorTemplate gp_stroke_material_black = {
/* ***************************************************************** */
/* LineArt API */
-/* Add a Simple LineArt setup. */
void ED_gpencil_create_lineart(bContext *C, Object *ob)
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index 8d60ef3ed12..3b952dbe7da 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -39,13 +39,6 @@
#include "ED_gpencil.h"
-/**
- * Populate stroke with point data from data buffers.
- * \param gps: Grease pencil stroke
- * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
- * \param totpoints: Total of points
- * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
- */
void ED_gpencil_stroke_init_data(bGPDstroke *gps,
const float *array,
const int totpoints,
@@ -842,7 +835,6 @@ static const ColorTemplate gp_monkey_pct_pupils = {
/* ***************************************************************** */
/* Monkey API */
-/* add a 2D Suzanne (original model created by Matias Mendiola) */
void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index 73c4e64dd9a..d9e652392b4 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -204,8 +204,6 @@ static const ColorTemplate gp_stroke_material_grey = {
/* ***************************************************************** */
/* Stroke API */
-/* Add a Simple stroke with colors
- * (original design created by Daniel M. Lara and Matias Mendiola). */
void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 656fec565df..bf414851aed 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1324,7 +1324,7 @@ static void gpencil_layer_to_curve(bContext *C,
cu->flag |= CU_3D;
cu->bevresol = gtd->bevel_resolution;
- cu->ext2 = gtd->bevel_depth;
+ cu->bevel_radius = gtd->bevel_depth;
gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index db2104dfdf9..bea8126cfcc 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -2809,7 +2809,6 @@ static void gpencil_joined_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
}
}
-/* join objects called from OBJECT_OT_join */
int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -3697,7 +3696,6 @@ void GPENCIL_OT_materials_copy_to_object(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Parent GPencil object to Lattice */
bool ED_gpencil_add_lattice_modifier(const bContext *C,
ReportList *reports,
Object *ob,
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 3fc08096ab5..2a656ac3aad 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -51,6 +51,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_curve.h"
@@ -1381,11 +1382,6 @@ void GPENCIL_OT_extrude(wmOperatorType *ot)
* from several different layers into a single layer.
* \{ */
-/**
- * list of #bGPDstroke instances
- *
- * \note is exposed within the editors/gpencil module so that other tools can use it too.
- */
ListBase gpencil_strokes_copypastebuf = {NULL, NULL};
/* Hash for hanging on to all the colors used by strokes in the buffer
@@ -1429,7 +1425,6 @@ static void gpencil_strokes_copypastebuf_colors_name_to_material_free(GHash *nam
BLI_ghash_free(name_to_ma, MEM_freeN, NULL);
}
-/* Free copy/paste buffer data */
void ED_gpencil_strokes_copybuf_free(void)
{
bGPDstroke *gps, *gpsn;
@@ -1462,10 +1457,6 @@ void ED_gpencil_strokes_copybuf_free(void)
gpencil_strokes_copypastebuf.first = gpencil_strokes_copypastebuf.last = NULL;
}
-/**
- * Ensure that destination datablock has all the colors the pasted strokes need.
- * Helper function for copy-pasting strokes
- */
GHash *gpencil_copybuf_validate_colormap(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -2654,7 +2645,6 @@ static int gpencil_delete_selected_points(bContext *C)
return OPERATOR_CANCELLED;
}
-/* simple wrapper to external call */
int gpencil_delete_selected_point_wrap(bContext *C)
{
return gpencil_delete_selected_points(C);
@@ -3319,10 +3309,6 @@ static bool gpencil_cyclical_set_curve_edit_poll_property(const bContext *C,
return true;
}
-/**
- * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
- * option to force opened/closed strokes instead of just toggle behavior.
- */
void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -3434,9 +3420,6 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/**
- * Change Stroke caps mode Rounded or Flat
- */
void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
{
static const EnumPropertyItem toggle_type[] = {
@@ -3966,7 +3949,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
/* perform smoothing */
if (smooth_position) {
- BKE_gpencil_stroke_smooth_point(gps, i, factor);
+ BKE_gpencil_stroke_smooth_point(gps, i, factor, false);
}
if (smooth_strength) {
BKE_gpencil_stroke_smooth_strength(gps, i, factor);
@@ -4587,6 +4570,9 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
id_us_min(ob_dst->data);
ob_dst->data = (bGPdata *)gpd_dst;
+ BKE_defgroup_copy_list(&gpd_dst->vertex_group_names, &gpd_src->vertex_group_names);
+ gpd_dst->vertex_group_active_index = gpd_src->vertex_group_active_index;
+
/* Loop old data-block and separate parts. */
if (ELEM(mode, GP_SEPARATE_POINT, GP_SEPARATE_STROKE)) {
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
@@ -5351,6 +5337,7 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot)
ot->srna, "use_unselected", 0, "Unselected", "Use whole stroke, not only selected points");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/gpencil/gpencil_edit_curve.c b/source/blender/editors/gpencil/gpencil_edit_curve.c
index e766a410889..2d7497357f2 100644
--- a/source/blender/editors/gpencil/gpencil_edit_curve.c
+++ b/source/blender/editors/gpencil/gpencil_edit_curve.c
@@ -51,6 +51,10 @@
#include "gpencil_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Enter Edit-Mode
+ * \{ */
+
/* Poll callback for checking if there is an active layer and we are in curve edit mode. */
static bool gpencil_curve_edit_mode_poll(bContext *C)
{
@@ -135,6 +139,12 @@ void GPENCIL_OT_stroke_enter_editcurve_mode(wmOperatorType *ot)
RNA_def_property_ui_range(prop, FLT_MIN, 10.0f, 0.1f, 5);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Handle Type
+ * \{ */
+
static int gpencil_editcurve_set_handle_type_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 9860c75f290..c3af28d4382 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1415,7 +1415,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
}
else {
if (interp_depth) {
- interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
+ interp_sparse_array(tgpf->depth_arr, totpoints, DEPTH_INVALID);
}
}
}
@@ -1570,7 +1570,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
float smoothfac = 1.0f;
for (int r = 0; r < 1; r++) {
for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce, false);
}
reduce += 0.25f; /* reduce the factor */
}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 3f3fd4fff39..601780ea651 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -27,6 +27,8 @@
#include "ED_numinput.h"
+#define DEPTH_INVALID 1.0f
+
/* internal exports only */
struct Material;
struct bGPDspoint;
@@ -104,6 +106,10 @@ typedef struct tGPDdraw {
} tGPDdraw;
/* Modal Operator Drawing Callbacks ------------------------ */
+
+/**
+ * Wrapper to draw strokes for filling operator.
+ */
void ED_gpencil_draw_fill(struct tGPDdraw *tgpw);
/* ***************************************************** */
@@ -229,28 +235,74 @@ typedef struct tGPDprimitive {
} tGPDprimitive;
+/**
+ * Check whether a given stroke segment is inside a circular brush
+ *
+ * \param mval: The current screen-space coordinates (midpoint) of the brush
+ * \param rad: The radius of the brush
+ *
+ * \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
+ * \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
+ */
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1);
+/**
+ * Init settings for stroke point space conversions
+ *
+ * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
+ */
void gpencil_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screen-space (2D)
+ *
+ * \param[out] r_x: The screen-space x-coordinate of the point
+ * \param[out] r_y: The screen-space y-coordinate of the point
+ *
+ * \warning This assumes that the caller has already checked
+ * whether the stroke in question can be drawn.
+ */
void gpencil_point_to_xy(const GP_SpaceConversion *gsc,
const struct bGPDstroke *gps,
const struct bGPDspoint *pt,
int *r_x,
int *r_y);
+/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screen-space (2D).
+ *
+ * Just like #gpencil_point_to_xy(), except the resulting coordinates are floats not ints.
+ * Use this version to solve "stair-step" artifacts which may arise when
+ * round-tripping the calculations.
+ *
+ * \param r_x: The screen-space x-coordinate of the point.
+ * \param r_y: The screen-space y-coordinate of the point.
+ *
+ * \warning This assumes that the caller has already checked
+ * whether the stroke in question can be drawn.
+ */
void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const bGPDspoint *pt,
float *r_x,
float *r_y);
+/**
+ * Convert point to parent space
+ *
+ * \param pt: Original point
+ * \param diff_mat: Matrix with the difference between original parent matrix
+ * \param[out] r_pt: Pointer to new point after apply matrix
+ */
void gpencil_point_to_parent_space(const bGPDspoint *pt,
const float diff_mat[4][4],
bGPDspoint *r_pt);
/**
* Change points position relative to parent object
*/
+/**
+ * Change position relative to parent object
+ */
void gpencil_apply_parent(struct Depsgraph *depsgraph,
struct Object *obact,
bGPDlayer *gpl,
@@ -258,61 +310,127 @@ void gpencil_apply_parent(struct Depsgraph *depsgraph,
/**
* Change point position relative to parent object
*/
+/**
+ * Change point position relative to parent object
+ */
void gpencil_apply_parent_point(struct Depsgraph *depsgraph,
struct Object *obact,
bGPDlayer *gpl,
bGPDspoint *pt);
+/**
+ * generic based on gpencil_point_to_xy_fl
+ */
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
const short flag,
const float pt[3],
float xy[2]);
+/**
+ * Project screen-space coordinates to 3D-space
+ *
+ * For use with editing tools where it is easier to perform the operations in 2D,
+ * and then later convert the transformed points back to 3D.
+ *
+ * \param screen_co: The screen-space 2D coordinates to convert to
+ * \param r_out: The resulting 3D coordinates of the input point
+ *
+ * \note We include this as a utility function, since the standard method
+ * involves quite a few steps, which are invariably always the same
+ * for all GPencil operations. So, it's nicer to just centralize these.
+ *
+ * \warning Assumes that it is getting called in a 3D view only.
+ */
bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
struct Scene *scene,
const float screen_co[2],
float r_out[3]);
/* helper to convert 2d to 3d */
+
+/**
+ * Convert #tGPspoint (temporary 2D/screen-space point data used by GP modal operators)
+ * to 3D coordinates.
+ *
+ * \param point2D: The screen-space 2D point data to convert.
+ * \param depth: Depth array (via #ED_view3d_depth_read_cached()).
+ * \param r_out: The resulting 2D point data.
+ */
void gpencil_stroke_convertcoords_tpoint(struct Scene *scene,
struct ARegion *region,
struct Object *ob,
const struct tGPspoint *point2D,
float *depth,
- float out[3]);
+ float r_out[3]);
/* Poll Callbacks ------------------------------------ */
/* gpencil_utils.c */
+/**
+ * Poll callback for adding data/layers - special.
+ */
bool gpencil_add_poll(struct bContext *C);
+/**
+ * Poll callback for checking if there is an active layer.
+ */
bool gpencil_active_layer_poll(struct bContext *C);
+/**
+ * Poll callback for checking if there is an active brush.
+ */
bool gpencil_active_brush_poll(struct bContext *C);
bool gpencil_brush_create_presets_poll(bContext *C);
/* Copy/Paste Buffer --------------------------------- */
/* gpencil_edit.c */
+/**
+ * list of #bGPDstroke instances
+ *
+ * \note is exposed within the editors/gpencil module so that other tools can use it too.
+ */
extern ListBase gpencil_strokes_copypastebuf;
/* Build a map for converting between old color-names and destination-color-refs. */
+/**
+ * Ensure that destination datablock has all the colors the pasted strokes need.
+ * Helper function for copy-pasting strokes
+ */
struct GHash *gpencil_copybuf_validate_colormap(struct bContext *C);
/* Stroke Editing ------------------------------------ */
+/**
+ * Simple wrapper to external call.
+ */
int gpencil_delete_selected_point_wrap(bContext *C);
+/**
+ * Subdivide a stroke once, by adding a point half way between each pair of existing points
+ * \param gpd: Datablock
+ * \param gps: Stroke data
+ * \param subdivide: Number of times to subdivide
+ */
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide);
/* Layers Enums -------------------------------------- */
+/**
+ * Just existing layers.
+ */
const struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Existing + Option to add/use new layer.
+ */
const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Just existing Materials.
+ */
const struct EnumPropertyItem *ED_gpencil_material_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -405,6 +523,9 @@ void GPENCIL_OT_stroke_editcurve_set_handle_type(struct wmOperatorType *ot);
/* stroke sculpting -- */
+/**
+ * Also used for weight paint.
+ */
void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot);
void GPENCIL_OT_weight_paint(struct wmOperatorType *ot);
@@ -474,7 +595,14 @@ enum {
void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_change_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_apply_thickness(struct wmOperatorType *ot);
+/**
+ * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
+ * option to force opened/closed strokes instead of just toggle behavior.
+ */
void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot);
+/**
+ * Change Stroke caps mode Rounded or Flat
+ */
void GPENCIL_OT_stroke_caps_set(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_join(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 22127d7ac3b..2023ae5fe27 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -336,7 +336,7 @@ static void gpencil_interpolate_smooth_stroke(bGPDstroke *gps,
float reduce = 0.0f;
for (int r = 0; r < smooth_steps; r++) {
for (int i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce, false);
BKE_gpencil_stroke_smooth_strength(gps, i, smooth_factor);
}
reduce += 0.25f; /* reduce the factor */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index f0118988559..dabe2050b28 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -429,6 +429,9 @@ static void gpencil_stroke_convertcoords(tGPsdata *p,
float *depth)
{
bGPdata *gpd = p->gpd;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
/* in 3d-space - pt->x/y/z are 3 side-by-side floats */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
@@ -1126,7 +1129,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* find first valid contact point */
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1138,7 +1141,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
}
else {
for (i = gpd->runtime.sbuffer_used - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -1148,14 +1151,14 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
* first and last contact in an imaginary line between them */
for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
if (!ELEM(i, first_valid, last_valid)) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, FLT_MAX);
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_used, DEPTH_INVALID);
}
}
}
@@ -1202,7 +1205,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
for (i = 0; i < gps->totpoints - 1; i++) {
BKE_gpencil_stroke_smooth_point(
- gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ gps, i, brush->gpencil_settings->draw_smoothfac - reduce, false);
BKE_gpencil_stroke_smooth_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
}
reduce += 0.25f; /* reduce the factor */
@@ -1214,7 +1217,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
float sfac = interpf(1.0f, 0.2f, ifac);
for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, sfac);
+ BKE_gpencil_stroke_smooth_point(gps, i, sfac, false);
BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 7382aca9a87..8157e9d8fe7 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -841,7 +841,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* find first valid contact point */
int i;
for (i = 0; i < gps->totpoints; i++) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -853,7 +853,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
else {
for (i = gps->totpoints - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX) {
+ if (depth_arr[i] != DEPTH_INVALID) {
break;
}
}
@@ -864,14 +864,14 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
* first and last contact in an imaginary line between them */
for (i = 0; i < gps->totpoints; i++) {
if (!ELEM(i, first_valid, last_valid)) {
- depth_arr[i] = FLT_MAX;
+ depth_arr[i] = DEPTH_INVALID;
}
}
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gps->totpoints, FLT_MAX);
+ interp_sparse_array(depth_arr, gps->totpoints, DEPTH_INVALID);
}
}
}
@@ -1041,7 +1041,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
/* add small offset to keep stroke over the surface */
- if ((depth_arr) && (gpd->zdepth_offset > 0.0f)) {
+ if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) {
depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f));
}
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index e9a6beab798..186c45c9f39 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -337,7 +337,7 @@ static bool gpencil_brush_smooth_apply(tGP_BrushEditData *gso,
/* perform smoothing */
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
- BKE_gpencil_stroke_smooth_point(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_point(gps, pt_index, inf, false);
}
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
@@ -2134,7 +2134,6 @@ static int gpencil_sculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
-/* Also used for weight paint. */
void GPENCIL_OT_sculpt_paint(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 6ad2fffc773..ed8d2996b6a 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -248,6 +248,7 @@ static void select_all_curve_points(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gp
/* -------------------------------------------------------------------- */
/** \name Select All Operator
* \{ */
+
static bool gpencil_select_all_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
diff --git a/source/blender/editors/gpencil/gpencil_trace.h b/source/blender/editors/gpencil/gpencil_trace.h
index 25d8dac2734..7c62288f65d 100644
--- a/source/blender/editors/gpencil/gpencil_trace.h
+++ b/source/blender/editors/gpencil/gpencil_trace.h
@@ -59,16 +59,48 @@ struct bGPDframe;
#define GPENCIL_TRACE_MODE_SINGLE 0
#define GPENCIL_TRACE_MODE_SEQUENCE 1
+/**
+ * Print trace bitmap for debugging.
+ * \param f: Output handle. Use `stderr` for printing
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm);
+/**
+ * Return new un-initialized trace bitmap
+ * \param w: Width in pixels
+ * \param h: Height in pixels
+ * \return Trace bitmap
+ */
potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h);
+/**
+ * Free a trace bitmap
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm);
+/**
+ * Invert the given bitmap (Black to White)
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm);
+/**
+ * Convert image to BW bitmap for tracing
+ * \param ibuf: ImBuf of the image
+ * \param bm: Trace bitmap
+ */
void ED_gpencil_trace_image_to_bitmap(struct ImBuf *ibuf,
const potrace_bitmap_t *bm,
const float threshold);
+/**
+ * Convert Potrace Bitmap to Grease Pencil strokes
+ * \param st: Data with traced data
+ * \param ob: Target grease pencil object
+ * \param offset: Offset to center
+ * \param scale: Scale of the output
+ * \param sample: Sample distance to distribute points
+ */
void ED_gpencil_trace_data_to_strokes(struct Main *bmain,
potrace_state_t *st,
struct Object *ob,
diff --git a/source/blender/editors/gpencil/gpencil_trace_utils.c b/source/blender/editors/gpencil/gpencil_trace_utils.c
index 970afc3ff6b..f5690904fcf 100644
--- a/source/blender/editors/gpencil/gpencil_trace_utils.c
+++ b/source/blender/editors/gpencil/gpencil_trace_utils.c
@@ -46,11 +46,6 @@
#include "gpencil_trace.h"
-/**
- * Print trace bitmap for debugging.
- * \param f: Output handle. Use `stderr` for printing
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm)
{
int32_t x, y;
@@ -77,12 +72,6 @@ void ED_gpencil_trace_bitmap_print(FILE *f, const potrace_bitmap_t *bm)
}
}
-/**
- * Return new un-initialized trace bitmap
- * \param w: Width in pixels
- * \param h: Height in pixels
- * \return Trace bitmap
- */
potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h)
{
potrace_bitmap_t *bm;
@@ -104,10 +93,6 @@ potrace_bitmap_t *ED_gpencil_trace_bitmap_new(int32_t w, int32_t h)
return bm;
}
-/**
- * Free a trace bitmap
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm)
{
if (bm != NULL) {
@@ -116,10 +101,6 @@ void ED_gpencil_trace_bitmap_free(const potrace_bitmap_t *bm)
MEM_SAFE_FREE(bm);
}
-/**
- * Invert the given bitmap (Black to White)
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm)
{
int32_t dy = bm->dy;
@@ -162,11 +143,6 @@ static void pixel_at_index(const ImBuf *ibuf, const int32_t idx, float r_col[4])
}
}
-/**
- * Convert image to BW bitmap for tracing
- * \param ibuf: ImBuf of the image
- * \param bm: Trace bitmap
- */
void ED_gpencil_trace_image_to_bitmap(ImBuf *ibuf,
const potrace_bitmap_t *bm,
const float threshold)
@@ -231,14 +207,6 @@ static void add_bezier(bGPDstroke *gps,
}
}
-/**
- * Convert Potrace Bitmap to Grease Pencil strokes
- * \param st: Data with traced data
- * \param ob: Target grease pencil object
- * \param offset: Offset to center
- * \param scale: Scale of the output
- * \param sample: Sample distance to distribute points
- */
void ED_gpencil_trace_data_to_strokes(Main *bmain,
potrace_state_t *st,
Object *ob,
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 99b8b672327..ec70febc80c 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -62,9 +62,6 @@ int ED_gpencil_session_active(void)
return (BLI_listbase_is_empty(&undo_nodes) == false);
}
-/**
- * \param step: eUndoStepDir.
- */
int ED_undo_gpencil_step(bContext *C, const int step)
{
bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 86df452f49a..f082af979a1 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -96,11 +96,6 @@
/* ******************************************************** */
/* Context Wrangling... */
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it,
- * when context info is not available.
- */
bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, PointerRNA *r_ptr)
{
/* if there's an active area, check if the particular editor may
@@ -130,11 +125,6 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, Pointer
return NULL;
}
-/**
- * Get pointer to active Grease Pencil data-block for annotations,
- * and an RNA-pointer to trace back to whatever owns it,
- * when context info is not available.
- */
bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
ScrArea *area,
Scene *scene,
@@ -233,10 +223,6 @@ bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
return NULL;
}
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it.
- */
bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ScrArea *area = CTX_wm_area(C);
@@ -245,10 +231,6 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
return ED_gpencil_data_get_pointers_direct(area, ob, r_ptr);
}
-/**
- * Get pointer to active Grease Pencil data-block,
- * and an RNA-pointer to trace back to whatever owns it.
- */
bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ID *screen_id = (ID *)CTX_wm_screen(C);
@@ -259,23 +241,18 @@ bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
}
/* -------------------------------------------------------- */
-/* Get the active Grease Pencil data-block, when context is not available */
bGPdata *ED_gpencil_data_get_active_direct(ScrArea *area, Object *ob)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(area, ob, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/* Get the active Grease Pencil data-block, when context is not available */
bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scene *scene)
{
bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, area, scene, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/**
- * Get the active Grease Pencil data-block
- */
bGPdata *ED_gpencil_data_get_active(const bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -285,24 +262,12 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C)
return ob->data;
}
-/**
- * Get the active Grease Pencil data-block
- * \note This is the original (#G.main) copy of the data-block, stored in files.
- * Do not use for reading evaluated copies of GP Objects data.
- */
bGPdata *ED_annotation_data_get_active(const bContext *C)
{
bGPdata **gpd_ptr = ED_annotation_data_get_pointers(C, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/**
- * Get the evaluated copy of the active Grease Pencil data-block (where applicable)
- * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP data-block
- * (i.e. a copy of the active GP data-block for the active object, where modifiers have been
- * applied). This is needed to correctly work with "Copy-on-Write".
- * - For all other editors (i.e. "GP Annotations"), this just gives the active data-block
- * like for #ED_gpencil_data_get_active()
- */
+
bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -316,10 +281,6 @@ bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
/* -------------------------------------------------------- */
-/**
- * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
- * is for annotation usage.
- */
bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
{
/* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
@@ -330,7 +291,6 @@ bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
/* ******************************************************** */
/* Keyframe Indicator Checks */
-/* Check whether there's an active GP keyframe on the current frame */
bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
{
if (ob && ob->data && (ob->type == OB_GPENCIL)) {
@@ -351,7 +311,6 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
/* ******************************************************** */
/* Poll Callbacks */
-/* poll callback for adding data/layers - special */
bool gpencil_add_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -363,7 +322,6 @@ bool gpencil_add_poll(bContext *C)
return (gpd != NULL);
}
-/* poll callback for checking if there is an active layer */
bool gpencil_active_layer_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -376,7 +334,6 @@ bool gpencil_active_layer_poll(bContext *C)
return (gpl != NULL);
}
-/* poll callback for checking if there is an active brush */
bool gpencil_active_brush_poll(bContext *C)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -391,7 +348,6 @@ bool gpencil_active_brush_poll(bContext *C)
/* Dynamic Enums of GP Layers */
/* NOTE: These include an option to create a new layer and use that... */
-/* Just existing layers */
const EnumPropertyItem *ED_gpencil_layers_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -429,7 +385,6 @@ const EnumPropertyItem *ED_gpencil_layers_enum_itemf(bContext *C,
return item;
}
-/* Existing + Option to add/use new layer */
const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -482,7 +437,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
return item;
}
-/* Just existing Materials */
const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -519,15 +473,6 @@ const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C,
/* ******************************************************** */
/* Brush Tool Core */
-/**
- * Check whether a given stroke segment is inside a circular brush
- *
- * \param mval: The current screen-space coordinates (midpoint) of the brush
- * \param rad: The radius of the brush
- *
- * \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
- * \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
- */
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
{
/* simple within-radius check for now */
@@ -577,8 +522,6 @@ bool ED_gpencil_layer_has_selected_stroke(const bGPDlayer *gpl, const bool is_mu
/* ******************************************************** */
/* Stroke Validity Testing */
-/* Check whether given stroke can be edited given the supplied context */
-/* TODO: do we need additional flags for screenspace vs dataspace? */
bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps)
{
/* sanity check */
@@ -603,14 +546,12 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps
return true;
}
-/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
{
ScrArea *area = CTX_wm_area(C);
return ED_gpencil_stroke_can_use_direct(area, gps);
}
-/* Check whether given stroke can be edited for the current color */
bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
{
/* check if the color is editable */
@@ -628,7 +569,6 @@ bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const
return true;
}
-/* Check whether given stroke is visible for the current material. */
bool ED_gpencil_stroke_material_visible(Object *ob, const bGPDstroke *gps)
{
/* check if the color is editable */
@@ -646,11 +586,6 @@ bool ED_gpencil_stroke_material_visible(Object *ob, const bGPDstroke *gps)
/* ******************************************************** */
/* Space Conversion */
-/**
- * Init settings for stroke point space conversions
- *
- * \param r_gsc: [out] The space conversion settings struct, populated with necessary params
- */
void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
ScrArea *area = CTX_wm_area(C);
@@ -691,13 +626,6 @@ void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
-/**
- * Convert point to parent space
- *
- * \param pt: Original point
- * \param diff_mat: Matrix with the difference between original parent matrix
- * \param[out] r_pt: Pointer to new point after apply matrix
- */
void gpencil_point_to_parent_space(const bGPDspoint *pt,
const float diff_mat[4][4],
bGPDspoint *r_pt)
@@ -708,9 +636,6 @@ void gpencil_point_to_parent_space(const bGPDspoint *pt,
copy_v3_v3(&r_pt->x, fpt);
}
-/**
- * Change position relative to parent object
- */
void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
@@ -731,9 +656,6 @@ void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, b
}
}
-/**
- * Change point position relative to parent object
- */
void gpencil_apply_parent_point(Depsgraph *depsgraph,
Object *obact,
bGPDlayer *gpl,
@@ -752,15 +674,6 @@ void gpencil_apply_parent_point(Depsgraph *depsgraph,
copy_v3_v3(&pt->x, fpt);
}
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
- *
- * \param[out] r_x: The screen-space x-coordinate of the point
- * \param[out] r_y: The screen-space y-coordinate of the point
- *
- * \warning This assumes that the caller has already checked
- * whether the stroke in question can be drawn.
- */
void gpencil_point_to_xy(
const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, int *r_x, int *r_y)
{
@@ -803,19 +716,6 @@ void gpencil_point_to_xy(
}
}
-/**
- * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D).
- *
- * Just like #gpencil_point_to_xy(), except the resulting coordinates are floats not ints.
- * Use this version to solve "stair-step" artifacts which may arise when
- * roundtripping the calculations.
- *
- * \param r_x: The screen-space x-coordinate of the point.
- * \param r_y: The screen-space y-coordinate of the point.
- *
- * \warning This assumes that the caller has already checked
- * whether the stroke in question can be drawn.
- */
void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const bGPDspoint *pt,
@@ -873,9 +773,6 @@ void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
}
}
-/**
- * generic based on gpencil_point_to_xy_fl
- */
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
const short flag,
const float pt[3],
@@ -930,21 +827,6 @@ void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
}
}
-/**
- * Project screenspace coordinates to 3D-space
- *
- * For use with editing tools where it is easier to perform the operations in 2D,
- * and then later convert the transformed points back to 3D.
- *
- * \param screen_co: The screenspace 2D coordinates to convert to
- * \param r_out: The resulting 3D coordinates of the input point
- *
- * \note We include this as a utility function, since the standard method
- * involves quite a few steps, which are invariably always the same
- * for all GPencil operations. So, it's nicer to just centralize these.
- *
- * \warning Assumes that it is getting called in a 3D view only.
- */
bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
Scene *scene,
const float screen_co[2],
@@ -974,14 +856,6 @@ bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc,
return false;
}
-/**
- * Convert tGPspoint (temporary 2D/screenspace point data used by GP modal operators)
- * to 3D coordinates.
- *
- * \param point2D: The screen-space 2D point data to convert.
- * \param depth: Depth array (via #ED_view3d_depth_read_cached()).
- * \param r_out: The resulting 2D point data.
- */
void gpencil_stroke_convertcoords_tpoint(Scene *scene,
ARegion *region,
Object *ob,
@@ -991,6 +865,10 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
{
ToolSettings *ts = scene->toolsettings;
+ if (depth && (*depth == DEPTH_INVALID)) {
+ depth = NULL;
+ }
+
int mval_i[2];
round_v2i_v2fl(mval_i, &point2D->x);
@@ -1023,10 +901,6 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
}
}
-/**
- * Get drawing reference point for conversion or projection of the stroke
- * \param r_vec: Reference point found
- */
void ED_gpencil_drawing_reference_get(const Scene *scene,
const Object *ob,
char align_flag,
@@ -1094,9 +968,6 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
}
}
-/**
- * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
- */
void ED_gpencil_project_stroke_to_plane(const Scene *scene,
const Object *ob,
const RegionView3D *rv3d,
@@ -1175,7 +1046,6 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene,
}
}
-/* Reproject selected strokes */
void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
const GP_SpaceConversion *gsc,
SnapObjectContext *sctx,
@@ -1316,10 +1186,6 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
}
}
-/**
- * Reproject given point to a plane locked to axis to avoid stroke offset
- * \param pt: Point to affect (used for input & output).
- */
void ED_gpencil_project_point_to_plane(const Scene *scene,
const Object *ob,
bGPDlayer *gpl,
@@ -1402,12 +1268,6 @@ void ED_gpencil_project_point_to_plane(const Scene *scene,
/* XXX: Check if these functions duplicate stuff in blenkernel,
* and/or whether we should just deduplicate. */
-/**
- * Subdivide a stroke once, by adding a point half way between each pair of existing points
- * \param gpd: Datablock
- * \param gps: Stroke data
- * \param subdivide: Number of times to subdivide
- */
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide)
{
bGPDspoint *temp_points;
@@ -1501,7 +1361,6 @@ void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
-/* Reset parent matrix for all layers. */
void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
{
bGPDspoint *pt;
@@ -1551,7 +1410,6 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata
/* ******************************************************** */
/* GP Object Stuff */
-/* Helper function to create new OB_GPENCIL Object */
Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view_bits)
{
const float rot[3] = {0.0f};
@@ -1564,7 +1422,6 @@ Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view
return ob;
}
-/* Helper function to create default colors and drawing brushes */
void ED_gpencil_add_defaults(bContext *C, Object *ob)
{
Main *bmain = CTX_data_main(C);
@@ -1596,7 +1453,6 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* ******************************************************** */
/* Vertex Groups */
-/* assign points to vertex group */
void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1650,7 +1506,6 @@ void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
CTX_DATA_END;
}
-/* remove points from vertex group */
void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1703,7 +1558,6 @@ void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
CTX_DATA_END;
}
-/* select points of vertex group */
void ED_gpencil_vgroup_select(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1758,7 +1612,6 @@ void ED_gpencil_vgroup_select(bContext *C, Object *ob)
CTX_DATA_END;
}
-/* unselect points of vertex group */
void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
@@ -1839,7 +1692,6 @@ static bool gpencil_check_cursor_region(bContext *C, const int mval_i[2])
return false;
}
-/* draw eraser cursor */
void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
{
short radius = (short)brush->size;
@@ -2075,7 +1927,6 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
immUnbindProgram();
}
-/* Turn brush cursor in on/off */
void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
{
Scene *scene = CTX_data_scene(C);
@@ -2103,7 +1954,6 @@ void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
}
}
-/* set object modes */
void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
{
if (!gpd) {
@@ -2190,9 +2040,6 @@ static void gpencil_stroke_convertcoords(ARegion *region,
}
}
-/**
- * Convert 2d #tGPspoint to 3d #bGPDspoint.
- */
void ED_gpencil_tpoint_to_point(ARegion *region,
float origin[3],
const tGPspoint *tpt,
@@ -2210,9 +2057,6 @@ void ED_gpencil_tpoint_to_point(ARegion *region,
pt->uv_rot = tpt->uv_rot;
}
-/**
- * Recalculate UV for any stroke using the material.
- */
void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
{
Material *gps_ma = NULL;
@@ -2420,7 +2264,6 @@ static float gpencil_calc_factor(const float p2d_a1[2],
return f;
}
-/* extend selection to stroke intersections */
int ED_gpencil_select_stroke_segment(bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
@@ -2801,10 +2644,6 @@ void ED_gpencil_select_curve_toggle_all(bContext *C, int action)
}
}
-/**
- * Ensure the #tGPspoint buffer (while drawing stroke)
- * size is enough to save all points of the stroke.
- */
tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
@@ -2855,9 +2694,6 @@ void ED_gpencil_sbuffer_update_eval(bGPdata *gpd, Object *ob_eval)
gpd_eval->runtime.cp_points = gpd->runtime.cp_points;
}
-/**
- * Tag all scene grease pencil object to update.
- */
void ED_gpencil_tag_scene_gpencil(Scene *scene)
{
/* Mark all grease pencil data-blocks of the scene. */
@@ -3106,7 +2942,6 @@ void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph,
}
}
-/* Get the bigger 2D bound box points. */
void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
const bGPDstroke *gps,
const float diff_mat[4][4],
@@ -3140,7 +2975,6 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
}
}
-/* Check if the stroke collides with brush. */
bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bGPDstroke *gps,
const float mouse[2],
@@ -3167,15 +3001,6 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
}
-/**
- * Check if a point is inside of the stroke.
- *
- * \param gps: Stroke to check.
- * \param gsc: Space conversion data.
- * \param mouse: Mouse position.
- * \param diff_mat: View matrix.
- * \return True if the point is inside.
- */
bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
const GP_SpaceConversion *gsc,
const int mouse[2],
@@ -3214,7 +3039,6 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
return hit;
}
-/* Get extremes of stroke in 2D using current view. */
void ED_gpencil_stroke_extremes_to2d(const GP_SpaceConversion *gsc,
const float diff_mat[4][4],
bGPDstroke *gps,
@@ -3329,7 +3153,6 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
return gps_rtn;
}
-/* Join two stroke using a contact point index and trimming the rest. */
bGPDstroke *ED_gpencil_stroke_join_and_trim(
bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *gps_dst, const int pt_index)
{
@@ -3399,7 +3222,6 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim(
return gps_final;
}
-/* Close if the distance between extremes is below threshold. */
void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
{
if (gps == NULL) {
@@ -3416,7 +3238,6 @@ void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold)
}
}
-/* Merge two layers. */
void ED_gpencil_layer_merge(bGPdata *gpd,
bGPDlayer *gpl_src,
bGPDlayer *gpl_dst,
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 0a1cf643f37..8f2a189e35e 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -46,6 +46,12 @@ typedef struct IMMDrawPixelsTexState {
/* To be used before calling immDrawPixelsTex
* Default shader is GPU_SHADER_2D_IMAGE_COLOR
* Returns a shader to be able to set uniforms */
+/**
+ * To be used before calling #immDrawPixelsTex
+ * Default shader is #GPU_SHADER_2D_IMAGE_COLOR
+ * You can still set uniforms with:
+ * `GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);`
+ */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
/**
@@ -101,6 +107,20 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
float xzoom,
float yzoom,
const float color[4]);
+/**
+ * Use the currently bound shader.
+ *
+ * Use #immDrawPixelsTexSetup to bind the shader you
+ * want before calling #immDrawPixelsTex.
+ *
+ * If using a special shader double check it uses the same
+ * attributes "pos" "texCoord" and uniform "image".
+ *
+ * If color is NULL then use white by default
+ *
+ * Be also aware that this function unbinds the shader when
+ * it's finished.
+ */
void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float x,
float y,
@@ -135,6 +155,9 @@ void ED_draw_imbuf(struct ImBuf *ibuf,
struct ColorManagedDisplaySettings *display_settings,
float zoom_x,
float zoom_y);
+/**
+ * Draw given image buffer on a screen using GLSL for display transform.
+ */
void ED_draw_imbuf_clipping(struct ImBuf *ibuf,
float x,
float y,
@@ -169,6 +192,9 @@ void ED_draw_imbuf_ctx_clipping(const struct bContext *C,
int ED_draw_imbuf_method(struct ImBuf *ibuf);
+/**
+ * Don't move to `GPU_immediate_util.h` because this uses user-prefs and isn't very low level.
+ */
void immDrawBorderCorners(unsigned int pos, const struct rcti *border, float zoomx, float zoomy);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index e9601220f2e..3294316f880 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -63,7 +63,9 @@ struct PropertyRNA;
/* ANIMATION CHANNEL FILTERING */
/* anim_filter.c */
-/* --------------- Context --------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Context
+ * \{ */
/* This struct defines a structure used for animation-specific
* 'context' information
@@ -126,7 +128,11 @@ typedef enum eAnimCont_Types {
ANIMCONT_TIMELINE = 10, /* "timeline" editor (bDopeSheet) */
} eAnimCont_Types;
-/* --------------- Channels -------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Channels
+ * \{ */
/* This struct defines a structure used for quick and uniform access for
* channels of animation data
@@ -281,7 +287,11 @@ typedef enum eAnim_Update_Flags {
#define ANIM_UPDATE_DEFAULT (ANIM_UPDATE_DEPS | ANIM_UPDATE_ORDER | ANIM_UPDATE_HANDLES)
#define ANIM_UPDATE_DEFAULT_NOHANDLES (ANIM_UPDATE_DEFAULT & ~ANIM_UPDATE_HANDLES)
-/* ----------------- Filtering -------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filtering
+ * \{ */
/* filtering flags - under what circumstances should a channel be returned */
typedef enum eAnimFilter_Flags {
@@ -334,7 +344,12 @@ typedef enum eAnimFilter_Flags {
ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31),
} eAnimFilter_Flags;
-/* ---------- Flag Checking Macros ------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flag Checking Macros
+ * \{ */
+
/* XXX check on all of these flags again. */
/* Dopesheet only */
@@ -421,7 +436,11 @@ typedef enum eAnimFilter_Flags {
/* AnimData - NLA mostly... */
#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED)
-/* -------------- Channel Defines -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Channel Defines
+ * \{ */
/* channel heights */
#define ACHANNEL_FIRST_TOP(ac) \
@@ -439,7 +458,11 @@ typedef enum eAnimFilter_Flags {
/* channel toggle-buttons */
#define ACHANNEL_BUTTON_WIDTH (0.8f * U.widget_unit)
-/* -------------- NLA Channel Defines -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA Channel Defines
+ * \{ */
/* NLA channel heights */
#define NLACHANNEL_FIRST_TOP(ac) \
@@ -459,10 +482,19 @@ typedef enum eAnimFilter_Flags {
/* channel toggle-buttons */
#define NLACHANNEL_BUTTON_WIDTH (0.8f * U.widget_unit)
-/* ---------------- API -------------------- */
+/** \} */
-/* Obtain list of filtered Animation channels to operate on.
- * Returns the number of channels in the list
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+/**
+ * This function filters the active data source to leave only animation channels suitable for
+ * usage by the caller. It will return the length of the list
+ *
+ * \param anim_data: Is a pointer to a #ListBase,
+ * to which the filtered animation channels will be placed for use.
+ * \param filter_mode: how should the data be filtered - bit-mapping accessed flags.
*/
size_t ANIM_animdata_filter(bAnimContext *ac,
ListBase *anim_data,
@@ -470,18 +502,27 @@ size_t ANIM_animdata_filter(bAnimContext *ac,
void *data,
eAnimCont_Types datatype);
-/* Obtain current anim-data context from Blender Context info.
- * Returns whether the operation was successful.
+/**
+ * Obtain current anim-data context from Blender Context info
+ * - AnimContext to write to is provided as pointer to var on stack so that we don't have
+ * allocation/freeing costs (which are not that avoidable with channels).
+ * - Clears data and sets the information from Blender Context which is useful
+ * \return whether the operation was successful.
*/
bool ANIM_animdata_get_context(const struct bContext *C, bAnimContext *ac);
-/* Obtain current anim-data context (from Animation Editor) given
- * that Blender Context info has already been set.
- * Returns whether the operation was successful.
+/**
+ * Obtain current anim-data context,
+ * given that context info from Blender context has already been set:
+ * - AnimContext to write to is provided as pointer to var on stack so that we don't have
+ * allocation/freeing costs (which are not that avoidable with channels).
+ * \return whether the operation was successful.
*/
bool ANIM_animdata_context_getdata(bAnimContext *ac);
-/* Acts on bAnimListElem eAnim_Update_Flags */
+/**
+ * Acts on bAnimListElem eAnim_Update_Flags.
+ */
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data);
void ANIM_animdata_freelist(ListBase *anim_data);
@@ -490,7 +531,11 @@ void ANIM_animdata_freelist(ListBase *anim_data);
/* ANIMATION CHANNELS LIST */
/* anim_channels_*.c */
-/* ------------------------ Drawing TypeInfo -------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing TypeInfo
+ * \{ */
/* role or level of animchannel in the hierarchy */
typedef enum eAnimChannel_Role {
@@ -569,18 +614,35 @@ typedef struct bAnimChannelType {
void *(*setting_ptr)(bAnimListElem *ale, eAnimChannel_Settings setting, short *type);
} bAnimChannelType;
-/* ------------------------ Drawing API -------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing API
+ * \{ */
-/* Get typeinfo for the given channel */
+/**
+ * Get type info from given channel type.
+ */
const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
-/* Print debugging info about a given channel */
+/**
+ * Print debug info string for the given channel.
+ */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level);
-/* Draw the given channel */
+/**
+ * Retrieves the Action associated with this animation channel.
+ */
+bAction *ANIM_channel_action_get(const bAnimListElem *ale);
+
+/**
+ * Draw the given channel.
+ */
void ANIM_channel_draw(
bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index);
-/* Draw the widgets for the given channel */
+/**
+ * Draw UI widgets the given channel.
+ */
void ANIM_channel_draw_widgets(const struct bContext *C,
bAnimContext *ac,
bAnimListElem *ale,
@@ -588,27 +650,30 @@ void ANIM_channel_draw_widgets(const struct bContext *C,
rctf *rect,
size_t channel_index);
-/* ------------------------ Editing API -------------------------- */
+/** \} */
-/* Check if some setting for a channel is enabled
- * Returns: 1 = On, 0 = Off, -1 = Invalid
- *
- * - setting: eAnimChannel_Settings
+/* -------------------------------------------------------------------- */
+/** \name Editing API
+ * \{ */
+
+/**
+ * Check if some setting for a channel is enabled
+ * Returns: 1 = On, 0 = Off, -1 = Invalid.
*/
short ANIM_channel_setting_get(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting);
-/* Change value of some setting for a channel
- * - setting: eAnimChannel_Settings
- * - mode: eAnimChannels_SetFlag
+/**
+ * Change value of some setting for a channel.
*/
void ANIM_channel_setting_set(bAnimContext *ac,
bAnimListElem *ale,
eAnimChannel_Settings setting,
eAnimChannels_SetFlag mode);
-/* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
+/**
+ * Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
* - anim_data: list of the all the anim channels that can be chosen
* -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
* then the channels under closed expanders get ignored...
@@ -623,13 +688,19 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac,
eAnimChannel_Settings setting,
eAnimChannels_SetFlag mode);
-/* Select or deselect animation channels */
+/**
+ * Set selection state of all animation channels in the context.
+ */
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel);
-/* Toggle selection of animation channels */
+/**
+ * Toggle selection state of all animation channels in the context.
+ */
void ANIM_anim_channels_select_toggle(bAnimContext *ac);
-/* Set the 'active' channel of type channel_type, in the given action */
+/**
+ * Set the given animation-channel as the active one for the active context.
+ */
void ANIM_set_active_channel(bAnimContext *ac,
void *data,
eAnimCont_Types datatype,
@@ -637,18 +708,31 @@ void ANIM_set_active_channel(bAnimContext *ac,
void *channel_data,
eAnim_ChannelType channel_type);
-/* Delete the F-Curve from the given AnimData block (if possible),
- * as appropriate according to animation context */
+/**
+ * Delete the F-Curve from the given AnimData block (if possible),
+ * as appropriate according to animation context.
+ */
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, struct AnimData *adt, struct FCurve *fcu);
-/* Unlink the action from animdata if it's empty. */
+/**
+ * Unlink the action from animdata if it's empty.
+ *
+ * If the action has no F-Curves, unlink it from AnimData if it did not
+ * come from a NLA Strip being tweaked.
+ */
bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt);
/* ************************************************ */
/* DRAWING API */
/* anim_draw.c */
-/* ---------- Current Frame Drawing ---------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Current Frame Drawing
+ *
+ * Main call to draw current-frame indicator in an Animation Editor.
+ * \{ */
/* flags for Current Frame Drawing */
typedef enum eAnimEditDraw_CurrentFrame {
@@ -660,23 +744,54 @@ typedef enum eAnimEditDraw_CurrentFrame {
DRAWCFRA_WIDE = (1 << 1),
} eAnimEditDraw_CurrentFrame;
-/* main call to draw current-frame indicator in an Animation Editor */
+/**
+ * General call for drawing current frame indicator in animation editor.
+ */
void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag);
-/* ------------- Preview Range Drawing -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Preview Range Drawing
+ *
+ * Main call to draw preview range curtains.
+ * \{ */
-/* main call to draw preview range curtains */
+/**
+ * Draw preview range 'curtains' for highlighting where the animation data is.
+ */
void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d, int end_frame_width);
-/* -------------- Frame Range Drawing --------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Frame Range Drawing
+ *
+ * Main call to draw normal frame range indicators.
+ * \{ */
-/* main call to draw normal frame range indicators */
+/**
+ * Draw frame range guides (for scene frame range) in background.
+ *
+ * TODO: Should we still show these when preview range is enabled?
+ */
void ANIM_draw_framerange(struct Scene *scene, struct View2D *v2d);
+/**
+ * Draw manually set intended playback frame range guides for the action in the background.
+ * Allows specifying a subset of the Y range of the view.
+ */
+void ANIM_draw_action_framerange(
+ struct AnimData *adt, struct bAction *action, struct View2D *v2d, float ymin, float ymax);
+
/* ************************************************* */
/* F-MODIFIER TOOLS */
-/* ------------- UI Panel Drawing -------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UI Panel Drawing
+ * \{ */
bool ANIM_nla_context_track_ptr(const struct bContext *C, struct PointerRNA *r_ptr);
bool ANIM_nla_context_strip_ptr(const struct bContext *C, struct PointerRNA *r_ptr);
@@ -690,6 +805,9 @@ typedef bool (*PanelTypePollFn)(const struct bContext *C, struct PanelType *pt);
/* Avoid including "UI_interface.h" here. */
typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+/**
+ * Checks if the panels match the active strip / curve, rebuilds them if they don't.
+ */
void ANIM_fmodifier_panels(const struct bContext *C,
struct ID *owner_id,
struct ListBase *fmodifiers,
@@ -702,49 +820,93 @@ void ANIM_modifier_panels_register_graph_only(struct ARegionType *region_type,
const char *modifier_panel_prefix,
PanelTypePollFn poll_function);
-/* ------------- Copy/Paste Buffer -------------- */
+/** \} */
-/* free the copy/paste buffer */
+/* -------------------------------------------------------------------- */
+/** \name Copy/Paste Buffer
+ * \{ */
+
+/**
+ * Free the copy/paste buffer.
+ */
void ANIM_fmodifiers_copybuf_free(void);
-/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
- * - active: only copy the active modifier
+/**
+ * Copy the given F-Modifiers to the buffer, returning whether anything was copied or not
+ * assuming that the buffer has been cleared already with #ANIM_fmodifiers_copybuf_free()
+ * \param active: Only copy the active modifier.
*/
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active);
-/* 'Paste' the F-Modifier(s) from the buffer to the specified list
- * - replace: free all the existing modifiers to leave only the pasted ones
+/**
+ * 'Paste' the F-Modifier(s) from the buffer to the specified list
+ * \param replace: Free all the existing modifiers to leave only the pasted ones.
*/
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, struct FCurve *curve);
/* ************************************************* */
/* ASSORTED TOOLS */
-/* ------------ Animation F-Curves <-> Icons/Names Mapping ------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation F-Curves <-> Icons/Names Mapping
+ * \{ */
+
/* anim_ipo_utils.c */
-/* Get icon + name for channel-list displays for F-Curve */
+/**
+ * Get icon + name for channel-list displays for F-Curve.
+ *
+ * Write into "name" buffer, the name of the property
+ * (retrieved using RNA from the curve's settings),
+ * and return the icon used for the struct that this property refers to
+ *
+ * \warning name buffer we're writing to cannot exceed 256 chars
+ * (check anim_channels_defines.c for details).
+ */
int getname_anim_fcurve(char *name, struct ID *id, struct FCurve *fcu);
-/* Automatically determine a color for the nth F-Curve */
+/**
+ * Automatically determine a color for the nth F-Curve.
+ */
void getcolor_fcurve_rainbow(int cur, int tot, float out[3]);
-/* ----------------- NLA Drawing ----------------------- */
-/* NOTE: Technically, this is not in the animation module (it's in space_nla)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA Drawing
+ *
+ * \note Technically, this is not in the animation module (it's in space_nla)
* but these are sometimes needed by various animation API's.
- */
+ * \{ */
-/* Get color to use for NLA Action channel's background */
+/**
+ * Get color to use for NLA Action channel's background.
+ * \note color returned includes fine-tuned alpha!
+ */
void nla_action_get_color(struct AnimData *adt, struct bAction *act, float color[4]);
-/* ----------------- NLA-Mapping ----------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NLA-Mapping
+ * \{ */
+
/* anim_draw.c */
-/* Obtain the AnimData block providing NLA-scaling for the given channel if applicable */
+/**
+ * Obtain the AnimData block providing NLA-mapping for the given channel (if applicable).
+ *
+ * TODO: do not supply return this if the animdata tells us that there is no mapping to perform.
+ */
struct AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale);
-/* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve */
+/**
+ * Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve
+ * \param restore: Whether to map points back to non-mapped time.
+ * \param only_keys: Whether to only adjust the location of the center point of beztriples.
+ */
void ANIM_nla_mapping_apply_fcurve(struct AnimData *adt,
struct FCurve *fcu,
bool restore,
@@ -752,11 +914,18 @@ void ANIM_nla_mapping_apply_fcurve(struct AnimData *adt,
/* ..... */
-/* Perform auto-blending/extend refreshes after some operations */
-/* NOTE: defined in space_nla/nla_edit.c, not in animation/ */
+/**
+ * Perform validation & auto-blending/extend refreshes after some operations
+ * \note defined in space_nla/nla_edit.c, not in animation/
+ */
void ED_nla_postop_refresh(bAnimContext *ac);
-/* ------------- Unit Conversion Mappings ------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unit Conversion Mappings
+ * \{ */
+
/* anim_draw.c */
/* flags for conversion mapping */
@@ -778,16 +947,24 @@ typedef enum eAnimUnitConv_Flags {
ANIM_UNITCONV_NORMALIZE_FREEZE = (1 << 6),
} eAnimUnitConv_Flags;
-/* Normalization flags from Space Graph passing to ANIM_unit_mapping_get_factor */
+/**
+ * Get flags used for normalization in ANIM_unit_mapping_get_factor.
+ */
short ANIM_get_normalization_flags(bAnimContext *ac);
-
-/* Get unit conversion factor for given ID + F-Curve */
+/**
+ * Get unit conversion factor for given ID + F-Curve.
+ */
float ANIM_unit_mapping_get_factor(
struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag, float *r_offset);
-/* ------------- Utility macros ----------------------- */
+/** \} */
-/* provide access to Keyframe Type info in BezTriple
+/* -------------------------------------------------------------------- */
+/** \name Utility macros
+ * \{ */
+
+/**
+ * Provide access to Keyframe Type info in #BezTriple.
* NOTE: this is so that we can change it from being stored in 'hide'
*/
#define BEZKEYTYPE(bezt) ((bezt)->hide)
@@ -830,18 +1007,37 @@ float ANIM_unit_mapping_get_factor(
} \
((void)0)
-/* --------- anim_deps.c, animation updates -------- */
+/** \} */
+/* anim_deps.c */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Updates
+ * \{ */
+
+/**
+ * Tags the given ID block for refreshes (if applicable) due to Animation Editor editing.
+ */
void ANIM_id_update(struct Main *bmain, struct ID *id);
+/**
+ * Tags the given anim list element for refreshes (if applicable) due to Animation Editor editing.
+ */
void ANIM_list_elem_update(struct Main *bmain, struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
+
+/**
+ * Main call to be exported to animation editors.
+ */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
void ANIM_center_frame(struct bContext *C, int smooth_viewtx);
-/* ************************************************* */
-/* OPERATORS */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operators
+ * \{ */
/* generic animation channels */
void ED_operatortypes_animchannels(void);
@@ -856,12 +1052,20 @@ void ED_operatormacros_graph(void);
/* space_action */
void ED_operatormacros_action(void);
-/* ************************************************ */
-/* Animation Editor Exports */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Editor Exports
+ * \{ */
+
/* XXX: Should we be doing these here, or at all? */
-/* Action Editor - Action Management */
-struct AnimData *ED_actedit_animdata_from_context(struct bContext *C, struct ID **r_adt_id_owner);
+/**
+ * Action Editor - Action Management.
+ * Helper function to find the active AnimData block from the Action Editor context.
+ */
+struct AnimData *ED_actedit_animdata_from_context(const struct bContext *C,
+ struct ID **r_adt_id_owner);
void ED_animedit_unlink_action(struct bContext *C,
struct ID *id,
struct AnimData *adt,
@@ -869,7 +1073,11 @@ void ED_animedit_unlink_action(struct bContext *C,
struct ReportList *reports,
bool force_delete);
-/* Drivers Editor - Utility to set up UI correctly */
+/**
+ * Set up UI configuration for Drivers Editor
+ * (drivers editor window) and RNA (mode switching).
+ * \note Currently called from window-manager.
+ */
void ED_drivers_editor_init(struct bContext *C, struct ScrArea *area);
/* ************************************************ */
@@ -897,8 +1105,14 @@ void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
eAnimvizCalcRange range,
bool restore);
+/**
+ * Get list of motion paths to be baked for the given object.
+ * - assumes the given list is ready to be used.
+ */
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 868235c36e5..0053bf5c865 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -70,45 +70,91 @@ struct wmOperator;
(CHECK_TYPE_INLINE(ebone, EditBone *), \
(((ebone)->flag & BONE_SELECTED) && !((ebone)->flag & BONE_EDITMODE_LOCKED)))
-/* used in armature_select.c and pose_select.c */
+/* Used in `armature_select.c` and `pose_select.c`. */
+
#define BONE_SELECT_PARENT 0
#define BONE_SELECT_CHILD 1
/* armature_add.c */
+
+/**
+ * Default bone add, returns it selected, but without tail set.
+ *
+ * \note should be used everywhere, now it allocates bones still locally in functions.
+ */
struct EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name);
struct EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm,
float length,
bool view_aligned);
/* armature_edit.c */
+
+/**
+ * Adjust bone roll to align Z axis with vector `align_axis` is in local space and is normalized.
+ */
float ED_armature_ebone_roll_to_vector(const struct EditBone *bone,
const float align_axis[3],
const bool axis_only);
+/**
+ * \param centermode: 0 == do center, 1 == center new, 2 == center cursor.
+ *
+ * \note Exported for use in `editors/object/`.
+ */
void ED_armature_origin_set(
struct Main *bmain, struct Object *ob, const float cursor[3], int centermode, int around);
+/**
+ * See #BKE_armature_transform for object-mode transform.
+ */
void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
/* armature_naming.c */
+
+/**
+ * Ensure the bone name is unique.
+ * If bone is already in list, pass it as argument to ignore it.
+ */
void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, struct EditBone *bone);
+
+/**
+ * Bone Rename (called by UI for renaming a bone).
+ * Seems messy, but that's what you get with not using pointers but channel names :).
+ * \warning make sure the original bone was not renamed yet!
+ */
void ED_armature_bone_rename(struct Main *bmain,
struct bArmature *arm,
const char *oldnamep,
const char *newnamep);
+/**
+ * Renames (by flipping) all selected bones at once.
+ *
+ * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time
+ * all the bones are safely renamed, without conflicting with each other.
+ *
+ * \param arm: Armature the bones belong to
+ * \param bones_names: List of bone conflict elements (#LinkData pointing to names).
+ * \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
+ */
void ED_armature_bones_flip_names(struct Main *bmain,
struct bArmature *arm,
struct ListBase *bones_names,
const bool do_strip_numbers);
/* armature_ops.c */
+
void ED_operatortypes_armature(void);
void ED_operatormacros_armature(void);
void ED_keymap_armature(struct wmKeyConfig *keyconf);
/* armature_relations.c */
+
+/**
+ * Join armature exec is exported for use in object->join objects operator.
+ */
int ED_armature_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* armature_select.c */
+
struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
@@ -121,6 +167,9 @@ struct Base *ED_armature_base_and_pchan_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
struct bPoseChannel **r_pchan);
+/**
+ * For callers that don't need the pose channel.
+ */
struct Base *ED_armature_base_and_bone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
@@ -137,11 +186,27 @@ bool ED_armature_edit_select_pick_bone(struct bContext *C,
bool extend,
bool deselect,
bool toggle);
+/**
+ * Bone selection picking for armature edit-mode in the view3d.
+ */
bool ED_armature_edit_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/**
+ * Perform a selection operation on elements which have been 'touched',
+ * use for lasso & border select but can be used elsewhere too.
+ *
+ * Tagging is done via #EditBone.temp.i using: #BONESEL_ROOT, #BONESEL_TIP, #BONESEL_BONE
+ * And optionally ignoring end-points using the #BONESEL_ROOT, #BONESEL_TIP right shifted 16 bits.
+ * (used when the values are clipped outside the view).
+ *
+ * \param sel_op: #eSelectOp type.
+ *
+ * \note Visibility checks must be done by the caller.
+ */
bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op);
/* armature_skinning.c */
+
#define ARM_GROUPS_NAME 1
#define ARM_GROUPS_ENVELOPE 2
#define ARM_GROUPS_AUTO 3
@@ -154,40 +219,74 @@ void ED_object_vgroup_calc_from_armature(struct ReportList *reports,
const bool mirror);
/* editarmature_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_armature_undosys_type(struct UndoType *ut);
/* armature_utils.c */
+
+/** Sync selection to parent for connected children. */
void ED_armature_edit_sync_selection(struct ListBase *edbo);
void ED_armature_edit_validate_active(struct bArmature *arm);
+/**
+ * Update the layers_used variable after bones are moved between layer
+ * \note Used to be done in drawing code in 2.7, but that won't work with
+ * Copy-on-Write, as drawing uses evaluated copies.
+ */
void ED_armature_edit_refresh_layer_used(struct bArmature *arm);
+/**
+ * \param clear_connected: When false caller is responsible for keeping the flag in a valid state.
+ */
void ED_armature_ebone_remove_ex(struct bArmature *arm,
struct EditBone *exBone,
bool clear_connected);
void ED_armature_ebone_remove(struct bArmature *arm, struct EditBone *exBone);
bool ED_armature_ebone_is_child_recursive(struct EditBone *ebone_parent,
struct EditBone *ebone_child);
+/**
+ * Finds the first parent shared by \a ebone_child
+ *
+ * \param ebone_child: Children bones to search
+ * \param ebone_child_tot: Size of the ebone_child array
+ * \return The shared parent or NULL.
+ */
struct EditBone *ED_armature_ebone_find_shared_parent(struct EditBone *ebone_child[],
const unsigned int ebone_child_tot);
void ED_armature_ebone_to_mat3(struct EditBone *ebone, float r_mat[3][3]);
void ED_armature_ebone_to_mat4(struct EditBone *ebone, float r_mat[4][4]);
void ED_armature_ebone_from_mat3(struct EditBone *ebone, const float mat[3][3]);
void ED_armature_ebone_from_mat4(struct EditBone *ebone, const float mat[4][4]);
+/**
+ * Return a pointer to the bone of the given name
+ */
struct EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name);
+/**
+ * \see #BKE_pose_channel_get_mirrored (pose-mode, matching function)
+ */
struct EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, struct EditBone *ebo);
void ED_armature_ebone_transform_mirror_update(struct bArmature *arm,
struct EditBone *ebo,
bool check_select);
+/**
+ * If edit-bone (partial) selected, copy data.
+ * context; edit-mode armature, with mirror editing enabled.
+ */
void ED_armature_edit_transform_mirror_update(struct Object *obedit);
+/** Put edit-mode back in Object. */
void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm);
+/** Put armature in edit-mode. */
void ED_armature_to_edit(struct bArmature *arm);
void ED_armature_edit_free(struct bArmature *arm);
void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
+
+/**
+ * Free's bones and their properties.
+ */
void ED_armature_ebone_listbase_free(struct ListBase *lb, const bool do_id_user);
void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst,
struct ListBase *lb_src,
const bool do_id_user);
-/* low level selection functions which handle */
int ED_armature_ebone_selectflag_get(const struct EditBone *ebone);
void ED_armature_ebone_selectflag_set(struct EditBone *ebone, int flag);
void ED_armature_ebone_select_set(struct EditBone *ebone, bool select);
@@ -198,21 +297,29 @@ void ED_armature_ebone_selectflag_disable(struct EditBone *ebone, int flag);
struct Object *ED_pose_object_from_context(struct bContext *C);
bool ED_object_posemode_exit_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_exit(struct bContext *C, struct Object *ob);
+/** This function is used to process the necessary updates for. */
bool ED_object_posemode_enter_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_enter(struct bContext *C, struct Object *ob);
-/* Corresponds to eAnimvizCalcRange. */
+/** Corresponds to #eAnimvizCalcRange. */
typedef enum ePosePathCalcRange {
POSE_PATH_CALC_RANGE_CURRENT_FRAME,
POSE_PATH_CALC_RANGE_CHANGED,
POSE_PATH_CALC_RANGE_FULL,
} ePosePathCalcRange;
+/**
+ * For the object with pose/action: update paths for those that have got them
+ * This should selectively update paths that exist...
+ *
+ * To be called from various tools that do incremental updates.
+ */
void ED_pose_recalculate_paths(struct bContext *C,
struct Scene *scene,
struct Object *ob,
ePosePathCalcRange range);
/* pose_select.c */
+
void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Object *ob,
@@ -220,6 +327,10 @@ void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
bool extend,
bool deselect,
bool toggle);
+/**
+ * Called for mode-less pose selection.
+ * assumes the active object is still on old situation.
+ */
bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Base *base,
@@ -229,6 +340,14 @@ bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
bool deselect,
bool toggle,
bool do_nearest);
+/**
+ * While in weight-paint mode, a single pose may be active as well.
+ * While not common, it's possible we have multiple armatures deforming a mesh.
+ *
+ * This function de-selects all other objects, and selects the new base.
+ * It can't be set to the active object because we need
+ * to keep this set to the weight paint object.
+ */
void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer,
struct Base *base_select);
bool ED_pose_deselect_all_multi_ex(struct Base **bases,
@@ -236,8 +355,16 @@ bool ED_pose_deselect_all_multi_ex(struct Base **bases,
int select_mode,
const bool ignore_visibility);
bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility);
+/**
+ * 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
+ * When true, 'ignore_visibility' makes this func also affect invisible bones
+ * (hidden or on hidden layers).
+ */
bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
+/**
+ * Utility method for changing the selection status of a bone.
+ */
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
/* meshlaplacian.c */
@@ -249,7 +376,9 @@ void ED_mesh_deform_bind_callback(struct MeshDeformModifierData *mmd,
/* Pose backups, pose_backup.c */
struct PoseBackup;
-/* Create a backup of those bones that are animated in the given action. */
+/**
+ * Create a backup of those bones that are animated in the given action.
+ */
struct PoseBackup *ED_pose_backup_create_selected_bones(
const struct Object *ob, const struct bAction *action) ATTR_WARN_UNUSED_RESULT;
struct PoseBackup *ED_pose_backup_create_all_bones(
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index af0643f0d64..79404aada41 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -30,6 +30,11 @@ struct ScrArea;
struct SpaceProperties;
struct bContext;
+/**
+ * Fills an array with the tab context values for the properties editor. -1 signals a separator.
+ *
+ * \return The total number of items in the array returned.
+ */
int ED_buttons_tabs_list(struct SpaceProperties *sbuts, short *context_tabs_array);
bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, const int index);
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 21d8a28e2c9..6167ae3aee6 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -56,6 +56,9 @@ void ED_space_clip_get_zoom(struct SpaceClip *sc,
void ED_space_clip_get_aspect(struct SpaceClip *sc, float *aspx, float *aspy);
void ED_space_clip_get_aspect_dimension_aware(struct SpaceClip *sc, float *aspx, float *aspy);
+/**
+ * Return current frame number in clip space.
+ */
int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc);
struct ImBuf *ED_space_clip_get_buffer(struct SpaceClip *sc);
@@ -65,9 +68,12 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc,
float *angle);
bool ED_space_clip_get_position(struct SpaceClip *sc,
- struct ARegion *ar,
+ struct ARegion *region,
int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_image_color_sample().
+ */
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
int mval[2],
@@ -82,10 +88,17 @@ bool ED_clip_can_select(struct bContext *C);
void ED_clip_point_undistorted_pos(struct SpaceClip *sc, const float co[2], float r_co[2]);
void ED_clip_point_stable_pos(
struct SpaceClip *sc, struct ARegion *region, float x, float y, float *xr, float *yr);
+/**
+ * \brief the reverse of #ED_clip_point_stable_pos(), gets the marker region coords.
+ * better name here? view_to_track / track_to_view or so?
+ */
void ED_clip_point_stable_pos__reverse(struct SpaceClip *sc,
struct ARegion *region,
const float co[2],
float r_co[2]);
+/**
+ * Takes `event->mval`.
+ */
void ED_clip_mouse_pos(struct SpaceClip *sc,
struct ARegion *region,
const int mval[2],
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 44c5897d3a3..805d42b6fbc 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -43,14 +43,22 @@ struct wmKeyConfig;
struct wmOperator;
/* curve_ops.c */
+
void ED_operatortypes_curve(void);
void ED_operatormacros_curve(void);
void ED_keymap_curve(struct wmKeyConfig *keyconf);
/* editcurve.c */
+
struct ListBase *object_editcurve_get(struct Object *ob);
+/**
+ * Load editNurb in object.
+ */
void ED_curve_editnurb_load(struct Main *bmain, struct Object *obedit);
+/**
+ * Make copy in `cu->editnurb`.
+ */
void ED_curve_editnurb_make(struct Object *obedit);
void ED_curve_editnurb_free(struct Object *obedit);
@@ -65,9 +73,14 @@ int ED_curve_nurb_select_count(const struct View3D *v3d, const struct Nurb *nu);
bool ED_curve_nurb_select_all(const struct Nurb *nu);
bool ED_curve_nurb_deselect_all(const struct Nurb *nu);
+/**
+ * This is used externally, by #OBJECT_OT_join.
+ * TODO: shape keys - as with meshes.
+ */
int ED_curve_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* editcurve_select.c */
+
bool ED_curve_select_check(const struct View3D *v3d, const struct EditNurb *editnurb);
bool ED_curve_deselect_all(struct EditNurb *editnurb);
bool ED_curve_deselect_all_multi_ex(struct Base **bases, int bases_len);
@@ -77,9 +90,12 @@ bool ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
int ED_curve_select_count(const struct View3D *v3d, const struct EditNurb *editnurb);
/* editcurve_undo.c */
+
+/** Export for ED_undo_sys */
void ED_curve_undosys_type(struct UndoType *ut);
/* editfont.c */
+
void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
void ED_curve_editfont_free(struct Object *obedit);
@@ -92,14 +108,22 @@ void ED_curve_beztcpy(struct EditNurb *editnurb,
int count);
void ED_curve_bpcpy(struct EditNurb *editnurb, struct BPoint *dst, struct BPoint *src, int count);
+/**
+ * Return 0 if animation data wasn't changed, 1 otherwise.
+ */
int ED_curve_updateAnimPaths(struct Main *bmain, struct Curve *cu);
bool ED_curve_active_center(struct Curve *cu, float center[3]);
+/**
+ * TextBox selection
+ */
bool ED_curve_editfont_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
/* editfont_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_font_undosys_type(struct UndoType *ut);
#if 0
diff --git a/source/blender/editors/include/ED_file_indexer.h b/source/blender/editors/include/ED_file_indexer.h
new file mode 100644
index 00000000000..0afa8819def
--- /dev/null
+++ b/source/blender/editors/include/ED_file_indexer.h
@@ -0,0 +1,153 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edfile
+ */
+
+#pragma once
+
+#include "BLO_readfile.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * File indexing for the file/asset browser.
+ *
+ * This file contains an API to create indexing functionality when listing blend files in
+ * the file browser.
+ *
+ * To implement a custom indexer a `FileIndexerType` struct should be made and passed to the
+ * `filelist_setindexer` function.
+ */
+
+struct AssetLibraryReference;
+struct LinkNode;
+
+/**
+ * Result code of the `read_index` callback.
+ */
+typedef enum eFileIndexerResult {
+ /**
+ * File listing entries are loaded from the index. Reading entries from the blend file itself
+ * should be skipped.
+ */
+ FILE_INDEXER_ENTRIES_LOADED,
+
+ /**
+ * Index isn't available or not up to date. Entries should be read from the blend file and
+ * `update_index` must be called to update the index.
+ */
+ FILE_INDEXER_NEEDS_UPDATE,
+} eFileIndexerResult;
+
+/**
+ * FileIndexerEntry contains all data that is required to create a file listing entry.
+ */
+typedef struct FileIndexerEntry {
+ struct BLODataBlockInfo datablock_info;
+ short idcode;
+} FileIndexerEntry;
+
+/**
+ * Contains all entries of a blend file.
+ */
+typedef struct FileIndexerEntries {
+ struct LinkNode /* FileIndexerEntry */ *entries;
+} FileIndexerEntries;
+
+typedef void *(*FileIndexerInitUserDataFunc)(const char *root_directory,
+ size_t root_directory_maxlen);
+typedef void (*FileIndexerFreeUserDataFunc)(void *);
+typedef void (*FileIndexerFinishedFunc)(void *);
+typedef eFileIndexerResult (*FileIndexerReadIndexFunc)(const char *file_name,
+ FileIndexerEntries *entries,
+ int *r_read_entries_len,
+ void *user_data);
+typedef void (*FileIndexerUpdateIndexFunc)(const char *file_name,
+ FileIndexerEntries *entries,
+ void *user_data);
+
+typedef struct FileIndexerType {
+ /**
+ * Is called at the beginning of the file listing process. An indexer can
+ * setup needed data. The result of this function will be passed around as `user_data` parameter.
+ *
+ * This is an optional callback.
+ */
+ FileIndexerInitUserDataFunc init_user_data;
+
+ /**
+ * Is called at the end of the file listing process. An indexer can free the data that it created
+ * during the file listing process.
+ *
+ * This is an optional callback */
+ FileIndexerFreeUserDataFunc free_user_data;
+
+ /**
+ * Is called at the end of the file listing process (before the `free_user_data`) where indexes
+ * can perform clean-ups.
+ *
+ * This is an optional callback. Called when listing files completed.
+ */
+ FileIndexerFinishedFunc filelist_finished;
+
+ /**
+ * Is called for each blend file being listed to read data from the index.
+ *
+ * Read entries should be added to given `entries` parameter (type: `FileIndexerEntries`).
+ * `*r_read_entries_len` must be set to the number of read entries.
+ * and the function must return `eFileIndexerResult::FILE_INDEXER_ENTRIES_LOADED`.
+ * In this case the blend file will not be opened and the FileIndexerEntry added to `entries`
+ * will be used as the content of the file.
+ *
+ * When the index isn't available or could not be used no entries must be added to the
+ * entries field, `r_read_entries_len` must be set to `0` and the function must return
+ * `eFileIndexerResult::FILE_INDEXER_NEEDS_UPDATE`. In this case the blend file will read from
+ * the blend file and the `update_index` function will be called.
+ */
+ FileIndexerReadIndexFunc read_index;
+
+ /**
+ * Update an index of a blend file.
+ *
+ * Is called after reading entries from the file when the result of `read_index` was
+ * `eFileIndexerResult::FILE_INDEXER_NEED_UPDATE`. The callback should update the index so the
+ * next time that read_index is called it will read the entries from the index.
+ */
+ FileIndexerUpdateIndexFunc update_index;
+} FileIndexerType;
+
+/* file_indexer.cc */
+
+/** Removes all entries inside the given `indexer_entries`. */
+void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries);
+
+/**
+ * Adds all entries from the given `datablock_infos` to the `indexer_entries`.
+ * The datablock_infos must only contain data for a single IDType. The specific IDType must be
+ * passed in the `idcode` parameter.
+ */
+void ED_file_indexer_entries_extend_from_datablock_infos(
+ FileIndexerEntries *indexer_entries,
+ const LinkNode * /* BLODataBlockInfo */ datablock_infos,
+ const int idcode);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 68b6e44371c..460de58bdb2 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -105,12 +105,26 @@ typedef struct FileSelection {
struct View2D;
struct rcti;
+/**
+ * If needed, create and return the file select parameters for the active browse mode.
+ */
struct FileSelectParams *ED_fileselect_ensure_active_params(struct SpaceFile *sfile);
+/**
+ * Get the file select parameters for the active browse mode.
+ */
struct FileSelectParams *ED_fileselect_get_active_params(const struct SpaceFile *sfile);
struct FileSelectParams *ED_fileselect_get_file_params(const struct SpaceFile *sfile);
struct FileAssetSelectParams *ED_fileselect_get_asset_params(const struct SpaceFile *sfile);
+bool ED_fileselect_is_local_asset_library(const struct SpaceFile *sfile);
void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
+/**
+ * Update the user-preference data for the file space. In fact, this also contains some
+ * non-FileSelectParams data, but we can safely ignore this.
+ *
+ * \param temp_win_size: If the browser was opened in a temporary window,
+ * pass its size here so we can store that in the preferences. Otherwise NULL.
+ */
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile,
const int temp_win_size[2],
const bool is_maximized);
@@ -123,6 +137,10 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, struct ARegion *region);
int ED_fileselect_layout_offset(FileLayout *layout, int x, int y);
FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const struct rcti *rect);
+/**
+ * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
+ * top column-header row.
+ */
void ED_fileselect_layout_maskrect(const FileLayout *layout,
const struct View2D *v2d,
struct rcti *r_rect);
@@ -149,8 +167,10 @@ struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
void ED_fileselect_activate_asset_catalog(const struct SpaceFile *sfile, bUUID catalog_id);
-/* Activate and select the file that corresponds to the given ID.
- * Pass deferred=true to wait for the next refresh before activating. */
+/**
+ * Activate and select the file that corresponds to the given ID.
+ * Pass deferred=true to wait for the next refresh before activating.
+ */
void ED_fileselect_activate_by_id(struct SpaceFile *sfile,
struct ID *asset_id,
const bool deferred);
@@ -165,12 +185,18 @@ void ED_fileselect_window_params_get(const struct wmWindow *win,
struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win,
const struct wmOperator *file_operator);
+/* TODO: Maybe we should move this to BLI?
+ * On the other hand, it's using defines from space-file area, so not sure... */
int ED_path_extension_type(const char *path);
int ED_file_extension_icon(const char *path);
int ED_file_icon(const struct FileDirEntry *file);
void ED_file_read_bookmarks(void);
+/**
+ * Support updating the directory even when this isn't the active space
+ * needed so RNA properties update function isn't context sensitive, see T70255.
+ */
void ED_file_change_dir_ex(struct bContext *C, struct ScrArea *area);
void ED_file_change_dir(struct bContext *C);
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 4d922162ee9..55beff40177 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -92,7 +92,17 @@ enum {
ED_GIZMO_ARROW_DRAW_FLAG_STEM = (1 << 0),
};
+/**
+ * Define a custom property UI range.
+ *
+ * \note Needs to be called before #WM_gizmo_target_property_def_rna!
+ */
void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, const float min, const float max);
+/**
+ * Define a custom factor for arrow min/max distance.
+ *
+ * \note Needs to be called before #WM_gizmo_target_property_def_rna!
+ */
void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, const float range_fac);
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 1cf15ce3a48..99164bbe439 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -116,42 +116,97 @@ typedef struct tGPspoint {
/* ----------- Grease Pencil Tools/Context ------------- */
/* Context-dependent */
+
+/**
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it.
+ */
struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *r_ptr);
+/**
+ * Get the active Grease Pencil data-block
+ */
struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
+/**
+ * Get the evaluated copy of the active Grease Pencil data-block (where applicable)
+ * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP data-block
+ * (i.e. a copy of the active GP data-block for the active object, where modifiers have been
+ * applied). This is needed to correctly work with "Copy-on-Write".
+ * - For all other editors (i.e. "GP Annotations"), this just gives the active data-block
+ * like for #ED_gpencil_data_get_active()
+ */
struct bGPdata *ED_gpencil_data_get_active_evaluated(const struct bContext *C);
-/* Context independent (i.e. each required part is passed in instead) */
+/**
+ * Context independent (i.e. each required part is passed in instead).
+ *
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ScrArea *area,
struct Object *ob,
struct PointerRNA *r_ptr);
+/* Get the active Grease Pencil data-block, when context is not available */
struct bGPdata *ED_gpencil_data_get_active_direct(struct ScrArea *area, struct Object *ob);
+/**
+ * Get the active Grease Pencil data-block
+ * \note This is the original (#G.main) copy of the data-block, stored in files.
+ * Do not use for reading evaluated copies of GP Objects data.
+ */
struct bGPdata *ED_annotation_data_get_active(const struct bContext *C);
+/**
+ * Get pointer to active Grease Pencil data-block,
+ * and an RNA-pointer to trace back to whatever owns it.
+ */
struct bGPdata **ED_annotation_data_get_pointers(const struct bContext *C,
struct PointerRNA *r_ptr);
+/**
+ * Get pointer to active Grease Pencil data-block for annotations,
+ * and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
struct bGPdata **ED_annotation_data_get_pointers_direct(struct ID *screen_id,
struct ScrArea *area,
struct Scene *scene,
struct PointerRNA *r_ptr);
+/**
+ * Get the active Grease Pencil data-block, when context is not available.
+ */
struct bGPdata *ED_annotation_data_get_active_direct(struct ID *screen_id,
struct ScrArea *area,
struct Scene *scene);
+/**
+ * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
+ * is for annotation usage.
+ */
bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr);
/* 3D View */
+
+/**
+ * Check whether there's an active GP keyframe on the current frame.
+ */
bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfra);
/* ----------- Stroke Editing Utilities ---------------- */
bool ED_gpencil_frame_has_selected_stroke(const struct bGPDframe *gpf);
bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, const bool is_multiedit);
+/**
+ * Check whether given stroke can be edited given the supplied context.
+ * TODO: do we need additional flags for screen-space vs data-space?.
+ */
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *area, const struct bGPDstroke *gps);
+/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
+/* Check whether given stroke can be edited for the current color */
bool ED_gpencil_stroke_material_editable(struct Object *ob,
const struct bGPDlayer *gpl,
const struct bGPDstroke *gps);
+/* Check whether given stroke is visible for the current material. */
bool ED_gpencil_stroke_material_visible(struct Object *ob, const struct bGPDstroke *gps);
/* ----------- Grease Pencil Operators ----------------- */
@@ -164,13 +219,32 @@ void ED_operatormacros_gpencil(void);
/* ------------- Copy-Paste Buffers -------------------- */
/* Strokes copybuf */
+
+/**
+ * Free copy/paste buffer data.
+ */
void ED_gpencil_strokes_copybuf_free(void);
/* ------------ Grease-Pencil Drawing API ------------------ */
/* drawgpencil.c */
+/**
+ * Draw grease-pencil sketches to specified 2d-view that uses ibuf corrections.
+ */
void ED_annotation_draw_2dimage(const struct bContext *C);
+/**
+ * Draw grease-pencil sketches to specified 2d-view
+ * assuming that matrices are already set correctly.
+ *
+ * \note This gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
+ * second time with onlyv2d=false for screen-aligned strokes.
+ */
void ED_annotation_draw_view2d(const struct bContext *C, bool onlyv2d);
+/**
+ * Draw annotations sketches to specified 3d-view assuming that matrices are already set correctly.
+ * NOTE: this gets called twice - first time with only3d=true to draw 3d-strokes,
+ * second time with only3d=false for screen-aligned strokes.
+ */
void ED_annotation_draw_view3d(struct Scene *scene,
struct Depsgraph *depsgraph,
struct View3D *v3d,
@@ -184,43 +258,103 @@ void ED_annotation_draw_ex(struct Scene *scene,
const char spacetype);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
+/**
+ * Loops over the gp-frames for a gp-layer, and applies the given callback.
+ */
bool ED_gpencil_layer_frames_looper(struct bGPDlayer *gpl,
struct Scene *scene,
bool (*gpf_cb)(struct bGPDframe *, struct Scene *));
+/**
+ * Make a listing all the gp-frames in a layer as cfraelems.
+ */
void ED_gpencil_layer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool onlysel);
+/**
+ * Check if one of the frames in this layer is selected.
+ */
bool ED_gpencil_layer_frame_select_check(const struct bGPDlayer *gpl);
+/**
+ * Set all/none/invert select.
+ */
void ED_gpencil_layer_frame_select_set(struct bGPDlayer *gpl, short mode);
+/**
+ * Select the frames in this layer that occur within the bounds specified.
+ */
void ED_gpencil_layer_frames_select_box(struct bGPDlayer *gpl,
float min,
float max,
short select_mode);
+/**
+ * Select the frames in this layer that occur within the lasso/circle region specified.
+ */
void ED_gpencil_layer_frames_select_region(struct KeyframeEditData *ked,
struct bGPDlayer *gpl,
short tool,
short select_mode);
+/**
+ * Set all/none/invert select (like above, but with SELECT_* modes).
+ */
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
+/**
+ * Select the frame in this layer that occurs on this frame (there should only be one at most).
+ */
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
+/**
+ * Delete selected frames.
+ */
bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl);
+/**
+ * Duplicate selected frames from given gp-layer.
+ */
void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl);
+/**
+ * Merge two layers.
+ */
void ED_gpencil_layer_merge(struct bGPdata *gpd,
struct bGPDlayer *gpl_src,
struct bGPDlayer *gpl_dst,
const bool reverse);
+/**
+ * Set keyframe type for selected frames from given gp-layer
+ *
+ * \param type: The type of keyframe (#eBezTriple_KeyframeType) to set selected frames to.
+ */
void ED_gpencil_layer_frames_keytype_set(struct bGPDlayer *gpl, short type);
-
+/**
+ * Snap selected frames to ....
+ */
void ED_gpencil_layer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
+
+/**
+ * Mirror selected gp-frames on...
+ * TODO: mirror over a specific time.
+ */
void ED_gpencil_layer_mirror_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
+/**
+ * This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ED_gpencil_anim_copybuf_free(void);
+/**
+ * This function adds data to the copy/paste buffer, freeing existing data first
+ * Only the selected GP-layers get their selected keyframes copied.
+ *
+ * Returns whether the copy operation was successful or not.
+ */
bool ED_gpencil_anim_copybuf_copy(struct bAnimContext *ac);
+/**
+ * Pastes keyframes from buffer, and reports success.
+ */
bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mode);
/* ------------ Grease-Pencil Undo System ------------------ */
int ED_gpencil_session_active(void);
+/**
+ * \param step: eUndoStepDir.
+ */
int ED_undo_gpencil_step(struct bContext *C, const int step); /* eUndoStepDir. */
/* ------------ Grease-Pencil Armature ------------------ */
@@ -234,7 +368,10 @@ bool ED_gpencil_add_armature_weights(const struct bContext *C,
struct Object *ob_arm,
int mode);
-/* Add Lattice modifier using Parent operator */
+/**
+ * Add Lattice modifier using Parent operator.
+ * Parent GPencil object to Lattice.
+ */
bool ED_gpencil_add_lattice_modifier(const struct bContext *C,
struct ReportList *reports,
struct Object *ob,
@@ -246,37 +383,74 @@ bool ED_gpencil_add_lattice_modifier(const struct bContext *C,
/* ------------ Transformation Utilities ------------ */
-/* reset parent matrix for all layers */
+/**
+ * Reset parent matrix for all layers.
+ */
void ED_gpencil_reset_layers_parent(struct Depsgraph *depsgraph,
struct Object *obact,
struct bGPdata *gpd);
-/* cursor utilities */
+/* Cursor utilities. */
+
+/**
+ * Draw eraser cursor.
+ */
void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
/* ----------- Add Primitive Utilities -------------- */
-/* Number of values defining each point in the built-in data buffers for primitives. */
+/** Number of values defining each point in the built-in data buffers for primitives. */
#define GP_PRIM_DATABUF_SIZE 5
+/**
+ * Populate stroke with point data from data buffers.
+ * \param gps: Grease pencil stroke
+ * \param array: Flat array of point data values. Each entry has #GP_PRIM_DATABUF_SIZE values.
+ * \param totpoints: Total of points
+ * \param mat: 4x4 transform matrix to transform points into the right coordinate space.
+ */
void ED_gpencil_stroke_init_data(struct bGPDstroke *gps,
const float *array,
const int totpoints,
const float mat[4][4]);
+/**
+ * Add a Simple empty object with one layer and one color.
+ */
void ED_gpencil_create_blank(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a 2D Suzanne (original model created by Matias Mendiola).
+ */
void ED_gpencil_create_monkey(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a Simple stroke with colors
+ * (original design created by Daniel M. Lara and Matias Mendiola).
+ */
void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4][4]);
+/**
+ * Add a Simple LineArt setup.
+ */
void ED_gpencil_create_lineart(struct bContext *C, struct Object *ob);
/* ------------ Object Utilities ------------ */
+/**
+ * Helper function to create new #OB_GPENCIL Object.
+ */
struct Object *ED_gpencil_add_object(struct bContext *C,
const float loc[3],
unsigned short local_view_bits);
+/**
+ * Helper function to create default colors and drawing brushes.
+ */
void ED_gpencil_add_defaults(struct bContext *C, struct Object *ob);
-/* set object modes */
+/**
+ * Set object modes.
+ */
void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode);
bool ED_object_gpencil_exit(struct Main *bmain, struct Object *ob);
+/**
+ * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
+ */
void ED_gpencil_project_stroke_to_plane(const struct Scene *scene,
const struct Object *ob,
const struct RegionView3D *rv3d,
@@ -284,6 +458,10 @@ void ED_gpencil_project_stroke_to_plane(const struct Scene *scene,
struct bGPDstroke *gps,
const float origin[3],
const int axis);
+/**
+ * Reproject given point to a plane locked to axis to avoid stroke offset
+ * \param pt: Point to affect (used for input & output).
+ */
void ED_gpencil_project_point_to_plane(const struct Scene *scene,
const struct Object *ob,
struct bGPDlayer *gpl,
@@ -291,14 +469,21 @@ void ED_gpencil_project_point_to_plane(const struct Scene *scene,
const float origin[3],
const int axis,
struct bGPDspoint *pt);
+/**
+ * Get drawing reference point for conversion or projection of the stroke
+ * \param r_vec: Reference point found
+ */
void ED_gpencil_drawing_reference_get(const struct Scene *scene,
const struct Object *ob,
char align_flag,
- float vec[3]);
+ float r_vec[3]);
void ED_gpencil_project_stroke_to_view(struct bContext *C,
struct bGPDlayer *gpl,
struct bGPDstroke *gps);
+/**
+ * Reproject selected strokes.
+ */
void ED_gpencil_stroke_reproject(struct Depsgraph *depsgraph,
const struct GP_SpaceConversion *gsc,
struct SnapObjectContext *sctx,
@@ -308,27 +493,54 @@ void ED_gpencil_stroke_reproject(struct Depsgraph *depsgraph,
const eGP_ReprojectModes mode,
const bool keep_original);
-/* set sculpt cursor */
+/**
+ * Turn brush cursor in on/off.
+ */
void ED_gpencil_toggle_brush_cursor(struct bContext *C, bool enable, void *customdata);
/* vertex groups */
+
+/**
+ * Assign points to vertex group.
+ */
void ED_gpencil_vgroup_assign(struct bContext *C, struct Object *ob, float weight);
+/**
+ * Remove points from vertex group.
+ */
void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob);
+/**
+ * Select points of vertex group.
+ */
void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob);
+/**
+ * Unselect points of vertex group.
+ */
void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob);
/* join objects */
+
+/**
+ * Join objects called from OBJECT_OT_join.
+ */
int ED_gpencil_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* texture coordinate utilities */
+
+/**
+ * Convert 2d #tGPspoint to 3d #bGPDspoint.
+ */
void ED_gpencil_tpoint_to_point(struct ARegion *region,
float origin[3],
const struct tGPspoint *tpt,
struct bGPDspoint *pt);
+/**
+ * Recalculate UV for any stroke using the material.
+ */
void ED_gpencil_update_color_uv(struct Main *bmain, struct Material *mat);
-/* extend selection to stroke intersections
- * returns:
+/**
+ * Extend selection to stroke intersections:
+ * \returns:
* 0 - No hit
* 1 - Hit in point A
* 2 - Hit in point B
@@ -347,17 +559,23 @@ int ED_gpencil_select_stroke_segment(struct bGPdata *gpd,
void ED_gpencil_select_toggle_all(struct bContext *C, int action);
void ED_gpencil_select_curve_toggle_all(struct bContext *C, int action);
-/* Ensure stroke sbuffer size is enough */
+/**
+ * Ensure the #tGPspoint buffer (while drawing stroke)
+ * size is enough to save all points of the stroke.
+ */
struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
const bool clear);
void ED_gpencil_sbuffer_update_eval(struct bGPdata *gpd, struct Object *ob_eval);
-/* Tag all scene grease pencil object to update. */
+/**
+ * Tag all scene grease pencil object to update.
+ */
void ED_gpencil_tag_scene_gpencil(struct Scene *scene);
/* Vertex color set. */
+
void ED_gpencil_fill_vertex_color_set(struct ToolSettings *ts,
struct Brush *brush,
struct bGPDstroke *gps);
@@ -376,15 +594,30 @@ void ED_gpencil_init_random_settings(struct Brush *brush,
const int mval[2],
struct GpRandomSettings *random_settings);
+/**
+ * Check if the stroke collides with brush.
+ */
bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
const float mouse[2],
const int radius,
const float diff_mat[4][4]);
+/**
+ * Check if a point is inside of the stroke.
+ *
+ * \param gps: Stroke to check.
+ * \param gsc: Space conversion data.
+ * \param mouse: Mouse position.
+ * \param diff_mat: View matrix.
+ * \return True if the point is inside.
+ */
bool ED_gpencil_stroke_point_is_inside(const struct bGPDstroke *gps,
const struct GP_SpaceConversion *gsc,
const int mouse[2],
const float diff_mat[4][4]);
+/**
+ * Get the bigger 2D bound box points.
+ */
void ED_gpencil_projected_2d_bound_box(const struct GP_SpaceConversion *gsc,
const struct bGPDstroke *gps,
const float diff_mat[4][4],
@@ -400,18 +633,27 @@ struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C,
const float ctrl2[2],
const float radius,
int *r_index);
+/**
+ * Get extremes of stroke in 2D using current view.
+ */
void ED_gpencil_stroke_extremes_to2d(const struct GP_SpaceConversion *gsc,
const float diff_mat[4][4],
struct bGPDstroke *gps,
float r_ctrl1[2],
float r_ctrl2[2]);
+/**
+ * Join two stroke using a contact point index and trimming the rest.
+ */
struct bGPDstroke *ED_gpencil_stroke_join_and_trim(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
struct bGPDstroke *gps_dst,
const int pt_index);
+/**
+ * Close if the distance between extremes is below threshold.
+ */
void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, const float threshold);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 1400bcf5ee3..3308ae2c178 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -48,11 +48,17 @@ float ED_space_image_zoom_level(const struct View2D *v2d, const int grid_dimensi
void ED_space_image_grid_steps(struct SpaceImage *sima,
float grid_steps[SI_GRID_STEPS_LEN],
const int grid_dimension);
+/**
+ * Calculate the increment snapping value for UV/image editor based on the zoom factor
+ * The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for
+ * drawing the grid overlay for the UV/Image editor.
+ */
float ED_space_image_increment_snap_value(const int grid_dimesnions,
const float grid_steps[SI_GRID_STEPS_LEN],
const float zoom_factor);
-/* image_edit.c, exported for transform */
+/* image_edit.c, exported for transform. */
+
struct Image *ED_space_image(const struct SpaceImage *sima);
void ED_space_image_set(struct Main *bmain,
struct SpaceImage *sima,
@@ -62,13 +68,22 @@ void ED_space_image_auto_set(const struct bContext *C, struct SpaceImage *sima);
struct Mask *ED_space_image_get_mask(const struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
+/**
+ * Returns mouse position in image space.
+ */
bool ED_space_image_get_position(struct SpaceImage *sima,
struct ARegion *region,
int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_node_color_sample().
+ */
bool ED_space_image_color_sample(
struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
+/**
+ * Get the #SpaceImage flag that is valid for the given ibuf.
+ */
int ED_space_image_get_display_channel_mask(struct ImBuf *ibuf);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);
@@ -87,6 +102,12 @@ void ED_space_image_scopes_update(const struct bContext *C,
struct ImBuf *ibuf,
bool use_view_settings);
+/**
+ * Enable the paint cursor if it isn't already.
+ *
+ * purpose is to make sure the paint cursor is shown if paint mode is enabled in the image editor.
+ * The paint poll will ensure that the cursor is hidden when not in paint mode.
+ */
void ED_space_image_paint_update(struct Main *bmain,
struct wmWindowManager *wm,
struct Scene *scene);
@@ -95,6 +116,7 @@ void ED_image_get_uv_aspect(struct Image *ima,
struct ImageUser *iuser,
float *r_aspx,
float *r_aspy);
+/** Takes `event->mval`. */
void ED_image_mouse_pos(struct SpaceImage *sima,
const struct ARegion *region,
const int mval[2],
@@ -110,6 +132,10 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima,
const struct ARegion *region,
const float co[2],
float r_co[2]);
+/**
+ * This is more a user-level functionality, for going to `next/prev` used slot,
+ * Stepping onto the last unused slot too.
+ */
bool ED_image_slot_cycle(struct Image *image, int direction);
bool ED_space_image_show_render(const struct SpaceImage *sima);
@@ -118,11 +144,17 @@ bool ED_space_image_show_uvedit(const struct SpaceImage *sima, struct Object *ob
bool ED_space_image_paint_curve(const struct bContext *C);
+/**
+ * Matches clip function.
+ */
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct Object *obedit);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
bool ED_space_image_cursor_poll(struct bContext *C);
+/**
+ * Used by node view too.
+ */
void ED_image_draw_info(struct Scene *scene,
struct ARegion *region,
bool color_manage,
@@ -161,6 +193,9 @@ typedef struct ImageFrameRange {
ListBase frames;
} ImageFrameRange;
+/**
+ * Used for both images and volume file loading.
+ */
ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
struct wmOperator *op,
const bool detect_udim);
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index dde26c072d0..caf76841bcd 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -39,6 +39,11 @@ const char *ED_info_statistics_string(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * \param v3d_local: Pass this argument to calculate view-port local statistics.
+ * Note that this must only be used for local-view, otherwise report specific statistics
+ * will be written into the global scene statistics giving incorrect results.
+ */
void ED_info_draw_stats(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index e29ff3ed890..bafe68bd28d 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -39,7 +39,9 @@ struct bDopeSheet;
/* ************************************************ */
/* Common Macros and Defines */
-/* --------- Tool Flags ------------ */
+/* -------------------------------------------------------------------- */
+/** \name Tool Flags
+ * \{ */
/* bezt validation */
typedef enum eEditKeyframes_Validate {
@@ -60,7 +62,7 @@ typedef enum eEditKeyframes_Validate {
BEZT_OK_CHANNEL_CIRCLE,
} eEditKeyframes_Validate;
-/* ------------ */
+/** \} */
/* select modes */
typedef enum eEditKeyframes_Select {
@@ -120,7 +122,9 @@ typedef struct KeyframeEdit_CircleData {
/* ************************************************ */
/* Non-Destructive Editing API (keyframes_edit.c) */
-/* --- Defines for 'OK' polls + KeyframeEditData Flags --------- */
+/* -------------------------------------------------------------------- */
+/** \name Defines for 'OK' polls + KeyframeEditData Flags
+ * \{ */
/* which verts of a keyframe is active (after polling) */
typedef enum eKeyframeVertOk {
@@ -154,7 +158,11 @@ typedef enum eKeyframeIterFlags {
KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE = (1 << 3),
} eKeyframeIterFlags;
-/* --- Generic Properties for Keyframe Edit Tools ----- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Properties for Keyframe Edit Tools
+ * \{ */
typedef struct KeyframeEditData {
/* generic properties/data access */
@@ -184,14 +192,22 @@ typedef struct KeyframeEditData {
eKeyframeIterFlags iterflags;
} KeyframeEditData;
-/* ------- Function Pointer Typedefs ---------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Function Pointer Typedefs
+ * \{ */
/* callback function that refreshes the F-Curve after use */
typedef void (*FcuEditFunc)(struct FCurve *fcu);
/* callback function that operates on the given BezTriple */
typedef short (*KeyframeEditFunc)(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ------- Custom Data Type Defines ------------------ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Type Defines
+ * \{ */
/* Custom data for remapping one range to another in a fixed way */
typedef struct KeyframeEditCD_Remap {
@@ -222,18 +238,28 @@ typedef enum eKeyMergeMode {
KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL,
} eKeyMergeMode;
-/* ---------------- Looping API --------------------- */
+/** \} */
-/* functions for looping over keyframes */
-/* function for working with F-Curve data only
- * (i.e. when filters have been chosen to explicitly use this) */
+/* -------------------------------------------------------------------- */
+/** \name Looping API
+ *
+ * Functions for looping over keyframes.
+ * \{ */
+
+/**
+ * This function is used to loop over BezTriples in the given F-Curve, applying a given
+ * operation on them, and optionally applies an F-Curve validation function afterwards.
+ *
+ * function for working with F-Curve data only
+ * (i.e. when filters have been chosen to explicitly use this).
+ */
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
struct FCurve *fcu,
KeyframeEditFunc key_ok,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* function for working with any type (i.e. one of the known types) of animation channel
- * - filterflag is bDopeSheet->flag (DOPESHEET_FILTERFLAG)
+/**
+ * Function for working with any type (i.e. one of the known types) of animation channel.
*/
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
struct bDopeSheet *ads,
@@ -241,8 +267,9 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
KeyframeEditFunc key_ok,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* same as above, except bAnimListElem wrapper is not needed...
- * - keytype is eAnim_KeyType
+/**
+ * Same as above, except bAnimListElem wrapper is not needed.
+ * \param keytype: is #eAnim_KeyType.
*/
short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
struct bDopeSheet *ads,
@@ -252,55 +279,92 @@ short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
-/* Calls callback_fn() for each keyframe in each fcurve in the filtered animation context.
- * Assumes the callback updates keys. */
+/**
+ * Calls callback_fn() for each keyframe in each fcurve in the filtered animation context.
+ * Assumes the callback updates keys.
+ */
void ANIM_animdata_keyframe_callback(struct bAnimContext *ac,
eAnimFilter_Flags filter,
KeyframeEditFunc callback_fn);
-/* functions for making sure all keyframes are in good order */
+/**
+ * Functions for making sure all keyframes are in good order.
+ */
void ANIM_editkeyframes_refresh(struct bAnimContext *ac);
-/* ----------- BezTriple Callback Getters ---------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callback Getters
+ * \{ */
/* accessories */
KeyframeEditFunc ANIM_editkeyframes_ok(short mode);
/* edit */
KeyframeEditFunc ANIM_editkeyframes_snap(short mode);
+/**
+ * \note for markers and 'value', the values to use must be supplied as the first float value.
+ */
KeyframeEditFunc ANIM_editkeyframes_mirror(short mode);
KeyframeEditFunc ANIM_editkeyframes_select(short mode);
+/**
+ * Set all selected Bezier Handles to a single type.
+ */
KeyframeEditFunc ANIM_editkeyframes_handles(short mode);
+/**
+ * Set the interpolation type of the selected BezTriples in each F-Curve to the specified one.
+ */
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode);
KeyframeEditFunc ANIM_editkeyframes_keytype(short mode);
KeyframeEditFunc ANIM_editkeyframes_easing(short mode);
-/* -------- BezTriple Callbacks (Selection Map) ---------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callbacks (Selection Map)
+ * \{ */
-/* Get a callback to populate the selection settings map
- * requires: ked->custom = char[] of length fcurve->totvert
+/**
+ * Get a callback to populate the selection settings map
+ * requires: ked->custom = char[] of length fcurve->totvert.
*/
KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode);
-/* Change the selection status of the keyframe based on the map entry for this vert
- * requires: ked->custom = char[] of length fcurve->totvert
+/**
+ * Change the selection status of the keyframe based on the map entry for this vert
+ * requires: ked->custom = char[] of length fcurve->totvert.
*/
short bezt_selmap_flush(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ----------- BezTriple Callback (Assorted Utilities) ---------- */
+/** \} */
-/* used to calculate the average location of all relevant BezTriples by summing their locations */
+/* -------------------------------------------------------------------- */
+/** \name BezTriple Callback (Assorted Utilities)
+ * \{ */
+
+/**
+ * Used to calculate the average location of all relevant BezTriples by summing their locations.
+ */
short bezt_calc_average(KeyframeEditData *ked, struct BezTriple *bezt);
-/* used to extract a set of cfra-elems from the keyframes */
+/**
+ * Used to extract a set of cfra-elems from the keyframes.
+ */
short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
-/* used to remap times from one range to another
- * requires: ked->custom = KeyframeEditCD_Remap
+/**
+ * Used to remap times from one range to another.
+ * requires: `ked->custom = KeyframeEditCD_Remap`.
*/
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ------ 1.5-D Region Testing Utilities (Lasso/Circle Select) ------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name 1.5-D Region Testing Utilities (Lasso/Circle Select)
+ * \{ */
+
/* XXX: These are temporary,
* until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
@@ -321,6 +385,9 @@ void clean_fcurve(struct bAnimContext *ac,
float thresh,
bool cleardefault);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
+/**
+ * Use a weighted moving-means method to reduce intensity of fluctuations.
+ */
void smooth_fcurve(struct FCurve *fcu);
void sample_fcurve(struct FCurve *fcu);
@@ -336,6 +403,8 @@ short paste_animedit_keys(struct bAnimContext *ac,
/* ************************************************ */
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 673f629d6ef..d539c7b688c 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -53,22 +53,28 @@ struct PropertyRNA;
struct NlaKeyframingContext;
-/* ************ Keyframing Management **************** */
+/* -------------------------------------------------------------------- */
+/** \name Key-Framing Management
+ * \{ */
-/* Get the active settings for keyframing settings from context (specifically the given scene)
- * - use_autokey_mode: include settings from keyframing mode in the result (i.e. replace only).
+/**
+ * Get the active settings for key-framing settings from context (specifically the given scene)
+ * \param use_autokey_mode: include settings from key-framing mode in the result
+ * (i.e. replace only).
*/
eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, const bool use_autokey_mode);
/* -------- */
-/* Get (or add relevant data to be able to do so) the Active Action for the given
+/**
+ * Get (or add relevant data to be able to do so) the Active Action for the given
* Animation Data block, given an ID block where the Animation Data should reside.
*/
struct bAction *ED_id_action_ensure(struct Main *bmain, struct ID *id);
-/* Get (or add relevant data to be able to do so) F-Curve from the given Action.
- * This assumes that all the destinations are valid.
+/**
+ * Get (or add relevant data to be able to do so) F-Curve from the Active Action,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
*/
struct FCurve *ED_action_fcurve_ensure(struct Main *bmain,
struct bAction *act,
@@ -77,15 +83,21 @@ struct FCurve *ED_action_fcurve_ensure(struct Main *bmain,
const char rna_path[],
const int array_index);
+/**
+ * Find the F-Curve from the Active Action,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
+ */
struct FCurve *ED_action_fcurve_find(struct bAction *act,
const char rna_path[],
const int array_index);
/* -------- */
-/* Lesser Keyframing API call:
- * Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
- * but also through RNA when editing an ID prop, see T37103).
+/**
+ * \brief Lesser Key-framing API call.
+ *
+ * Update integer/discrete flags of the FCurve (used when creating/inserting keyframes,
+ * but also through RNA when editing an ID prop, see T37103).
*/
void update_autoflags_fcurve(struct FCurve *fcu,
struct bContext *C,
@@ -94,16 +106,34 @@ void update_autoflags_fcurve(struct FCurve *fcu,
/* -------- */
-/* Lesser Keyframing API call:
- * Use this when validation of necessary animation data isn't necessary as it already
- * exists, and there is a beztriple that can be directly copied into the array.
+/**
+ * \brief Lesser Key-framing API call.
+ *
+ * Use this when validation of necessary animation data isn't necessary as it already
+ * exists, and there is a #BezTriple that can be directly copied into the array.
+ *
+ * This function adds a given #BezTriple to an F-Curve. It will allocate
+ * memory for the array if needed, and will insert the #BezTriple into a
+ * suitable place in chronological order.
+ *
+ * \note any recalculate of the F-Curve that needs to be done will need to be done by the caller.
*/
int insert_bezt_fcurve(struct FCurve *fcu, const struct BezTriple *bezt, eInsertKeyFlags flag);
-/* Main Keyframing API call:
- * Use this when validation of necessary animation data isn't necessary as it
- * already exists. It will insert a keyframe using the current value being keyframed.
- * Returns the index at which a keyframe was added (or -1 if failed)
+/**
+ * \brief Main Key-framing API call.
+ *
+ * Use this when validation of necessary animation data isn't necessary as it
+ * already exists. It will insert a keyframe using the current value being keyframed.
+ * Returns the index at which a keyframe was added (or -1 if failed).
+ *
+ * This function is a wrapper for #insert_bezt_fcurve(), and should be used when
+ * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
+ * It returns the index at which the keyframe was added.
+ *
+ * \param keyframe_type: The type of keyframe (#eBezTriple_KeyframeType).
+ * \param flag: Optional flags (#eInsertKeyFlags) for controlling how keys get added
+ * and/or whether updates get done.
*/
int insert_vert_fcurve(struct FCurve *fcu,
float x,
@@ -113,9 +143,21 @@ int insert_vert_fcurve(struct FCurve *fcu,
/* -------- */
-/* Secondary Keyframing API calls:
- * Use this to insert a keyframe using the current value being keyframed, in the
- * nominated F-Curve (no creation of animation data performed). Returns success.
+/**
+ * \brief Secondary Insert Key-framing API call.
+ *
+ * Use this when validation of necessary animation data is not necessary,
+ * since an RNA-pointer to the necessary data being keyframed,
+ * and a pointer to the F-Curve to use have both been provided.
+ *
+ * This function can't keyframe quaternion channels on some NLA strip types.
+ *
+ * \param keytype: The "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet.
+ *
+ * \param flag: Used for special settings that alter the behavior of the keyframe insertion.
+ * These include the 'visual' key-framing modes, quick refresh,
+ * and extra keyframe filtering.
+ * \return Success.
*/
bool insert_keyframe_direct(struct ReportList *reports,
struct PointerRNA ptr,
@@ -128,9 +170,17 @@ bool insert_keyframe_direct(struct ReportList *reports,
/* -------- */
-/* Main Keyframing API calls:
+/**
+ * \brief Main Insert Key-framing API call.
+ *
* Use this to create any necessary animation data, and then insert a keyframe
- * using the current value being keyframed, in the relevant place. Returns success.
+ * using the current value being keyframed, in the relevant place.
+ *
+ * \param flag: Used for special settings that alter the behavior of the keyframe insertion.
+ * These include the 'visual' key-framing modes, quick refresh, and extra keyframe filtering.
+ *
+ * \param array_index: The index to key or -1 keys all array indices.
+ * \return The number of key-frames inserted.
*/
int insert_keyframe(struct Main *bmain,
struct ReportList *reports,
@@ -144,9 +194,13 @@ int insert_keyframe(struct Main *bmain,
struct ListBase *nla_cache,
eInsertKeyFlags flag);
-/* Main Keyframing API call:
+/**
+ * \brief Main Delete Key-Framing API call.
+ *
* Use this to delete keyframe on current frame for relevant channel.
- * Will perform checks just in case. */
+ * Will perform checks just in case.
+ * \return The number of key-frames deleted.
+ */
int delete_keyframe(struct Main *bmain,
struct ReportList *reports,
struct ID *id,
@@ -155,7 +209,11 @@ int delete_keyframe(struct Main *bmain,
int array_index,
float cfra);
-/* ************ Keying Sets ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying Sets
+ * \{ */
/* forward decl. for this struct which is declared a bit later... */
struct ExtensionRNA;
@@ -206,7 +264,9 @@ typedef struct KeyingSetInfo {
/* -------- */
-/* Add another data source for Relative Keying Sets to be evaluated with */
+/**
+ * Add another data source for Relative Keying Sets to be evaluated with.
+ */
void ANIM_relative_keyingset_add_source(ListBase *dsources,
struct ID *id,
struct StructRNA *srna,
@@ -226,13 +286,28 @@ typedef enum eModifyKey_Returns {
MODIFYKEY_MISSING_TYPEINFO = -2,
} eModifyKey_Returns;
-/* poll the current KeyingSet, updating its set of paths
- * (if "builtin"/"relative") for context changes */
+/**
+ * Given a #KeyingSet and context info, validate Keying Set's paths.
+ * This is only really necessary with relative/built-in KeyingSets
+ * where their list of paths is dynamically generated based on the
+ * current context info.
+ *
+ * \return 0 if succeeded, otherwise an error code: #eModifyKey_Returns.
+ */
eModifyKey_Returns ANIM_validate_keyingset(struct bContext *C,
ListBase *dsources,
struct KeyingSet *ks);
-/* use the specified KeyingSet to add/remove various Keyframes on the specified frame */
+/**
+ * Use the specified #KeyingSet and context info (if required)
+ * to add/remove various Keyframes on the specified frame.
+ *
+ * Modify keyframes for the channels specified by the KeyingSet.
+ * This takes into account many of the different combinations of using KeyingSets.
+ *
+ * \returns the number of channels that key-frames were added or
+ * an #eModifyKey_Returns value (always a negative number).
+ */
int ANIM_apply_keyingset(struct bContext *C,
ListBase *dsources,
struct bAction *act,
@@ -242,49 +317,88 @@ int ANIM_apply_keyingset(struct bContext *C,
/* -------- */
-/* Get the first builtin KeyingSet with the given name, which occurs after the given one
- * (or start of list if none given) */
+/**
+ * Find builtin #KeyingSet by name.
+ *
+ * \return The first builtin #KeyingSet with the given name, which occurs after the given one
+ * (or start of list if none given).
+ */
struct KeyingSet *ANIM_builtin_keyingset_get_named(struct KeyingSet *prevKS, const char name[]);
-/* Find KeyingSet type info given a name */
+/**
+ * Find KeyingSet type info given a name.
+ */
KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[]);
-/* Find a given ID in the KeyingSet */
+/**
+ * Check if the ID appears in the paths specified by the #KeyingSet.
+ */
bool ANIM_keyingset_find_id(struct KeyingSet *ks, ID *id);
-/* for RNA type registrations... */
+/**
+ * Add the given KeyingSetInfo to the list of type infos,
+ * and create an appropriate builtin set too.
+ */
void ANIM_keyingset_info_register(KeyingSetInfo *ksi);
+/**
+ * Remove the given #KeyingSetInfo from the list of type infos,
+ * and also remove the builtin set if appropriate.
+ */
void ANIM_keyingset_info_unregister(struct Main *bmain, KeyingSetInfo *ksi);
/* cleanup on exit */
+/* --------------- */
+
void ANIM_keyingset_infos_exit(void);
/* -------- */
-/* Get the active KeyingSet for the given scene */
+/**
+ * Get the active Keying Set for the given scene.
+ */
struct KeyingSet *ANIM_scene_get_active_keyingset(const struct Scene *scene);
-/* Get the index of the Keying Set provided, for the given Scene */
+/**
+ * Get the index of the Keying Set provided, for the given Scene.
+ */
int ANIM_scene_get_keyingset_index(struct Scene *scene, struct KeyingSet *ks);
-/* Get Keying Set to use for Auto-Keyframing some transforms */
+/**
+ * Get Keying Set to use for Auto-Key-Framing some transforms.
+ */
struct KeyingSet *ANIM_get_keyingset_for_autokeying(const struct Scene *scene,
const char *transformKSName);
-/* Dynamically populate an enum of Keying Sets */
+/**
+ * Dynamically populate an enum of Keying Sets.
+ */
const struct EnumPropertyItem *ANIM_keying_sets_enum_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
-/* Use to get the keying set from the int value used by enums. */
+/**
+ * Get the keying set from enum values generated in #ANIM_keying_sets_enum_itemf.
+ *
+ * Type is the Keying Set the user specified to use when calling the operator:
+ * \param type:
+ * - == 0: use scene's active Keying Set.
+ * - > 0: use a user-defined Keying Set from the active scene.
+ * - < 0: use a builtin Keying Set.
+ */
KeyingSet *ANIM_keyingset_get_from_enum_type(struct Scene *scene, int type);
KeyingSet *ANIM_keyingset_get_from_idname(struct Scene *scene, const char *idname);
-/* Check if KeyingSet can be used in the current context */
+/**
+ * Check if #KeyingSet can be used in the current context.
+ */
bool ANIM_keyingset_context_ok_poll(struct bContext *C, struct KeyingSet *ks);
-/* ************ Drivers ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drivers
+ * \{ */
/* Flags for use by driver creation calls */
typedef enum eCreateDriverFlags {
@@ -311,7 +425,10 @@ typedef enum eCreateDriver_MappingTypes {
CREATEDRIVER_MAPPING_NONE_ALL = 4,
} eCreateDriver_MappingTypes;
-/* RNA Enum of eCreateDriver_MappingTypes, for use by the appropriate operators */
+/**
+ * Mapping Types enum for operators.
+ * \note Used by #ANIM_OT_driver_button_add and #UI_OT_eyedropper_driver.
+ */
extern EnumPropertyItem prop_driver_create_mapping_types[];
/* -------- */
@@ -323,7 +440,11 @@ typedef enum eDriverFCurveCreationMode {
DRIVER_FCURVE_EMPTY = 3 /* Add without data, for pasting. */
} eDriverFCurveCreationMode;
-/* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools,
+/**
+ * Get (or add relevant data to be able to do so) F-Curve from the driver stack,
+ * for the given Animation Data block. This assumes that all the destinations are valid.
+ *
+ * \note This low-level function shouldn't be used directly for most tools,
* although there are special cases where this approach is preferable.
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
@@ -337,16 +458,18 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[],
/* -------- */
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block,
- * and make it be driven by the specified target.
+/**
+ * \brief Main Driver Management API calls
+ *
+ * Add a new driver for the specified property on the given ID block,
+ * and make it be driven by the specified target.
*
* This is intended to be used in conjunction with a modal "eyedropper"
* for picking the variable that is going to be used to drive this one.
*
- * - flag: eCreateDriverFlags
- * - driver_type: eDriver_Types
- * - mapping_type: eCreateDriver_MappingTypes
+ * \param flag: eCreateDriverFlags
+ * \param driver_type: eDriver_Types
+ * \param mapping_type: eCreateDriver_MappingTypes
*/
int ANIM_add_driver_with_target(struct ReportList *reports,
struct ID *dst_id,
@@ -361,8 +484,10 @@ int ANIM_add_driver_with_target(struct ReportList *reports,
/* -------- */
-/* Main Driver Management API calls:
- * Add a new driver for the specified property on the given ID block
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Add a new driver for the specified property on the given ID block
*/
int ANIM_add_driver(struct ReportList *reports,
struct ID *id,
@@ -371,90 +496,128 @@ int ANIM_add_driver(struct ReportList *reports,
short flag,
int type);
-/* Main Driver Management API calls:
- * Remove the driver for the specified property on the given ID block (if available)
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Remove the driver for the specified property on the given ID block (if available).
*/
bool ANIM_remove_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
/* -------- */
-/* Clear copy-paste buffer for drivers */
+/**
+ * Clear copy-paste buffer for drivers.
+ * \note This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ANIM_drivers_copybuf_free(void);
-/* Clear copy-paste buffer for driver variable sets */
+/**
+ * Clear copy-paste buffer for driver variable sets.
+ * \note This function frees any MEM_calloc'ed copy/paste buffer data.
+ */
void ANIM_driver_vars_copybuf_free(void);
/* -------- */
-/* Returns whether there is a driver in the copy/paste buffer to paste */
+/**
+ * Returns whether there is a driver in the copy/paste buffer to paste.
+ */
bool ANIM_driver_can_paste(void);
-/* Main Driver Management API calls:
- * Make a copy of the driver for the specified property on the given ID block
+/**
+ * \brief Main Driver Management API calls.
+ *
+ * Make a copy of the driver for the specified property on the given ID block.
*/
bool ANIM_copy_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
-/* Main Driver Management API calls:
+/**
+ * \brief Main Driver Management API calls.
+ *
* Add a new driver for the specified property on the given ID block or replace an existing one
- * with the driver + driver-curve data from the buffer
+ * with the driver + driver-curve data from the buffer.
*/
bool ANIM_paste_driver(
struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
/* -------- */
-/* Checks if there are driver variables in the copy/paste buffer */
+/**
+ * Checks if there are driver variables in the copy/paste buffer.
+ */
bool ANIM_driver_vars_can_paste(void);
-/* Copy the given driver's variables to the buffer */
+/**
+ * Copy the given driver's variables to the buffer.
+ */
bool ANIM_driver_vars_copy(struct ReportList *reports, struct FCurve *fcu);
-/* Paste the variables in the buffer to the given FCurve */
+/**
+ * Paste the variables in the buffer to the given FCurve.
+ */
bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool replace);
/* -------- */
-/* Create a driver & variable that reads the specified property,
- * and store it in the buffers for Paste Driver and Paste Variables. */
+/**
+ * Create a driver & variable that reads the specified property,
+ * and store it in the buffers for Paste Driver and Paste Variables.
+ */
void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name);
-/* ************ Auto-Keyframing ********************** */
-/* Notes:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Key-Framing
+ *
+ * Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
* are defined in DNA_userdef_types.h
- * - Scene settings take precedence over those for userprefs, with old files
- * inheriting userpref settings for the scene settings
- * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored
- * as userprefs
- */
+ * - Scene settings take precedence over those for user-preferences, with old files
+ * inheriting user-preferences settings for the scene settings
+ * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored as user-preferences.
+ * \{ */
-/* Auto-Keying macros for use by various tools */
-/* check if auto-keyframing is enabled (per scene takes precedence) */
+/* Auto-Keying macros for use by various tools. */
+
+/** Check if auto-key-framing is enabled (per scene takes precedence).
+ */
#define IS_AUTOKEY_ON(scene) \
((scene) ? ((scene)->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
-/* Check the mode for auto-keyframing (per scene takes precedence). */
+/** Check the mode for auto-keyframing (per scene takes precedence). */
#define IS_AUTOKEY_MODE(scene, mode) \
((scene) ? ((scene)->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : \
(U.autokey_mode == AUTOKEY_MODE_##mode))
-/* check if a flag is set for auto-keyframing (per scene takes precedence) */
+/** Check if a flag is set for auto-key-framing (per scene takes precedence). */
#define IS_AUTOKEY_FLAG(scene, flag) \
((scene) ? (((scene)->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || \
(U.autokey_flag & AUTOKEY_FLAG_##flag)) : \
(U.autokey_flag & AUTOKEY_FLAG_##flag))
-/* auto-keyframing feature - checks for whether anything should be done for the current frame */
+/**
+ * Auto-keyframing feature - checks for whether anything should be done for the current frame.
+ */
bool autokeyframe_cfra_can_key(const struct Scene *scene, struct ID *id);
-/* ************ Keyframe Checking ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keyframe Checking
+ * \{ */
-/* Lesser Keyframe Checking API call:
- * - Used for the buttons to check for keyframes...
+/**
+ * \brief Lesser Keyframe Checking API call.
+ *
+ * Checks if some F-Curve has a keyframe for a given frame.
+ * \note Used for the buttons to check for keyframes.
*/
bool fcurve_frame_has_keyframe(const struct FCurve *fcu, float frame, short filter);
-/* Lesser Keyframe Checking API call:
+/**
+ * \brief Lesser Keyframe Checking API call.
+ *
* - Returns whether the current value of a given property differs from the interpolated value.
* - Used for button drawing.
*/
@@ -464,18 +627,19 @@ bool fcurve_is_changed(struct PointerRNA ptr,
const struct AnimationEvalContext *anim_eval_context);
/**
- * Main Keyframe Checking API call:
+ * \brief Main Keyframe Checking API call.
+ *
* Checks whether a keyframe exists for the given ID-block one the given frame.
- * - It is recommended to call this method over the other keyframe-checkers directly,
- * in case some detail of the implementation changes...
- * - frame: the value of this is quite often result of #BKE_scene_ctime_get()
+ * It is recommended to call this method over the other keyframe-checkers directly,
+ * in case some detail of the implementation changes...
+ * \param frame: The value of this is quite often result of #BKE_scene_ctime_get()
*/
bool id_frame_has_keyframe(struct ID *id, float frame, short filter);
-/* filter flags for id_cfra_has_keyframe
+/**
+ * Filter flags for #id_frame_has_keyframe.
*
- * WARNING: do not alter order of these, as also stored in files
- * (for v3d->keyflags)
+ * \warning do not alter order of these, as also stored in files (for `v3d->keyflags`).
*/
typedef enum eAnimFilterFlags {
/* general */
@@ -488,7 +652,8 @@ typedef enum eAnimFilterFlags {
ANIMFILTER_KEYS_NOSKEY = (1 << 10), /* don't include shape keys (for geometry) */
} eAnimFilterFlags;
-/* utility funcs for auto keyframe */
+/* Utility functions for auto key-frame. */
+
bool ED_autokeyframe_object(struct bContext *C,
struct Scene *scene,
struct Object *ob,
@@ -498,6 +663,9 @@ bool ED_autokeyframe_pchan(struct bContext *C,
struct Object *ob,
struct bPoseChannel *pchan,
struct KeyingSet *ks);
+/**
+ * Use for auto-key-framing from the UI.
+ */
bool ED_autokeyframe_property(struct bContext *C,
struct Scene *scene,
PointerRNA *ptr,
@@ -506,7 +674,8 @@ bool ED_autokeyframe_property(struct bContext *C,
float cfra);
/* Names for builtin keying sets so we don't confuse these with labels/text,
- * defined in python script: keyingsets_builtins.py */
+ * defined in python script: `keyingsets_builtins.py`. */
+
#define ANIM_KS_LOCATION_ID "Location"
#define ANIM_KS_ROTATION_ID "Rotation"
#define ANIM_KS_SCALING_ID "Scaling"
@@ -516,6 +685,8 @@ bool ED_autokeyframe_property(struct bContext *C,
#define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter"
#define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected"
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 6982ad20f07..dc800d78007 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -33,10 +33,12 @@ struct UndoType;
struct wmKeyConfig;
/* lattice_ops.c */
+
void ED_operatortypes_lattice(void);
void ED_keymap_lattice(struct wmKeyConfig *keyconf);
/* editlattice_select.c */
+
bool ED_lattice_flags_set(struct Object *obedit, int flag);
bool ED_lattice_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
@@ -45,6 +47,8 @@ bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool ED_lattice_deselect_all_multi(struct bContext *C);
/* editlattice_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_lattice_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_markers.h b/source/blender/editors/include/ED_markers.h
index 8c10a8e36fd..8e6961ffd6f 100644
--- a/source/blender/editors/include/ED_markers.h
+++ b/source/blender/editors/include/ED_markers.h
@@ -33,7 +33,9 @@ struct bAnimContext;
struct bContext;
struct wmKeyConfig;
-/* Drawing API ------------------------------ */
+/* -------------------------------------------------------------------- */
+/** \name Drawing API
+ * \{ */
/* flags for drawing markers */
enum {
@@ -42,37 +44,86 @@ enum {
DRAW_MARKERS_MARGIN = (1 << 2),
};
+/* Draw Scene-Markers in time window */
void ED_markers_draw(const struct bContext *C, int flag);
-/* Backend API ----------------------------- */
+/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Backend API
+ * \{ */
+
+/**
+ * Public API for getting markers from context.
+ */
ListBase *ED_context_get_markers(const struct bContext *C);
+/**
+ * Public API for getting markers from "animation" context.
+ */
ListBase *ED_animcontext_get_markers(const struct bAnimContext *ac);
+/**
+ * Apply some transformation to markers after the fact
+ *
+ * \param markers: List of markers to affect - this may or may not be the scene markers list,
+ * so don't assume anything.
+ * \param scene: Current scene (for getting current frame)
+ * \param mode: (TfmMode) transform mode that this transform is for
+ * \param value: From the transform code, this is `t->vec[0]`
+ * (which is delta transform for grab/extend, and scale factor for scale)
+ * \param side: (B/L/R) for 'extend' functionality, which side of current frame to use
+ */
int ED_markers_post_apply_transform(
ListBase *markers, struct Scene *scene, int mode, float value, char side);
+/**
+ * Get the marker that is closest to this point.
+ * XXX: for select, the min_dist should be small.
+ */
struct TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x);
+/**
+ * Return the time of the marker that occurs on a frame closest to the given time.
+ */
int ED_markers_find_nearest_marker_time(ListBase *markers, float x);
void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *last);
+/**
+ * This function makes a list of all the markers. The only_sel
+ * argument is used to specify whether only the selected markers
+ * are added.
+ */
void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short sel);
void ED_markers_deselect_all(ListBase *markers, int action);
+/**
+ * Get the first selected marker.
+ */
struct TimeMarker *ED_markers_get_first_selected(ListBase *markers);
-/* Operators ------------------------------ */
+/** \} */
-/* called in screen_ops.c:ED_operatortypes_screen() */
+/* -------------------------------------------------------------------- */
+/** \name Operators
+ * \{ */
+
+/**
+ * Called in screen_ops.c:ED_operatortypes_screen().
+ */
void ED_operatortypes_marker(void);
-/* called in screen_ops.c:ED_keymap_screen() */
+/**
+ * Called in screen_ops.c:ED_keymap_screen().
+ */
void ED_keymap_marker(struct wmKeyConfig *keyconf);
-/* debugging only */
+/**
+ * Debugging only: print debugging prints of list of markers.
+ */
void debug_markers_print_list(struct ListBase *markers);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index c2fdbc160de..3aab6882dc2 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -37,6 +37,7 @@ struct bContext;
struct wmKeyConfig;
/* mask_edit.c */
+
void ED_mask_deselect_all(const struct bContext *C);
void ED_operatortypes_mask(void);
@@ -44,6 +45,7 @@ void ED_keymap_mask(struct wmKeyConfig *keyconf);
void ED_operatormacros_mask(void);
/* mask_query.c */
+
void ED_mask_get_size(struct ScrArea *area, int *width, int *height);
void ED_mask_zoom(struct ScrArea *area, struct ARegion *region, float *zoomx, float *zoomy);
void ED_mask_get_aspect(struct ScrArea *area, struct ARegion *region, float *aspx, float *aspy);
@@ -52,11 +54,18 @@ void ED_mask_pixelspace_factor(struct ScrArea *area,
struct ARegion *region,
float *scalex,
float *scaley);
+/**
+ * Takes `event->mval`.
+ */
void ED_mask_mouse_pos(struct ScrArea *area,
struct ARegion *region,
const int mval[2],
float co[2]);
+/**
+ * \param x/y: input, mval space.
+ * \param xr/yr: output, mask point space.
+ */
void ED_mask_point_pos(
struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
void ED_mask_point_pos__reverse(
@@ -69,7 +78,12 @@ bool ED_mask_selected_minmax(const struct bContext *C,
bool handles_as_control_point);
/* mask_draw.c */
+
void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type);
+/**
+ * Sets up the opengl context.
+ * width, height are to match the values from #ED_mask_get_size().
+ */
void ED_mask_draw_region(struct Depsgraph *depsgraph,
struct Mask *mask,
struct ARegion *region,
@@ -89,33 +103,68 @@ void ED_mask_draw_frames(
struct Mask *mask, struct ARegion *region, const int cfra, const int sfra, const int efra);
/* mask_shapekey.c */
+
void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, const int frame);
bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, const int frame);
bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, const int frame);
/* ----------- Mask AnimEdit API ------------------ */
+
+/**
+ * Loops over the mask-frames for a mask-layer, and applies the given callback.
+ */
bool ED_masklayer_frames_looper(struct MaskLayer *mask_layer,
struct Scene *scene,
bool (*mask_layer_shape_cb)(struct MaskLayerShape *,
struct Scene *));
+/**
+ * Make a listing all the mask-frames in a layer as cfraelems.
+ */
void ED_masklayer_make_cfra_list(struct MaskLayer *mask_layer, ListBase *elems, bool onlysel);
+/**
+ * Check if one of the frames in this layer is selected.
+ */
bool ED_masklayer_frame_select_check(const struct MaskLayer *mask_layer);
+/**
+ * Set all/none/invert select.
+ */
void ED_masklayer_frame_select_set(struct MaskLayer *mask_layer, short mode);
+/**
+ * Select the frames in this layer that occur within the bounds specified.
+ */
void ED_masklayer_frames_select_box(struct MaskLayer *mask_layer,
float min,
float max,
short select_mode);
+/**
+ * Select the frames in this layer that occur within the lasso/circle region specified.
+ */
void ED_masklayer_frames_select_region(struct KeyframeEditData *ked,
struct MaskLayer *mask_layer,
short tool,
short select_mode);
+/**
+ * Set all/none/invert select (like above, but with SELECT_* modes).
+ */
void ED_mask_select_frames(struct MaskLayer *mask_layer, short select_mode);
+/**
+ * Select the frame in this layer that occurs on this frame (there should only be one at most).
+ */
void ED_mask_select_frame(struct MaskLayer *mask_layer, int selx, short select_mode);
+/**
+ * Delete selected frames.
+ */
bool ED_masklayer_frames_delete(struct MaskLayer *mask_layer);
+/**
+ * Duplicate selected frames from given mask-layer.
+ */
void ED_masklayer_frames_duplicate(struct MaskLayer *mask_layer);
+/**
+ * Snap selected frames to ...
+ */
void ED_masklayer_snap_frames(struct MaskLayer *mask_layer, struct Scene *scene, short mode);
#if 0
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 7648af159c9..1afd7f06a5a 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -37,6 +37,9 @@ void ED_operatortypes_metaball(void);
void ED_operatormacros_metaball(void);
void ED_keymap_metaball(struct wmKeyConfig *keyconf);
+/**
+ * Add meta-element primitive to meta-ball object (which is in edit mode).
+ */
struct MetaElem *ED_mball_add_primitive(struct bContext *C,
struct Object *obedit,
bool obedit_is_new,
@@ -44,17 +47,32 @@ struct MetaElem *ED_mball_add_primitive(struct bContext *C,
float dia,
int type);
+/**
+ * Select MetaElement with mouse click (user can select radius circle or stiffness circle).
+ */
bool ED_mball_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
bool ED_mball_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_mball_deselect_all_multi(struct bContext *C);
+/**
+ * This function is used to free all MetaElems from MetaBall.
+ */
void ED_mball_editmball_free(struct Object *obedit);
+/**
+ * This function is called, when MetaBall Object is switched from object mode to edit mode.
+ */
void ED_mball_editmball_make(struct Object *obedit);
+/**
+ * This function is called, when MetaBall Object switched from edit mode to object mode.
+ * List of MetaElements is copied from object->data->edit_elems to object->data->elems.
+ */
void ED_mball_editmball_load(struct Object *obedit);
/* editmball_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_mball_undosys_type(struct UndoType *ut);
#define MBALLSEL_STIFF (1u << 30)
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 22de6ca15bf..35838f4ce48 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -58,6 +58,17 @@ struct wmKeyConfig;
struct wmOperator;
/* editmesh_utils.c */
+
+/**
+ * \param em: Editmesh.
+ * \param use_self: Allow a vertex to point to its self (middle verts).
+ * \param use_select: Restrict to selected verts.
+ * \param respecthide: Skip hidden vertices.
+ * \param use_topology: Use topology mirror.
+ * \param maxdist: Distance for close point test.
+ * \param r_index: Optional array to write into, as an alternative to a customdata layer
+ * (length of total verts).
+ */
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em,
const int axis,
const bool use_self,
@@ -86,14 +97,24 @@ void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
+/**
+ * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
+ */
void EDBM_mesh_free_data(struct BMEditMesh *em);
+/**
+ * \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
+ * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913.
+ * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh.
+ */
void EDBM_mesh_load_ex(struct Main *bmain, struct Object *ob, bool free_data);
void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
-/* flushes based on the current select mode. if in vertex select mode,
+/**
+ * flushes based on the current select mode. If in vertex select mode,
* verts select/deselect edges and faces, if in edge select mode,
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
- * edges and vertices. */
+ * edges and vertices.
+ */
void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step);
void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step);
@@ -105,6 +126,9 @@ void EDBM_select_flush(struct BMEditMesh *em);
bool EDBM_vert_color_check(struct BMEditMesh *em);
+/**
+ * Swap is 0 or 1, if 1 it hides not selected.
+ */
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap);
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select);
@@ -114,9 +138,18 @@ struct EDBMUpdate_Params {
uint is_destructive : 1;
};
+/**
+ * So many tools call these that we better make it a generic function.
+ */
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params);
+/**
+ * Bad level call from Python API.
+ */
void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive);
+/**
+ * A specialized vert map used by stitch operator.
+ */
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
const struct Scene *scene,
const bool face_selected,
@@ -128,13 +161,23 @@ struct UvElement *BM_uv_element_get(struct UvElementMap *map,
struct BMFace *efa,
struct BMLoop *l);
+/**
+ * Can we edit UV's for this mesh?
+ */
bool EDBM_uv_check(struct BMEditMesh *em);
+/**
+ * last_sel, use em->act_face otherwise get the last selected face in the editselections
+ * at the moment, last_sel is mainly useful for making sure the space image doesn't flicker.
+ */
struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em,
const bool sloppy,
const bool selected);
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
+/**
+ * Return a new #UvVertMap from the edit-mesh.
+ */
struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm,
const bool use_select,
const bool use_winding);
@@ -156,6 +199,7 @@ void EDBM_project_snap_verts(struct bContext *C,
struct BMEditMesh *em);
/* editmesh_automerge.c */
+
void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
void EDBM_automerge_and_split(struct Object *ob,
const bool split_edges,
@@ -165,9 +209,12 @@ void EDBM_automerge_and_split(struct Object *ob,
const float dist);
/* editmesh_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_mesh_undosys_type(struct UndoType *ut);
/* editmesh_select.c */
+
void EDBM_select_mirrored(struct BMEditMesh *em,
const struct Mesh *me,
const int axis,
@@ -175,6 +222,17 @@ void EDBM_select_mirrored(struct BMEditMesh *em,
int *r_totmirr,
int *r_totfail);
+/**
+ * Nearest vertex under the cursor.
+ *
+ * \param dist_px_manhattan_p: (in/out), minimal distance to the nearest and at the end,
+ * actual distance.
+ * \param use_select_bias:
+ * - When true, selected vertices are given a 5 pixel bias
+ * to make them further than unselected vertices.
+ * - When false, unselected vertices are given the bias.
+ * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
+ */
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan_p,
const bool use_select_bias,
@@ -195,6 +253,13 @@ struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc,
uint *r_base_index);
struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p);
+/**
+ * \param use_zbuf_single_px: Special case, when using the back-buffer selection,
+ * only use the pixel at `vc->mval` instead of using `dist_px_manhattan_p` to search over a larger
+ * region. This is needed because historically selection worked this way for a long time, however
+ * it's reasonable that some callers might want to expand the region too. So add an argument to do
+ * this,
+ */
struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan,
float *r_dist_center,
@@ -230,19 +295,48 @@ bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
bool EDBM_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/**
+ * When switching select mode, makes sure selection is consistent for editing
+ * also for paranoia checks to make sure edge or face mode works.
+ */
void EDBM_selectmode_set(struct BMEditMesh *em);
+/**
+ * Expand & Contract the Selection
+ * (used when changing modes and Ctrl key held)
+ *
+ * Flush the selection up:
+ * - vert -> edge
+ * - vert -> face
+ * - edge -> face
+ *
+ * Flush the selection down:
+ * - face -> edge
+ * - face -> vert
+ * - edge -> vert
+ */
void EDBM_selectmode_convert(struct BMEditMesh *em,
const short selectmode_old,
const short selectmode_new);
-/* user access this */
+/**
+ * User access this.
+ */
bool EDBM_selectmode_set_multi(struct bContext *C, const short selectmode);
+/**
+ * User facing function, does notification.
+ */
bool EDBM_selectmode_toggle_multi(struct bContext *C,
const short selectmode_new,
const int action,
const bool use_extend,
const bool use_expand);
+/**
+ * Use to disable a select-mode if its enabled, Using another mode as a fallback
+ * if the disabled mode is the only mode set.
+ *
+ * \return true if the mode is changed.
+ */
bool EDBM_selectmode_disable(struct Scene *scene,
struct BMEditMesh *em,
const short selectmode_disable,
@@ -305,12 +399,22 @@ void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
void EDBM_preselect_action_set(struct EditMesh_PreSelElem *psel,
eEditMesh_PreSelPreviewAction action);
eEditMesh_PreSelPreviewAction EDBM_preselect_action_get(struct EditMesh_PreSelElem *psel);
+
/* mesh_ops.c */
+
void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
+/**
+ * Note mesh keymap also for other space?
+ */
void ED_keymap_mesh(struct wmKeyConfig *keyconf);
/* editface.c */
+
+/**
+ * Copy the face flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting faces (while painting).
+ */
void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag);
bool paintface_mouse_select(struct bContext *C,
struct Object *ob,
@@ -331,8 +435,17 @@ bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]);
void paintface_hide(struct bContext *C, struct Object *ob, const bool unselected);
void paintface_reveal(struct bContext *C, struct Object *ob, const bool select);
+/**
+ * \note if the caller passes false to flush_flags,
+ * then they will need to run #paintvert_flush_flags(ob) themselves.
+ */
bool paintvert_deselect_all_visible(struct Object *ob, int action, bool flush_flags);
void paintvert_select_ungrouped(struct Object *ob, bool extend, bool flush_flags);
+/**
+ * (similar to void `paintface_flush_flags(Object *ob)`)
+ * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting vertices (while painting).
+ */
void paintvert_flush_flags(struct Object *ob);
void paintvert_tag_select_update(struct bContext *C, struct Object *ob);
@@ -360,17 +473,35 @@ void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
bool ED_vgroup_sync_from_pose(struct Object *ob);
void ED_vgroup_select_by_name(struct Object *ob, const char *name);
+/**
+ * Removes out of range #MDeformWeights
+ */
void ED_vgroup_data_clamp_range(struct ID *id, const int total);
+/**
+ * Matching index only.
+ */
bool ED_vgroup_array_copy(struct Object *ob, struct Object *ob_from);
bool ED_vgroup_parray_alloc(struct ID *id,
struct MDeformVert ***dvert_arr,
int *dvert_tot,
const bool use_vert_sel);
+/**
+ * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true.
+ * This finds the unselected mirror deform verts and copies the weights to them from the selected.
+ *
+ * \note \a dvert_array has mirrored weights filled in,
+ * in case cleanup operations are needed on both.
+ */
void ED_vgroup_parray_mirror_sync(struct Object *ob,
struct MDeformVert **dvert_array,
const int dvert_tot,
const bool *vgroup_validmap,
const int vgroup_tot);
+/**
+ * Fill in the pointers for mirror verts (as if all mirror verts were selected too).
+ *
+ * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points.
+ */
void ED_vgroup_parray_mirror_assign(struct Object *ob,
struct MDeformVert **dvert_array,
const int dvert_tot);
@@ -397,13 +528,23 @@ void ED_vgroup_mirror(struct Object *ob,
int *r_totmirr,
int *r_totfail);
+/**
+ * Called while not in editmode.
+ */
void ED_vgroup_vert_add(
struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode);
+/**
+ * Mesh object mode, lattice can be in edit-mode.
+ */
void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum);
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
+/**
+ * Use when adjusting the active vertex weight and apply to mirror vertices.
+ */
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
/* mesh_data.c */
+
void ED_mesh_verts_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count);
@@ -428,6 +569,9 @@ bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n);
bool ED_mesh_uv_texture_remove_active(struct Mesh *me);
bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name);
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me);
+/**
+ * Without a #bContext, called when UV-editing.
+ */
void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum);
bool ED_mesh_color_ensure(struct Mesh *me, const char *name);
int ED_mesh_color_add(struct Mesh *me,
@@ -452,7 +596,9 @@ bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name);
void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail);
void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode);
-/* Returns the pinned mesh, the mesh from the pinned object, or the mesh from the active object. */
+/**
+ * Returns the pinned mesh, the mesh from the pinned object, or the mesh from the active object.
+ */
struct Mesh *ED_mesh_context(struct bContext *C);
/* mesh backup */
@@ -460,20 +606,30 @@ typedef struct BMBackup {
struct BMesh *bmcopy;
} BMBackup;
+/**
+ * Save a copy of the #BMesh for restoring later.
+ */
struct BMBackup EDBM_redo_state_store(struct BMEditMesh *em);
-/* restore a bmesh from backup */
+/**
+ * Restore a BMesh from backup.
+ */
void EDBM_redo_state_restore(struct BMBackup *backup, struct BMEditMesh *em, bool recalc_looptri)
ATTR_NONNULL(1, 2);
+/**
+ * Delete the backup, flushing it to an edit-mesh.
+ */
void EDBM_redo_state_restore_and_free(struct BMBackup *backup,
struct BMEditMesh *em,
bool recalc_looptri) ATTR_NONNULL(1, 2);
void EDBM_redo_state_free(struct BMBackup *backup) ATTR_NONNULL(1);
/* *** meshtools.c *** */
+
int ED_mesh_join_objects_exec(struct bContext *C, struct wmOperator *op);
int ED_mesh_shapes_join_objects_exec(struct bContext *C, struct wmOperator *op);
/* mirror lookup api */
+
/* Spatial Mirror */
void ED_mesh_mirror_spatial_table_begin(struct Object *ob,
struct BMEditMesh *em,
@@ -485,11 +641,19 @@ int ED_mesh_mirror_spatial_table_lookup(struct Object *ob,
const float co[3]);
/* Topology Mirror */
+
+/**
+ * Mode is 's' start, or 'e' end, or 'u' use if end, ob can be NULL.
+ * \note This is supposed return -1 on error,
+ * which callers are currently checking for, but is not used so far.
+ */
void ED_mesh_mirror_topo_table_begin(struct Object *ob, struct Mesh *me_eval);
void ED_mesh_mirror_topo_table_end(struct Object *ob);
-/* Retrieves mirrored cache vert, or NULL if there isn't one.
- * NOTE: calling this without ensuring the mirror cache state is bad. */
+/**
+ * Retrieves mirrored cache vert, or NULL if there isn't one.
+ * \note calling this without ensuring the mirror cache state is bad.
+ */
int mesh_get_x_mirror_vert(struct Object *ob,
struct Mesh *me_eval,
int index,
@@ -500,8 +664,16 @@ struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob,
const float co[3],
int index,
const bool use_topology);
+/**
+ * This is a Mesh-based copy of #mesh_get_x_mirror_faces().
+ */
int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval);
+/**
+ * Wrapper for object-mode/edit-mode.
+ *
+ * call #BM_mesh_elem_table_ensure first for editmesh.
+ */
int ED_mesh_mirror_get_vert(struct Object *ob, int index);
bool ED_mesh_pick_vert(struct bContext *C,
@@ -510,8 +682,18 @@ bool ED_mesh_pick_vert(struct bContext *C,
uint dist_px,
bool use_zbuf,
uint *r_index);
+/**
+ * Face selection in object mode,
+ * currently only weight-paint and vertex-paint use this.
+ *
+ * \return boolean true == Found
+ */
bool ED_mesh_pick_face(
struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, uint *r_index);
+/**
+ * Use when the back buffer stores face index values. but we want a vert.
+ * This gets the face then finds the closest vertex to mval.
+ */
bool ED_mesh_pick_face_vert(
struct bContext *C, struct Object *ob, const int mval[2], uint dist_px, uint *r_index);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index e68617f7867..5bac452c7c9 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -77,6 +77,7 @@ struct bNodeTree *ED_node_tree_get(struct SpaceNode *snode, int level);
void ED_node_set_active_viewer_key(struct SpaceNode *snode);
/* drawnode.c */
+
void ED_node_init_butfuncs(void);
void ED_init_custom_node_type(struct bNodeType *ntype);
void ED_init_custom_node_socket_type(struct bNodeSocketType *stype);
@@ -87,6 +88,12 @@ void ED_node_draw_snap(
struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos);
/* node_draw.cc */
+
+/**
+ * Draw a single node socket at default size.
+ * \note this is only called from external code, internally #node_socket_draw_nested() is used for
+ * optimized drawing of multiple/all sockets of a node.
+ */
void ED_node_socket_draw(struct bNodeSocket *sock,
const struct rcti *rect,
const float color[4],
@@ -94,22 +101,46 @@ void ED_node_socket_draw(struct bNodeSocket *sock,
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
+/**
+ * Sort nodes by selection: unselected nodes first, then selected,
+ * then the active node at the very end. Relative order is kept intact.
+ */
void ED_node_sort(struct bNodeTree *ntree);
float ED_node_grid_size(void);
/* node_relationships.c */
+
+/**
+ * Test == 0, clear all intersect flags.
+ */
void ED_node_link_intersect_test(struct ScrArea *area, int test);
+/**
+ * Assumes link with #NODE_LINKFLAG_HILITE set.
+ */
void ED_node_link_insert(struct Main *bmain, struct ScrArea *area);
/* node_edit.c */
+
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
bool ED_node_is_geometry(struct SpaceNode *snode);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_shader_default(const struct bContext *C, struct ID *id);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
+/**
+ * Assumes nothing being done in ntree yet, sets the default in/out node.
+ * Called from shading buttons or header.
+ */
void ED_node_texture_default(const struct bContext *C, struct Tex *tex);
bool ED_node_select_check(const ListBase *lb);
void ED_node_select_all(ListBase *lb, int action);
@@ -120,19 +151,34 @@ void ED_node_set_active(struct Main *bmain,
struct bNode *node,
bool *r_active_texture_changed);
+/**
+ * \param scene_owner: is the owner of the job,
+ * we don't use it for anything else currently so could also be a void pointer,
+ * but for now keep it an 'Scene' for consistency.
+ *
+ * \note only call from spaces `refresh` callbacks, not direct! - use with care.
+ */
void ED_node_composite_job(const struct bContext *C,
struct bNodeTree *nodetree,
struct Scene *scene_owner);
/* node_ops.c */
+
void ED_operatormacros_node(void);
/* node_view.c */
+/**
+ * Returns mouse position in image space.
+ */
bool ED_space_node_get_position(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
const int mval[2],
float fpos[2]);
+/**
+ * Returns color in linear space, matching #ED_space_image_color_sample().
+ * And here we've got recursion in the comments tips...
+ */
bool ED_space_node_color_sample(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index d5685788ce1..84fa4488374 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -94,8 +94,14 @@ struct UnitSettings;
*/
void initNumInput(NumInput *n);
+/**
+ * \param str: Must be NUM_STR_REP_LEN * (idx_max + 1) length.
+ */
void outputNumInput(NumInput *n, char *str, struct UnitSettings *unit_settings);
bool hasNumInput(const NumInput *n);
+/**
+ * \warning \a vec must be set beforehand otherwise we risk uninitialized vars.
+ */
bool applyNumInput(NumInput *n, float *vec);
bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 2a557f1abd3..576c6f51362 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -56,12 +56,24 @@ struct wmOperator;
struct wmOperatorType;
/* object_edit.c */
-/* context.object */
+
+/** `context.object` */
struct Object *ED_object_context(const struct bContext *C);
-/* context.object or context.active_object */
+/**
+ * Find the correct active object per context (`context.object` or `context.active_object`)
+ * \note context can be NULL when called from a enum with #PROP_ENUM_NO_CONTEXT.
+ */
struct Object *ED_object_active_context(const struct bContext *C);
void ED_collection_hide_menu_draw(const struct bContext *C, struct uiLayout *layout);
+/**
+ * Return an array of objects:
+ * - When in the property space, return the pinned or active object.
+ * - When in edit-mode/pose-mode, return an array of objects in the mode.
+ * - Otherwise return selected objects,
+ * the callers \a filter_fn needs to check of they are editable
+ * (assuming they need to be modified).
+ */
Object **ED_object_array_in_mode_or_selected(struct bContext *C,
bool (*filter_fn)(const struct Object *ob,
void *user_data),
@@ -81,6 +93,10 @@ bool ED_object_calc_active_center(struct Object *ob, const bool select_only, flo
struct XFormObjectData_Container;
struct XFormObjectData_Container *ED_object_data_xform_container_create(void);
void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds);
+/**
+ * This may be called multiple times with the same data.
+ * Each time, the original transformations are re-applied, instead of accumulating the changes.
+ */
void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
struct Main *bmain,
struct Depsgraph *depsgraph);
@@ -130,6 +146,7 @@ void ED_operatormacros_object(void);
void ED_keymap_object(struct wmKeyConfig *keyconf);
/* object_relations.c */
+
typedef enum eParentType {
PAR_OBJECT,
PAR_ARMATURE,
@@ -163,7 +180,9 @@ extern struct EnumPropertyItem prop_clear_parent_types[];
extern struct EnumPropertyItem prop_make_parent_types[];
#endif
-/* Set the object's parent, return true if successful. */
+/**
+ * Set the object's parent, return true if successful.
+ */
bool ED_object_parent_set(struct ReportList *reports,
const struct bContext *C,
struct Scene *scene,
@@ -175,13 +194,35 @@ bool ED_object_parent_set(struct ReportList *reports,
const int vert_par[3]);
void ED_object_parent_clear(struct Object *ob, const int type);
+/**
+ * Simple API for object selection, rather than just using the flag
+ * this takes into account the 'restrict selection in 3d view' flag.
+ * deselect works always, the restriction just prevents selection
+ *
+ * \note Caller must send a `NC_SCENE | ND_OB_SELECT` notifier
+ * (or a `NC_SCENE | ND_OB_VISIBLE` in case of visibility toggling).
+ */
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode);
+/**
+ * Change active base, it includes the notifier
+ */
void ED_object_base_activate(struct bContext *C, struct Base *base);
void ED_object_base_activate_with_mode_exit_if_needed(struct bContext *C, struct Base *base);
+/**
+ * Call when the active base has changed.
+ */
void ED_object_base_active_refresh(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
+/**
+ * Remove base from a specific scene.
+ * \note now unlinks constraints as well.
+ */
void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob);
+/**
+ * Remove base from a specific scene.
+ * `ob` must not be indirectly used.
+ */
void ED_object_base_free_and_unlink_no_indirect_check(struct Main *bmain,
struct Scene *scene,
struct Object *ob);
@@ -191,7 +232,13 @@ bool ED_object_base_deselect_all_ex(struct ViewLayer *view_layer,
bool *r_any_visible);
bool ED_object_base_deselect_all(struct ViewLayer *view_layer, struct View3D *v3d, int action);
-/* single object duplicate, if (dupflag == 0), fully linked, else it uses the flags given */
+/**
+ * Single object duplicate, if `dupflag == 0`, fully linked, else it uses the flags given.
+ * Leaves selection of base/object unaltered.
+ * \note don't call this within a loop since clear_* funcs loop over the entire database.
+ * \note caller must do `DAG_relations_tag_update(bmain);`
+ * this is not done automatic since we may duplicate many objects in a batch.
+ */
struct Base *ED_object_add_duplicate(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -211,12 +258,21 @@ enum {
EM_FREEDATA = (1 << 0),
EM_NO_CONTEXT = (1 << 1),
};
+/**
+ * \param flag:
+ * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly.
+ */
bool ED_object_editmode_exit_ex(struct Main *bmain,
struct Scene *scene,
struct Object *obedit,
int flag);
bool ED_object_editmode_exit(struct bContext *C, int flag);
+/**
+ * Support freeing edit-mode data without flushing it back to the object.
+ *
+ * \return true if data was freed.
+ */
bool ED_object_editmode_free_ex(struct Main *bmain, struct Object *obedit);
bool ED_object_editmode_exit_multi_ex(struct Main *bmain,
@@ -284,6 +340,10 @@ void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char a
void ED_object_base_init_transform_on_add(struct Object *object,
const float loc[3],
const float rot[3]);
+/**
+ * Uses context to figure out transform for primitive.
+ * Returns standard diameter.
+ */
float ED_object_new_primitive_matrix(struct bContext *C,
struct Object *obedit,
const float loc[3],
@@ -291,8 +351,9 @@ float ED_object_new_primitive_matrix(struct bContext *C,
const float scale[3],
float primmat[4][4]);
-/* Avoid allowing too much insane values even by typing
- * (typos can hang/crash Blender otherwise). */
+/**
+ * Avoid allowing too much insane values even by typing (typos can hang/crash Blender otherwise).
+ */
#define OBJECT_ADD_SIZE_MAXF 1.0e12f
void ED_object_add_unit_props_size(struct wmOperatorType *ot);
@@ -310,6 +371,12 @@ bool ED_object_add_generic_get_opts(struct bContext *C,
unsigned short *r_local_view_bits,
bool *r_is_view_aligned);
+/**
+ * For object add primitive operators, or for object creation when `obdata != NULL`.
+ * \param obdata: Assigned to #Object.data, with increased user count.
+ *
+ * \note Do not call undo push in this function (users of this function have to).
+ */
struct Object *ED_object_add_type_with_obdata(struct bContext *C,
const int type,
const char *name,
@@ -327,9 +394,16 @@ struct Object *ED_object_add_type(struct bContext *C,
const unsigned short local_view_bits)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
+/**
+ * Not an especially efficient function, only added so the single user button can be functional.
+ */
void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* object motion paths */
+
+/**
+ * Clear motion paths for all objects.
+ */
void ED_objects_clear_paths(struct bContext *C, bool only_selected);
/* Corresponds to eAnimvizCalcRange. */
@@ -339,6 +413,12 @@ typedef enum eObjectPathCalcRange {
OBJECT_PATH_CALC_RANGE_FULL,
} eObjectPathCalcRange;
+/**
+ * For the objects with animation: update paths for those that have got them
+ * This should selectively update paths that exist.
+ *
+ * To be called from various tools that do incremental updates
+ */
void ED_objects_recalculate_paths(struct bContext *C,
struct Scene *scene,
eObjectPathCalcRange range,
@@ -353,11 +433,26 @@ void ED_objects_recalculate_paths_visible(struct bContext *C,
eObjectPathCalcRange range);
/* constraints */
+/**
+ * If object is in pose-mode, return active bone constraints, else object constraints.
+ * No constraints are returned for a bone on an inactive bone-layer.
+ */
struct ListBase *ED_object_constraint_active_list(struct Object *ob);
+/**
+ * Get the constraints for the active pose bone. Bone may be on an inactive bone-layer
+ * (unlike #ED_object_constraint_active_list, such constraints are not excluded here).
+ */
struct ListBase *ED_object_pose_constraint_list(const struct bContext *C);
+/**
+ * Find the list that a given constraint belongs to,
+ * and/or also get the posechannel this is from (if applicable).
+ */
struct ListBase *ED_object_constraint_list_from_constraint(struct Object *ob,
struct bConstraint *con,
struct bPoseChannel **r_pchan);
+/**
+ * Single constraint.
+ */
struct bConstraint *ED_object_constraint_active_get(struct Object *ob);
void object_test_constraints(struct Main *bmain, struct Object *ob);
@@ -389,7 +484,17 @@ void ED_object_constraint_copy_for_pose(struct Main *bmain,
struct bConstraint *con);
/* object_modes.c */
+
+/**
+ * Checks the mode to be set is compatible with the object
+ * should be made into a generic function
+ */
bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
+/**
+ * Sets the mode to a compatible state (use before entering the mode).
+ *
+ * This is so each mode's exec function can call
+ */
bool ED_object_mode_compat_set(struct bContext *C,
struct Object *ob,
eObjectMode mode,
@@ -412,11 +517,18 @@ void ED_object_posemode_set_for_weight_paint(struct bContext *C,
const bool is_mode_set);
/* object_modifier.c */
+
enum {
MODIFIER_APPLY_DATA = 1,
MODIFIER_APPLY_SHAPE,
};
+/**
+ * Add a modifier to given object, including relevant extra processing needed by some physics types
+ * (particles, simulations...).
+ *
+ * \param scene: is only used to set current frame in some cases, and may be NULL.
+ */
struct ModifierData *ED_object_modifier_add(struct ReportList *reports,
struct Main *bmain,
struct Scene *scene,
@@ -465,12 +577,25 @@ void ED_object_modifier_copy_to_object(struct bContext *C,
struct Object *ob_src,
struct ModifierData *md);
+/**
+ * If the object data of 'orig_ob' has other users, run 'callback' on
+ * each of them.
+ *
+ * If include_orig is true, the callback will run on 'orig_ob' too.
+ *
+ * If the callback ever returns true, iteration will stop and the
+ * function value will be true. Otherwise the function returns false.
+ */
bool ED_object_iter_other(struct Main *bmain,
struct Object *orig_ob,
const bool include_orig,
bool (*callback)(struct Object *ob, void *callback_data),
void *callback_data);
+/**
+ * Use with #ED_object_iter_other(). Sets the total number of levels
+ * for any multi-res modifiers on the object to the int pointed to by callback_data.
+ */
bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v);
/* object_greasepencil_modifier.c */
@@ -546,16 +671,40 @@ void ED_object_check_force_modifiers(struct Main *bmain,
struct Scene *scene,
struct Object *object);
+/**
+ * If id is not already an Object, try to find an object that uses it as data.
+ * Prefers active, then selected, then visible/selectable.
+ */
struct Base *ED_object_find_first_by_data_id(struct ViewLayer *view_layer, struct ID *id);
+/**
+ * Select and make the target object active in the view layer.
+ * If already selected, selection isn't changed.
+ *
+ * \returns false if not found in current view layer
+ */
bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, const bool reveal_hidden);
+/**
+ * Select and make the target object and bone active.
+ * Switches to Pose mode if in Object mode so the selection is visible.
+ * Un-hides the target bone and bone layer if necessary.
+ *
+ * \returns false if object not in layer, bone not found, or other error
+ */
bool ED_object_jump_to_bone(struct bContext *C,
struct Object *ob,
const char *bone_name,
const bool reveal_hidden);
/* object_facemap_ops.c */
+
+/**
+ * Called while not in edit-mode.
+ */
void ED_object_facemap_face_add(struct Object *ob, struct bFaceMap *fmap, int facenum);
+/**
+ * Called while not in edit-mode.
+ */
void ED_object_facemap_face_remove(struct Object *ob, struct bFaceMap *fmap, int facenum);
/* object_data_transform.c */
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index 1d1471f0be6..99f65010595 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -33,10 +33,21 @@ struct bContext;
bool ED_outliner_collections_editor_poll(struct bContext *C);
+/**
+ * Populates the \param objects: ListBase with all the outliner selected objects
+ * We store it as (Object *)LinkData->data
+ * \param objects: expected to be empty
+ */
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
+/**
+ * Get base of object under cursor. Used for eyedropper tool.
+ */
struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
+/**
+ * Functions for tagging outliner selection syncing is dirty from operators.
+ */
void ED_outliner_select_sync_from_object_tag(struct bContext *C);
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C);
void ED_outliner_select_sync_from_pose_bone_tag(struct bContext *C);
@@ -45,9 +56,15 @@ void ED_outliner_select_sync_from_all_tag(struct bContext *C);
bool ED_outliner_select_sync_is_dirty(const struct bContext *C);
+/**
+ * Set clean outliner and mark other outliners for syncing.
+ */
void ED_outliner_select_sync_from_outliner(struct bContext *C,
struct SpaceOutliner *space_outliner);
+/**
+ * Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw.
+ */
void ED_outliner_select_sync_flag_outliners(const struct bContext *C);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index 6a28baa4ca1..1d1ba264de5 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -54,11 +54,21 @@ void ED_imapaint_bucket_fill(struct bContext *C,
const int mouse[2]);
/* paint_image_proj.c */
+
void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil);
+/**
+ * Make sure that active object has a material,
+ * and assign UVs and image layers if they do not exist.
+ */
bool ED_paint_proj_mesh_data_check(
struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil);
/* image_undo.c */
+
+/**
+ * The caller is responsible for running #ED_image_undo_push_end,
+ * failure to do so causes an invalid state for the undo system.
+ */
void ED_image_undo_push_begin(const char *name, int paint_mode);
void ED_image_undo_push_begin_with_image(const char *name,
struct Image *image,
@@ -66,8 +76,12 @@ void ED_image_undo_push_begin_with_image(const char *name,
struct ImageUser *iuser);
void ED_image_undo_push_end(void);
+/**
+ * Restore painting image to previous state. Used for anchored and drag-dot style brushes.
+ */
void ED_image_undo_restore(struct UndoStep *us);
+/** Export for ED_undo_sys. */
void ED_image_undosys_type(struct UndoType *ut);
void *ED_image_paint_tile_find(struct ListBase *paint_tiles,
@@ -100,9 +114,11 @@ struct ListBase *ED_image_paint_tile_list_get(void);
(((size) + ED_IMAGE_UNDO_TILE_SIZE - 1) >> ED_IMAGE_UNDO_TILE_BITS)
/* paint_curve_undo.c */
+
void ED_paintcurve_undo_push_begin(const char *name);
void ED_paintcurve_undo_push_end(struct bContext *C);
+/** Export for ED_undo_sys. */
void ED_paintcurve_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 5318c653b6d..ce25943b40a 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -39,10 +39,12 @@ struct rcti;
struct wmGenericUserData;
/* particle edit mode */
+
void PE_free_ptcache_edit(struct PTCacheEdit *edit);
int PE_start_edit(struct PTCacheEdit *edit);
/* access */
+
struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
struct PTCacheEdit *PE_get_current(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -59,6 +61,7 @@ int PE_minmax(struct Depsgraph *depsgraph,
struct ParticleEditSettings *PE_settings(struct Scene *scene);
/* update calls */
+
void PE_hide_keys_time(struct Scene *scene, struct PTCacheEdit *edit, float cfra);
void PE_update_object(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -66,6 +69,7 @@ void PE_update_object(struct Depsgraph *depsgraph,
int useflag);
/* selection tools */
+
bool PE_mouse_particles(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
@@ -82,6 +86,8 @@ bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit);
bool PE_deselect_all_visible(struct bContext *C);
/* particle_edit_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_particle_undosys_type(struct UndoType *ut);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 5cdcbbab42a..f60d62ed384 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -41,6 +41,7 @@ struct bContext;
struct bScreen;
struct wmWindow;
struct wmWindowManager;
+enum eIconSizes;
/* render_ops.c */
@@ -55,7 +56,14 @@ void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen);
/* Callbacks handling data update events coming from depsgraph. */
void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx, struct ID *id);
+/**
+ * Update all 3D viewport render and draw engines on changes to the scene.
+ * This is called by the dependency graph when it detects changes.
+ */
void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, const bool updated);
+/**
+ * Update 3D viewport render or draw engine on changes to the scene or view settings.
+ */
void ED_render_view3d_update(struct Depsgraph *depsgraph,
struct wmWindow *window,
struct ScrArea *area,
@@ -69,19 +77,22 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
* pr_method:
* - PR_BUTS_RENDER: preview is rendered for buttons window
* - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32
- * - PR_NODE_RENDER: preview is rendered for node editor
* - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
*/
typedef enum ePreviewRenderMethod {
PR_BUTS_RENDER = 0,
PR_ICON_RENDER = 1,
- PR_NODE_RENDER = 2,
- PR_ICON_DEFERRED = 3,
+ PR_ICON_DEFERRED = 2,
} ePreviewRenderMethod;
void ED_preview_ensure_dbase(void);
void ED_preview_free_dbase(void);
+/**
+ * Check if \a id is supported by the automatic preview render.
+ */
+bool ED_preview_id_is_supported(const struct ID *id);
+
void ED_preview_shader_job(const struct bContext *C,
void *owner,
struct ID *id,
@@ -103,6 +114,11 @@ void ED_preview_icon_job(const struct bContext *C,
int sizex,
int sizey,
const bool delay);
+
+void ED_preview_restart_queue_free(void);
+void ED_preview_restart_queue_add(struct ID *id, enum eIconSizes size);
+void ED_preview_restart_queue_work(const struct bContext *C);
+
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain);
void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *slot, rcti *rect);
diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h
index e3abd26a4cd..e4e7a4bdfce 100644
--- a/source/blender/editors/include/ED_scene.h
+++ b/source/blender/editors/include/ED_scene.h
@@ -32,7 +32,14 @@ struct Scene *ED_scene_add(struct Main *bmain,
struct bContext *C,
struct wmWindow *win,
enum eSceneCopyMethod method) ATTR_NONNULL();
+/**
+ * \note Only call outside of area/region loops.
+ * \return true if successful.
+ */
bool ED_scene_delete(struct bContext *C, struct Main *bmain, struct Scene *scene) ATTR_NONNULL();
+/**
+ * Depsgraph updates after scene becomes active in a window.
+ */
void ED_scene_change_update(struct Main *bmain, struct Scene *scene, struct ViewLayer *layer)
ATTR_NONNULL();
bool ED_scene_view_layer_delete(struct Main *bmain,
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index eee119c0712..c65ef3e397d 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -65,33 +65,65 @@ struct wmWindow;
struct wmWindowManager;
/* regions */
+/** Only exported for WM. */
void ED_region_do_listen(struct wmRegionListenerParams *params);
+/** Only exported for WM. */
void ED_region_do_layout(struct bContext *C, struct ARegion *region);
+/** Only exported for WM. */
void ED_region_do_draw(struct bContext *C, struct ARegion *region);
void ED_region_exit(struct bContext *C, struct ARegion *region);
+/**
+ * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
+ * slightly differently, see #ui_region_temp_remove().
+ */
void ED_region_remove(struct bContext *C, struct ScrArea *area, struct ARegion *region);
void ED_region_pixelspace(const struct ARegion *region);
+/**
+ * Call to move a popup window (keep OpenGL context free!)
+ */
void ED_region_update_rect(struct ARegion *region);
+/**
+ * Externally called for floating regions like menus.
+ */
void ED_region_floating_init(struct ARegion *region);
void ED_region_tag_redraw(struct ARegion *region);
void ED_region_tag_redraw_partial(struct ARegion *region, const struct rcti *rct, bool rebuild);
void ED_region_tag_redraw_cursor(struct ARegion *region);
void ED_region_tag_redraw_no_rebuild(struct ARegion *region);
void ED_region_tag_refresh_ui(struct ARegion *region);
+/**
+ * Tag editor overlays to be redrawn. If in doubt about which parts need to be redrawn (partial
+ * clipping rectangle set), redraw everything.
+ */
void ED_region_tag_redraw_editor_overlays(struct ARegion *region);
+/**
+ * Set the temporary update flag for property search.
+ */
void ED_region_search_filter_update(const struct ScrArea *area, struct ARegion *region);
+/**
+ * Returns the search string if the space type and region type support property search.
+ */
const char *ED_area_region_search_filter_get(const struct ScrArea *area,
const struct ARegion *region);
void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *region);
void ED_region_panels_ex(const struct bContext *C, struct ARegion *region, const char *contexts[]);
void ED_region_panels(const struct bContext *C, struct ARegion *region);
+/**
+ * \param contexts: A NULL terminated array of context strings to match against.
+ * Matching against any of these strings will draw the panel.
+ * Can be NULL to skip context checks.
+ */
void ED_region_panels_layout_ex(const struct bContext *C,
struct ARegion *region,
struct ListBase *paneltypes,
const char *contexts[],
const char *category_override);
+/**
+ * Build the same panel list as #ED_region_panels_layout_ex and checks whether any
+ * of the panels contain a search result based on the area / region's search filter.
+ */
bool ED_region_property_search(const struct bContext *C,
struct ARegion *region,
struct ListBase *paneltypes,
@@ -107,11 +139,20 @@ void ED_region_header_layout(const struct bContext *C, struct ARegion *region);
void ED_region_header_draw(const struct bContext *C, struct ARegion *region);
void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *area, struct ARegion *region);
+/**
+ * Exported to all editors, uses fading default.
+ */
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *region);
+/**
+ * For use after changing visibility of regions.
+ */
void ED_region_visibility_change_update(struct bContext *C,
struct ScrArea *area,
struct ARegion *region);
/* screen_ops.c */
+/**
+ * \note Assumes that \a region itself is not a split version from previous region.
+ */
void ED_region_visibility_change_update_animated(struct bContext *C,
struct ScrArea *area,
struct ARegion *region);
@@ -129,6 +170,9 @@ void ED_region_grid_draw(struct ARegion *region, float zoomx, float zoomy, float
float ED_region_blend_alpha(struct ARegion *region);
void ED_region_visible_rect_calc(struct ARegion *region, struct rcti *rect);
const rcti *ED_region_visible_rect(ARegion *region);
+/**
+ * Overlapping regions only in the following restricted cases.
+ */
bool ED_region_is_overlap(int spacetype, int regiontype);
int ED_region_snap_size_test(const struct ARegion *region);
@@ -142,39 +186,76 @@ void ED_area_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
+/**
+ * Follow #ARegionType.message_subscribe.
+ */
void ED_area_do_mgs_subscribe_for_tool_header(const struct wmRegionMessageSubscribeParams *params);
void ED_area_do_mgs_subscribe_for_tool_ui(const struct wmRegionMessageSubscribeParams *params);
/* message bus */
+
+/**
+ * Generate subscriptions for this region.
+ */
void ED_region_message_subscribe(struct wmRegionMessageSubscribeParams *params);
/* spaces */
+
+/**
+ * \note Keymap definitions are registered only once per WM initialize,
+ * usually on file read, using the keymap the actual areas/regions add the handlers.
+ * \note Called in wm.c. */
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
+/**
+ * Returns offset for next button in header.
+ */
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
/* areas */
+/**
+ * Called in screen_refresh, or screens_init, also area size changes.
+ */
void ED_area_init(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *area);
void ED_area_exit(struct bContext *C, struct ScrArea *area);
int ED_screen_area_active(const struct bContext *C);
void ED_screen_global_areas_refresh(struct wmWindow *win);
void ED_screen_global_areas_sync(struct wmWindow *win);
+/** Only exported for WM. */
void ED_area_do_listen(struct wmSpaceTypeListenerParams *params);
void ED_area_tag_redraw(ScrArea *area);
void ED_area_tag_redraw_no_rebuild(ScrArea *area);
void ED_area_tag_redraw_regiontype(ScrArea *area, int type);
void ED_area_tag_refresh(ScrArea *area);
+/**
+ * Only exported for WM.
+ */
void ED_area_do_refresh(struct bContext *C, ScrArea *area);
struct AZone *ED_area_azones_update(ScrArea *area, const int mouse_xy[2]);
+/**
+ * Use NULL to disable it.
+ */
void ED_area_status_text(ScrArea *area, const char *str);
+/**
+ * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
+ */
void ED_area_newspace(struct bContext *C, ScrArea *area, int type, const bool skip_region_exit);
void ED_area_prevspace(struct bContext *C, ScrArea *area);
void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
int ED_area_headersize(void);
int ED_area_footersize(void);
+/**
+ * \return the final height of a global \a area, accounting for DPI.
+ */
int ED_area_global_size_y(const ScrArea *area);
int ED_area_global_min_size_y(const ScrArea *area);
int ED_area_global_max_size_y(const ScrArea *area);
bool ED_area_is_global(const ScrArea *area);
+/**
+ * For now we just assume all global areas are made up out of horizontal bars
+ * with the same size. A fixed size could be stored in ARegion instead if needed.
+ *
+ * \return the DPI aware height of a single bar/region in global areas.
+ */
int ED_region_global_size_y(void);
void ED_area_update_region_sizes(struct wmWindowManager *wm,
struct wmWindow *win,
@@ -204,31 +285,90 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
vert_name->next)
/* screens */
+
+/**
+ * File read, set all screens, ....
+ */
void ED_screens_init(struct Main *bmain, struct wmWindowManager *wm);
+/**
+ * Only for edge lines between areas.
+ */
void ED_screen_draw_edges(struct wmWindow *win);
+
+/**
+ * Make this screen usable.
+ * for file read and first use, for scaling window, area moves.
+ */
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_ensure_updated(struct wmWindowManager *wm,
struct wmWindow *win,
struct bScreen *screen);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
+/**
+ * \brief Change the active screen.
+ *
+ * Operator call, WM + Window + screen already existed before
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if screen changing was successful.
+ */
bool ED_screen_change(struct bContext *C, struct bScreen *screen);
void ED_screen_scene_change(struct bContext *C,
struct wmWindow *win,
struct Scene *scene,
const bool refresh_toolsystem);
+/**
+ * Called in wm_event_system.c. sets state vars in screen, cursors.
+ * event type is mouse move.
+ */
void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2]);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
+/**
+ * redraws: uses defines from `stime->redraws`
+ * \param enable: 1 - forward on, -1 - backwards on, 0 - off.
+ */
void ED_screen_animation_timer(struct bContext *C, int redraws, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws);
void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
+/**
+ * \a was_prev_temp for the case previous space was a temporary full-screen as well
+ */
void ED_screen_full_prevspace(struct bContext *C, ScrArea *area);
+/**
+ * Restore a screen / area back to default operation, after temp full-screen modes.
+ */
void ED_screen_full_restore(struct bContext *C, ScrArea *area);
+/**
+ * Create a new temporary screen with a maximized, empty area.
+ * This can be closed with #ED_screen_state_toggle().
+ *
+ * Use this to just create a new maximized screen/area, rather than maximizing an existing one.
+ * Otherwise, maximize with #ED_screen_state_toggle().
+ */
bScreen *ED_screen_state_maximized_create(struct bContext *C);
+/**
+ * This function toggles: if area is maximized/full then the parent will be restored.
+ *
+ * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to
+ * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a
+ * specific area. In the former case, space data of the maximized and non-maximized area should be
+ * independent, in the latter it should be the same.
+ *
+ * \warning \a area may be freed.
+ */
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *area,
const short state);
+/**
+ * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
+ * by \a display_type.
+ *
+ * \param title: Title to set for the window, if a window is spawned.
+ * \param x, y: Position of the window, if a window is spawned.
+ * \param sizex, sizey: Dimensions of the window, if a window is spawned.
+ */
ScrArea *ED_screen_temp_space_open(struct bContext *C,
const char *title,
int x,
@@ -243,8 +383,15 @@ void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *la
void ED_screens_navigation_bar_tools_menu_create(struct bContext *C,
struct uiLayout *layout,
void *arg);
+/**
+ * \return true if any active area requires to see in 3D.
+ */
bool ED_screen_stereo3d_required(const struct bScreen *screen, const struct Scene *scene);
Scene *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm);
+/**
+ * Find the scene displayed in \a screen.
+ * \note Assumes \a screen to be visible/active!
+ */
Scene *ED_screen_scene_find_with_window(const struct bScreen *screen,
const struct wmWindowManager *wm,
struct wmWindow **r_window);
@@ -253,31 +400,64 @@ ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen,
const bool only_visible);
struct wmWindow *ED_screen_window_find(const struct bScreen *screen,
const struct wmWindowManager *wm);
+/**
+ * Render the preview for a screen layout in \a screen.
+ */
void ED_screen_preview_render(const struct bScreen *screen,
int size_x,
int size_y,
unsigned int *r_rect) ATTR_NONNULL();
/* workspaces */
+
struct WorkSpace *ED_workspace_add(struct Main *bmain, const char *name) ATTR_NONNULL();
+/**
+ * \brief Change the active workspace.
+ *
+ * Operator call, WM + Window + screen already existed before
+ * Pretty similar to #ED_screen_change since changing workspace also changes screen.
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if workspace changing was successful.
+ */
bool ED_workspace_change(struct WorkSpace *workspace_new,
struct bContext *C,
struct wmWindowManager *wm,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * Duplicate a workspace including its layouts. Does not activate the workspace, but
+ * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
+ */
struct WorkSpace *ED_workspace_duplicate(struct WorkSpace *workspace_old,
struct Main *bmain,
struct wmWindow *win);
+/**
+ * \return if succeeded.
+ */
bool ED_workspace_delete(struct WorkSpace *workspace,
struct Main *bmain,
struct bContext *C,
struct wmWindowManager *wm) ATTR_NONNULL();
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors in active layout of \a workspace.
+ */
void ED_workspace_scene_data_sync(struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL();
+/**
+ * Make sure there is a non-full-screen layout to switch to that isn't used yet by an other window.
+ * Needed for workspace or screen switching to ensure valid screens.
+ *
+ * \param layout_fallback_base: As last resort, this layout is duplicated and returned.
+ */
struct WorkSpaceLayout *ED_workspace_screen_change_ensure_unused_layout(
struct Main *bmain,
struct WorkSpace *workspace,
struct WorkSpaceLayout *layout_new,
const struct WorkSpaceLayout *layout_fallback_base,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * Empty screen, with 1 dummy area without space-data. Uses window size.
+ */
struct WorkSpaceLayout *ED_workspace_layout_add(struct Main *bmain,
struct WorkSpace *workspace,
struct wmWindow *win,
@@ -286,6 +466,10 @@ struct WorkSpaceLayout *ED_workspace_layout_duplicate(struct Main *bmain,
struct WorkSpace *workspace,
const struct WorkSpaceLayout *layout_old,
struct wmWindow *win) ATTR_NONNULL();
+/**
+ * \warning Only call outside of area/region loops!
+ * \return true if succeeded.
+ */
bool ED_workspace_layout_delete(struct WorkSpace *workspace,
struct WorkSpaceLayout *layout_old,
struct bContext *C) ATTR_NONNULL();
@@ -296,22 +480,42 @@ bool ED_workspace_layout_cycle(struct WorkSpace *workspace,
void ED_workspace_status_text(struct bContext *C, const char *str);
/* anim */
+/**
+ * Results in fully updated anim system.
+ */
void ED_update_for_newframe(struct Main *bmain, struct Depsgraph *depsgraph);
+/**
+ * Update frame rate info for viewport drawing.
+ */
void ED_refresh_viewport_fps(struct bContext *C);
+/**
+ * Toggle operator.
+ */
int ED_screen_animation_play(struct bContext *C, int sync, int mode);
+/**
+ * Find window that owns the animation timer.
+ */
bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm);
bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/* screen keymaps */
+/* called in spacetypes.c */
void ED_operatortypes_screen(void);
+/* called in spacetypes.c */
void ED_keymap_screen(struct wmKeyConfig *keyconf);
-/* workspace keymaps */
+/**
+ * Workspace key-maps.
+ */
void ED_operatortypes_workspace(void);
/* operators; context poll callbacks */
+
bool ED_operator_screenactive(struct bContext *C);
bool ED_operator_screenactive_nobackground(struct bContext *C);
+/**
+ * When mouse is over area-edge.
+ */
bool ED_operator_screen_mainwinactive(struct bContext *C);
bool ED_operator_areaactive(struct bContext *C);
bool ED_operator_regionactive(struct bContext *C);
@@ -319,14 +523,31 @@ bool ED_operator_regionactive(struct bContext *C);
bool ED_operator_scene(struct bContext *C);
bool ED_operator_scene_editable(struct bContext *C);
bool ED_operator_objectmode(struct bContext *C);
+/**
+ * Same as #ED_operator_objectmode() but additionally sets a "disabled hint". That is, a message
+ * to be displayed to the user explaining why the operator can't be used in current context.
+ */
bool ED_operator_objectmode_poll_msg(struct bContext *C);
bool ED_operator_view3d_active(struct bContext *C);
bool ED_operator_region_view3d_active(struct bContext *C);
+/**
+ * Generic for any view2d which uses anim_ops.
+ */
bool ED_operator_animview_active(struct bContext *C);
bool ED_operator_outliner_active(struct bContext *C);
bool ED_operator_outliner_active_no_editobject(struct bContext *C);
+/**
+ * \note Will return true for file spaces in either file or asset browsing mode! See
+ * #ED_operator_file_browsing_active() (file browsing only) and
+ * #ED_operator_asset_browsing_active() (asset browsing only).
+ */
bool ED_operator_file_active(struct bContext *C);
+/**
+ * \note Will only return true if the file space is in file browsing mode, not asset browsing! See
+ * #ED_operator_file_active() (file or asset browsing) and
+ * #ED_operator_asset_browsing_active() (asset browsing only).
+ */
bool ED_operator_file_browsing_active(struct bContext *C);
bool ED_operator_asset_browsing_active(struct bContext *C);
bool ED_operator_spreadsheet_active(struct bContext *C);
@@ -345,6 +566,9 @@ bool ED_operator_console_active(struct bContext *C);
bool ED_operator_object_active(struct bContext *C);
bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_editable(struct bContext *C);
+/**
+ * Object must be editable and fully local (i.e. not an override).
+ */
bool ED_operator_object_active_local_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_local_editable(struct bContext *C);
bool ED_operator_object_active_editable_mesh(struct bContext *C);
@@ -363,11 +587,21 @@ bool ED_operator_editsurfcurve_region_view3d(struct bContext *C);
bool ED_operator_editfont(struct bContext *C);
bool ED_operator_editlattice(struct bContext *C);
bool ED_operator_editmball(struct bContext *C);
+/**
+ * Wrapper for #ED_space_image_show_uvedit.
+ */
bool ED_operator_uvedit(struct bContext *C);
bool ED_operator_uvedit_space_image(struct bContext *C);
bool ED_operator_uvmap(struct bContext *C);
bool ED_operator_posemode_exclusive(struct bContext *C);
+/**
+ * Object must be editable, fully local (i.e. not an override), and exclusively in Pose mode.
+ */
bool ED_operator_object_active_local_editable_posemode_exclusive(struct bContext *C);
+/**
+ * Allows for pinned pose objects to be used in the object buttons
+ * and the non-active pose object to be used in the 3D view.
+ */
bool ED_operator_posemode_context(struct bContext *C);
bool ED_operator_posemode(struct bContext *C);
bool ED_operator_posemode_local(struct bContext *C);
@@ -418,8 +652,15 @@ void ED_region_cache_draw_cached_segments(struct ARegion *region,
const int efra);
/* area_utils.c */
+
+/**
+ * Callback for #ARegionType.message_subscribe
+ */
void ED_region_generic_tools_region_message_subscribe(
const struct wmRegionMessageSubscribeParams *params);
+/**
+ * Callback for #ARegionType.snap_size
+ */
int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis);
/* area_query.c */
@@ -440,15 +681,29 @@ bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter);
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]);
+/**
+ * \note: This may return true for multiple overlapping regions.
+ * If it matters, check overlapped regions first (#ARegion.overlap).
+ */
bool ED_region_contains_xy(const struct ARegion *region, const int event_xy[2]);
+/**
+ * Similar to #BKE_area_find_region_xy() but when \a event_xy intersects an overlapping region,
+ * this returns the region that is visually under the cursor. E.g. when over the
+ * transparent part of the region, it returns the region underneath.
+ *
+ * The overlapping region is determined using the #ED_region_contains_xy() query.
+ */
ARegion *ED_area_find_region_xy_visual(const ScrArea *area, int regiontype, const int event_xy[2]);
/* interface_region_hud.c */
+
struct ARegionType *ED_area_type_hud(int space_type);
void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *area_keep);
void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *area);
-/* default keymaps, bitflags (matches order of evaluation). */
+/**
+ * Default key-maps, bit-flags (matches order of evaluation).
+ */
enum {
ED_KEYMAP_UI = (1 << 1),
ED_KEYMAP_GIZMO = (1 << 2),
@@ -462,7 +717,7 @@ enum {
ED_KEYMAP_NAVBAR = (1 << 11),
};
-/* SCREEN_OT_space_context_cycle direction */
+/** #SCREEN_OT_space_context_cycle direction. */
typedef enum eScreenCycle {
SPACE_CONTEXT_CYCLE_PREV,
SPACE_CONTEXT_CYCLE_NEXT,
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 348ea503372..0cdd8873cb2 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -35,6 +35,7 @@ struct bContext;
struct rcti;
/* sculpt.c */
+
void ED_operatortypes_sculpt(void);
void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *region, struct Object *ob);
bool ED_sculpt_mask_box_select(struct bContext *C,
@@ -42,18 +43,22 @@ bool ED_sculpt_mask_box_select(struct bContext *C,
const struct rcti *rect,
bool select);
-/* transform */
+/* sculpt_transform.c */
+
void ED_sculpt_update_modal_transform(struct bContext *C, struct Object *ob);
void ED_sculpt_init_transform(struct bContext *C, struct Object *ob);
void ED_sculpt_end_transform(struct bContext *C, struct Object *ob);
/* sculpt_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_sculpt_undosys_type(struct UndoType *ut);
void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name);
void ED_sculpt_undo_geometry_end(struct Object *ob);
/* Face sets. */
+
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh);
void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, const int new_id);
@@ -62,7 +67,7 @@ int ED_sculpt_face_sets_active_update_and_get(struct bContext *C,
const float mval[2]);
/* Undo for changes happening on a base mesh for multires sculpting.
- * if there is no multires sculpt active regular undo is used. */
+ * if there is no multi-res sculpt active regular undo is used. */
void ED_sculpt_undo_push_multires_mesh_begin(struct bContext *C, const char *str);
void ED_sculpt_undo_push_multires_mesh_end(struct bContext *C, const char *str);
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index 049ea7a092f..4656099799b 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -60,8 +60,17 @@ enum {
#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET))
#define SEL_OP_CAN_DESELECT(sel_op) (!ELEM(sel_op, SEL_OP_ADD))
-/* Use when we've de-selected all first for 'SEL_OP_SET' */
+/**
+ * Use when we've de-selected all first for 'SEL_OP_SET'.
+ * 1: select, 0: deselect, -1: pass.
+ */
int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside);
+/**
+ * Use when we've de-selected all items first (for modes that need it).
+ *
+ * \note In some cases changing selection needs to perform other checks,
+ * so it's more straightforward to deselect all, then select.
+ */
int ED_select_op_action_deselected(const eSelectOp sel_op,
const bool is_select,
const bool is_inside);
@@ -72,6 +81,9 @@ bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
const float thresh,
const int compare);
+/**
+ * Utility to use for selection operations that run multiple times (circle select).
+ */
eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_sequencer.h b/source/blender/editors/include/ED_sequencer.h
index 606b4c9cad0..843b94cea00 100644
--- a/source/blender/editors/include/ED_sequencer.h
+++ b/source/blender/editors/include/ED_sequencer.h
@@ -40,8 +40,18 @@ bool ED_space_sequencer_maskedit_mask_poll(struct bContext *C);
bool ED_space_sequencer_check_show_maskedit(struct SpaceSeq *sseq, struct Scene *scene);
bool ED_space_sequencer_maskedit_poll(struct bContext *C);
+/**
+ * Are we displaying the seq output (not channels or histogram).
+ */
bool ED_space_sequencer_check_show_imbuf(struct SpaceSeq *sseq);
+
bool ED_space_sequencer_check_show_strip(struct SpaceSeq *sseq);
+/**
+ * Check if there is animation shown during playback.
+ *
+ * - Colors of color strips are displayed on the strip itself.
+ * - Backdrop is drawn.
+ */
bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
const struct Scene *scene);
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index 958df8f7707..f4a69737da1 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -30,12 +30,18 @@ extern "C" {
struct ARegionType;
struct bContext;
+/* Only called once on startup. storage is global in BKE kernel listbase. */
void ED_spacetypes_init(void);
void ED_spacemacros_init(void);
/* the pluginnable API for export to editors */
-/* calls for registering default spaces */
+/* -------------------------------------------------------------------- */
+/** \name Calls for registering default spaces
+ *
+ * Calls for registering default spaces, only called once, from #ED_spacetypes_init
+ * \{ */
+
void ED_spacetype_outliner(void);
void ED_spacetype_view3d(void);
void ED_spacetype_ipo(void);
@@ -57,12 +63,18 @@ void ED_spacetype_statusbar(void);
void ED_spacetype_topbar(void);
void ED_spacetype_spreadsheet(void);
-/* calls for instancing and freeing spacetype static data
- * called in WM_init_exit */
-/* in space_file.c */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Spacetype Static Data
+ * Calls for instancing and freeing space-type static data called in #WM_init_exit
+ * \{ */
+
void ED_file_init(void);
void ED_file_exit(void);
+/** \} */
+
#define REGION_DRAW_POST_VIEW 0
#define REGION_DRAW_POST_PIXEL 1
#define REGION_DRAW_PRE_VIEW 2
diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h
index 6e012ec1a91..33ca3ea03a6 100644
--- a/source/blender/editors/include/ED_text.h
+++ b/source/blender/editors/include/ED_text.h
@@ -36,16 +36,25 @@ struct bContext;
bool ED_text_activate_in_screen(struct bContext *C, struct Text *text);
+/**
+ * Moves the view to the cursor location, also used to make sure the view isn't outside the file.
+ */
void ED_text_scroll_to_cursor(struct SpaceText *st, struct ARegion *region, bool center);
+/**
+ * Takes a cursor (row, character) and returns x,y pixel coords.
+ */
bool ED_text_region_location_from_cursor(struct SpaceText *st,
struct ARegion *region,
const int cursor_co[2],
int r_pixel_co[2]);
/* text_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_text_undosys_type(struct UndoType *ut);
+/** Use operator system to finish the undo step. */
struct UndoStep *ED_text_undo_push_init(struct bContext *C);
/* text_format.c */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index b132e559baa..f0d6072fdbc 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -146,6 +146,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags);
/* *** transform_orientations.c *** */
void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]);
+/**
+ * \note The resulting matrix may not be orthogonal,
+ * callers that depend on `r_mat` to be orthogonal should use #orthogonalize_m3.
+ *
+ * A non orthogonal matrix may be returned when:
+ * - #V3D_ORIENT_GIMBAL the result won't be orthogonal unless the object has no rotation.
+ * - #V3D_ORIENT_LOCAL may contain shear from non-uniform scale in parent/child relationships.
+ * - #V3D_ORIENT_CUSTOM may have been created from #V3D_ORIENT_LOCAL.
+ */
short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d,
@@ -159,6 +168,9 @@ short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene,
/* transform gizmos */
void VIEW3D_GGT_xform_gizmo(struct wmGizmoGroupType *gzgt);
+/**
+ * Only poll, flag & gzmap_params differ.
+ */
void VIEW3D_GGT_xform_gizmo_context(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_xform_cage(struct wmGizmoGroupType *gzgt);
void VIEW3D_GGT_xform_shear(struct wmGizmoGroupType *gzgt);
@@ -196,6 +208,11 @@ struct TransformCalcParams {
/* Use 'Scene.orientation_type' when zero, otherwise subtract one and use. */
ushort orientation_index;
};
+/**
+ * Centroid, bound-box, of selection.
+ *
+ * Returns total items selected.
+ */
int ED_transform_calc_gizmo_stats(const struct bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds);
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index c4da1588117..6f25a63188d 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -117,6 +117,13 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
float r_co[3],
float r_no[3]);
+/**
+ * Fill in a list of all hits.
+ *
+ * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
+ * \param sort: Optionally sort the hits by depth.
+ * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
+ */
bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const View3D *v3d,
@@ -142,6 +149,19 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
struct Object **r_ob,
float r_obmat[4][4],
float r_face_nor[3]);
+/**
+ * Convenience function for performing snapping.
+ *
+ * Given a 2D region value, snap to vert/edge/face.
+ *
+ * \param sctx: Snap context.
+ * \param mval: Screenspace coordinate.
+ * \param prev_co: Coordinate for perpendicular point calculation (optional).
+ * \param dist_px: Maximum distance to snap (in pixels).
+ * \param r_loc: hit location.
+ * \param r_no: hit normal (optional).
+ * \return Snap success.
+ */
short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
@@ -155,6 +175,9 @@ short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
float r_loc[3],
float r_no[3]);
+/**
+ * see: #ED_transform_snap_object_project_ray_all
+ */
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h
index 059277e1466..dceecc6aab5 100644
--- a/source/blender/editors/include/ED_undo.h
+++ b/source/blender/editors/include/ED_undo.h
@@ -36,6 +36,9 @@ struct wmOperator;
struct wmOperatorType;
/* undo.c */
+/**
+ * Run from the main event loop, basic checks that undo is left in a correct state.
+ */
bool ED_undo_is_state_valid(struct bContext *C);
void ED_undo_group_begin(struct bContext *C);
void ED_undo_group_end(struct bContext *C);
@@ -52,18 +55,38 @@ void ED_OT_redo(struct wmOperatorType *ot);
void ED_OT_undo_redo(struct wmOperatorType *ot);
void ED_OT_undo_history(struct wmOperatorType *ot);
+/**
+ * UI callbacks should call this rather than calling WM_operator_repeat() themselves.
+ */
int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
-/* Convenience since UI callbacks use this mostly. */
+/**
+ * Convenience since UI callbacks use this mostly.
+ */
void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused);
void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused);
+/**
+ * Name optionally, function used to check for operator redo panel.
+ */
bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
bool ED_undo_is_memfile_compatible(const struct bContext *C);
/* Unfortunate workaround for limits mixing undo systems. */
+
+/**
+ * When a property of ID changes, return false.
+ *
+ * This is to avoid changes to a property making undo pushes
+ * which are ignored by the undo-system.
+ * For example, changing a brush property isn't stored by sculpt-mode undo steps.
+ * This workaround is needed until the limitation is removed, see: T61948.
+ */
bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, struct ID *id);
+/**
+ * Load all our objects from `object_array` into edit-mode, clear everything else.
+ */
void ED_undo_object_editmode_restore_helper(struct bContext *C,
struct Object **object_array,
uint object_array_len,
@@ -73,6 +96,13 @@ struct Object **ED_undo_editmode_objects_from_view_layer(struct ViewLayer *view_
uint *r_len);
struct Base **ED_undo_editmode_bases_from_view_layer(struct ViewLayer *view_layer, uint *r_len);
+/**
+ * Ideally we won't access the stack directly,
+ * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
+ *
+ * Using global isn't great, this just avoids doing inline,
+ * causing 'BKE_global.h' & 'BKE_main.h' includes.
+ */
struct UndoStack *ED_undo_stack_get(void);
/* helpers */
@@ -83,11 +113,28 @@ void ED_undo_object_set_active_or_warn(struct Scene *scene,
struct CLG_LogRef *log);
/* undo_system_types.c */
+
void ED_undosys_type_init(void);
void ED_undosys_type_free(void);
/* memfile_undo.c */
+
struct MemFile *ED_undosys_stack_memfile_get_active(struct UndoStack *ustack);
+/**
+ * If the last undo step is a memfile one, find the first #MemFileChunk matching given ID
+ * (using its session UUID), and tag it as "changed in the future".
+ *
+ * Since non-memfile undo-steps cannot automatically set this flag in the previous step as done
+ * with memfile ones, this has to be called manually by relevant undo code.
+ *
+ * \note Only current known case for this is undoing a switch from Object to Sculpt mode (see
+ * T82388).
+ *
+ * \note Calling this ID by ID is not optimal, as it will loop over all #MemFile.chunks until it
+ * finds the expected one. If this becomes an issue we'll have to add a mapping from session UUID
+ * to first #MemFileChunk in #MemFile itself
+ * (currently we only do that in #MemFileWriteData when writing a new step).
+ */
void ED_undosys_stack_memfile_id_changed_tag(struct UndoStack *ustack, struct ID *id);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index df132e6ae80..69378d436ab 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -35,8 +35,12 @@ struct Main;
struct bContext;
/* ed_util.c */
+
void ED_editors_init_for_undo(struct Main *bmain);
void ED_editors_init(struct bContext *C);
+/**
+ * Frees all edit-mode stuff.
+ */
void ED_editors_exit(struct Main *bmain, bool do_undo_system);
bool ED_editors_flush_edits_for_object_ex(struct Main *bmain,
@@ -45,9 +49,17 @@ bool ED_editors_flush_edits_for_object_ex(struct Main *bmain,
bool check_needs_flush);
bool ED_editors_flush_edits_for_object(struct Main *bmain, struct Object *ob);
+/**
+ * Flush any temp data from object editing to DNA before writing files, rendering, copying, etc.
+ */
bool ED_editors_flush_edits_ex(struct Main *bmain, bool for_render, bool check_needs_flush);
bool ED_editors_flush_edits(struct Main *bmain);
+/**
+ * Use to free ID references within runtime data (stored outside of DNA)
+ *
+ * \param new_id: may be NULL to unlink \a old_id.
+ */
void ED_spacedata_id_remap(struct ScrArea *area,
struct SpaceLink *sl,
struct ID *old_id,
@@ -56,21 +68,38 @@ void ED_spacedata_id_remap(struct ScrArea *area,
void ED_operatortypes_edutils(void);
/* Drawing */
+
+/**
+ * Callback that draws a line between the mouse and a position given as the initial argument.
+ */
void ED_region_draw_mouse_line_cb(const struct bContext *C,
struct ARegion *region,
void *arg_info);
+/**
+ * \note Keep in sync with #BKE_image_stamp_buf.
+ */
void ED_region_image_metadata_draw(
int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
/* Slider */
+
struct tSlider;
struct tSlider *ED_slider_create(struct bContext *C);
+/**
+ * For modal operations so the percentage doesn't pop on the first mouse movement.
+ */
void ED_slider_init(struct tSlider *slider, const struct wmEvent *event);
+/**
+ * Calculate slider factor based on mouse position.
+ */
bool ED_slider_modal(struct tSlider *slider, const struct wmEvent *event);
void ED_slider_destroy(struct bContext *C, struct tSlider *slider);
+/**
+ * Return string based on the current state of the slider.
+ */
void ED_slider_status_string_get(const struct tSlider *slider,
char *status_string,
const size_t size_of_status_string);
@@ -83,6 +112,11 @@ void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value);
/* ************** XXX OLD CRUFT WARNING ************* */
+/**
+ * Now only used in 2D spaces, like time, f-curve, NLA, image, etc.
+ *
+ * \note Shift/Control are not configurable key-bindings.
+ */
void apply_keyb_grid(
int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert);
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 884124396b9..e7b3c191d36 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -46,6 +46,7 @@ struct bNodeTree;
struct wmKeyConfig;
/* uvedit_ops.c */
+
void ED_operatortypes_uvedit(void);
void ED_operatormacros_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
@@ -54,6 +55,9 @@ bool ED_uvedit_minmax(const struct Scene *scene,
struct Object *obedit,
float min[2],
float max[2]);
+/**
+ * Be careful when using this, it bypasses all synchronization options.
+ */
void ED_uvedit_select_all(struct BMesh *bm);
bool ED_uvedit_minmax_multi(const struct Scene *scene,
@@ -231,12 +235,17 @@ struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm);
void ED_uvedit_active_edge_loop_set(struct BMesh *bm, struct BMLoop *l);
struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm);
+/**
+ * Intentionally don't return #UV_SELECT_ISLAND as it's not an element type.
+ * In this case return #UV_SELECT_VERTEX as a fallback.
+ */
char ED_uvedit_select_mode_get(const struct Scene *scene);
void ED_uvedit_select_sync_flush(const struct ToolSettings *ts,
struct BMEditMesh *em,
const bool select);
/* uvedit_unwrap_ops.c */
+
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit);
void ED_uvedit_live_unwrap_re_solve(void);
void ED_uvedit_live_unwrap_end(short cancel);
@@ -245,9 +254,11 @@ void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, i
void ED_uvedit_add_simple_uvs(struct Main *bmain, const struct Scene *scene, struct Object *ob);
/* uvedit_draw.c */
+
void ED_image_draw_cursor(struct ARegion *region, const float cursor[2]);
/* uvedit_buttons.c */
+
void ED_uvedit_buttons_register(struct ARegionType *art);
/* uvedit_islands.c */
@@ -273,6 +284,9 @@ struct UVPackIsland_Params {
uint correct_aspect : 1;
};
+/**
+ * Returns true if UV coordinates lie on a valid tile in UDIM grid or tiled image.
+ */
bool uv_coords_isect_udim(const struct Image *image,
const int udim_grid[2],
const float coords[2]);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 008ad5b3203..6c986d8efe1 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -107,6 +107,11 @@ void ED_view3d_background_color_get(const struct Scene *scene,
bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene,
const struct Object *ob,
const struct View3D *v3d);
+/**
+ * Cursor position in `r_cursor_co`, result in `r_cursor_co`, `mval` in region coords.
+ *
+ * \note cannot use `event->mval` here, called by #object_add().
+ */
void ED_view3d_cursor3d_position(struct bContext *C,
const int mval[2],
const bool use_depth,
@@ -124,11 +129,44 @@ void ED_view3d_cursor3d_update(struct bContext *C,
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
+/**
+ * Calculate the view transformation matrix from RegionView3D input.
+ * The resulting matrix is equivalent to #RegionView3D.viewinv
+ * \param mat: The view 4x4 transformation matrix to calculate.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from ofs, normally from #RegionView3D.dist.
+ */
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist);
+/**
+ * Set the view transformation from a 4x4 matrix.
+ *
+ * \param mat: The view 4x4 transformation matrix to assign.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs`, normally from #RegionView3D.dist.
+ */
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist);
+/**
+ * Set the #RegionView3D members from an objects transformation and optionally lens.
+ * \param ob: The object to set the view to.
+ * \param ofs: The view offset to be set, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation to be set, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs `to be set, normally from #RegionView3D.dist.
+ * \param lens: The view lens angle set for cameras and lights, normally from View3D.lens.
+ */
void ED_view3d_from_object(
const struct Object *ob, float ofs[3], float quat[4], float *dist, float *lens);
+/**
+ * Set the object transformation from #RegionView3D members.
+ * \param depsgraph: The depsgraph to get the evaluated object parent
+ * for the transformation calculation.
+ * \param ob: The object which has the transformation assigned.
+ * \param ofs: The view offset, normally from #RegionView3D.ofs.
+ * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat.
+ * \param dist: The view distance from `ofs`, normally from #RegionView3D.dist.
+ */
void ED_view3d_to_object(const struct Depsgraph *depsgraph,
struct Object *ob,
const float ofs[3],
@@ -140,14 +178,24 @@ bool ED_view3d_camera_to_view_selected(struct Main *bmain,
const struct Scene *scene,
struct Object *camera_ob);
+/**
+ * Use to store the last view, before entering camera view.
+ */
void ED_view3d_lastview_store(struct RegionView3D *rv3d);
/* Depth buffer */
typedef enum {
+ /** Redraw viewport without Grease Pencil and Annotations. */
V3D_DEPTH_NO_GPENCIL = 0,
+ /** Redraw viewport with Grease Pencil and Annotations only. */
V3D_DEPTH_GPENCIL_ONLY,
+ /** Redraw viewport with active object only. */
V3D_DEPTH_OBJECT_ONLY,
+
} eV3DDepthOverrideMode;
+/**
+ * Redraw the viewport depth buffer.
+ */
void ED_view3d_depth_override(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -309,6 +357,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
/* view3d_iterators.c */
/* foreach iterators */
+
void meshobject_foreachScreenVert(
struct ViewContext *vc,
void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index),
@@ -328,6 +377,10 @@ void mesh_foreachScreenEdge(struct ViewContext *vc,
void *userData,
const eV3DProjTest clip_flag);
+/**
+ * A version of #mesh_foreachScreenEdge that clips the segment when
+ * there is a clipping bounding box.
+ */
void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc,
void (*func)(void *userData,
struct BMEdge *eed,
@@ -352,6 +405,9 @@ void nurbs_foreachScreenVert(struct ViewContext *vc,
const float screen_co[2]),
void *userData,
const eV3DProjTest clip_flag);
+/**
+ * #ED_view3d_init_mats_rv3d must be called first.
+ */
void mball_foreachScreenElem(struct ViewContext *vc,
void (*func)(void *userData,
struct MetaElem *ml,
@@ -364,6 +420,9 @@ void lattice_foreachScreenVert(struct ViewContext *vc,
const float screen_co[2]),
void *userData,
const eV3DProjTest clip_flag);
+/**
+ * #ED_view3d_init_mats_rv3d must be called first.
+ */
void armature_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct EditBone *ebone,
@@ -371,6 +430,10 @@ void armature_foreachScreenBone(struct ViewContext *vc,
const float screen_co_b[2]),
void *userData,
const eV3DProjTest clip_flag);
+
+/**
+ * ED_view3d_init_mats_rv3d must be called first.
+ */
void pose_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct bPoseChannel *pchan,
@@ -381,10 +444,17 @@ void pose_foreachScreenBone(struct ViewContext *vc,
/* *** end iterators *** */
/* view3d_project.c */
+
+/**
+ * \note use #ED_view3d_ob_project_mat_get to get the projection matrix
+ */
void ED_view3d_project_float_v2_m4(const struct ARegion *region,
const float co[3],
float r_co[2],
float mat[4][4]);
+/**
+ * \note use #ED_view3d_ob_project_mat_get to get projecting mat
+ */
void ED_view3d_project_float_v3_m4(const struct ARegion *region,
const float co[3],
float r_co[3],
@@ -399,10 +469,12 @@ eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *region,
const float co[3],
short r_co[2],
const eV3DProjTest flag);
+/* --- short --- */
eV3DProjStatus ED_view3d_project_short_global(const struct ARegion *region,
const float co[3],
short r_co[2],
const eV3DProjTest flag);
+/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_short_object(const struct ARegion *region,
const float co[3],
short r_co[2],
@@ -415,10 +487,12 @@ eV3DProjStatus ED_view3d_project_int_ex(const struct ARegion *region,
const float co[3],
int r_co[2],
const eV3DProjTest flag);
+/* --- int --- */
eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region,
const float co[3],
int r_co[2],
const eV3DProjTest flag);
+/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_int_object(const struct ARegion *region,
const float co[3],
int r_co[2],
@@ -431,10 +505,14 @@ eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *region,
const float co[3],
float r_co[2],
const eV3DProjTest flag);
+/* --- float --- */
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region,
const float co[3],
float r_co[2],
const eV3DProjTest flag);
+/**
+ * Object space, use #ED_view3d_init_mats_rv3d before calling.
+ */
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region,
const float co[3],
float r_co[2],
@@ -443,17 +521,52 @@ eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region,
float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
float ED_view3d_pixel_size_no_ui_scale(const struct RegionView3D *rv3d, const float co[3]);
+/**
+ * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
+ */
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
+/**
+ * Calculate a depth value from `co` (result should only be used for comparison).
+ */
float ED_view3d_calc_depth_for_comparison(const struct RegionView3D *rv3d, const float co[3]);
bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
+ * ray_start is clipped by the view near limit so points in front of it are always in view.
+ * In orthographic view the resulting ray_normal will match the view vector.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near clipping value).
+ * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
+ * \param r_ray_start: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
+ * \return success, false if the ray is totally clipped.
+ */
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
const struct ARegion *region,
const struct View3D *v3d,
const float mval[2],
- float ray_start[3],
- float ray_normal[3],
- const bool do_clip);
+ float r_ray_start[3],
+ float r_ray_normal[3],
+ const bool do_clip_planes);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards `mval`.
+ * ray_start is clipped by the view near limit so points in front of it are always in view.
+ * In orthographic view the resulting ray_normal will match the view vector.
+ * This version also returns the ray_co point of the ray on window plane, useful to fix precision
+ * issues especially with orthographic view, where default ray_start is set rather far away.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near clipping value).
+ * \param mval: The area relative 2d location (such as `event->mval`, converted into float[2]).
+ * \param r_ray_co: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ * \param r_ray_start: The world-space starting point of the ray.
+ * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
+ * \return success, false if the ray is totally clipped.
+ */
bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
const struct ARegion *region,
const struct View3D *v3d,
@@ -461,14 +574,39 @@ bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
float r_ray_co[3],
float r_ray_normal[3],
float r_ray_start[3],
- bool do_clip);
+ bool do_clip_planes);
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards `mval`.
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as `event->mval`, converted into float[2]).
+ * \param r_ray_start: The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal: The normalized world-space direction of towards mval.
+ *
+ * \note Ignores view near/far clipping,
+ * to take this into account use #ED_view3d_win_to_ray_clipped.
+ */
void ED_view3d_win_to_ray(const struct ARegion *region,
const float mval[2],
float r_ray_start[3],
float r_ray_normal[3]);
+/**
+ * Calculate a normalized 3d direction vector from the viewpoint towards a global location.
+ * In orthographic view the resulting vector will match the view vector.
+ * \param rv3d: The region (used for the window width and height).
+ * \param coord: The world-space location.
+ * \param vec: The resulting normalized vector.
+ */
void ED_view3d_global_to_vector(const struct RegionView3D *rv3d,
const float coord[3],
float vec[3]);
+/**
+ * Calculate a 3d location from 2d window coordinates.
+ * \param region: The region (used for the window width and height).
+ * \param depth_pt: The reference location used to calculate the Z depth.
+ * \param mval: The area relative location (such as `event->mval` converted to floats).
+ * \param r_out: The resulting world-space location.
+ */
void ED_view3d_win_to_3d(const struct View3D *v3d,
const struct ARegion *region,
const float depth_pt[3],
@@ -484,6 +622,13 @@ bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region,
const float mval[2],
const bool do_clip,
float r_out[3]);
+/**
+ * A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback
+ * then maps this back to \a plane.
+ *
+ * This is intended to be used when \a plane is orthogonal to the views Z axis where
+ * projecting the \a mval doesn't work well (or fail completely when exactly aligned).
+ */
bool ED_view3d_win_to_3d_on_plane_with_fallback(const struct ARegion *region,
const float plane[4],
const float mval[2],
@@ -495,19 +640,64 @@ bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region,
const int mval[2],
const bool do_clip,
float r_out[3]);
+/**
+ * Calculate a 3d difference vector from 2d window offset.
+ * note that #ED_view3d_calc_zfac() must be called first to determine
+ * the depth used to calculate the delta.
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d difference (such as `event->mval[0] - other_x`).
+ * \param out: The resulting world-space delta.
+ */
void ED_view3d_win_to_delta(const struct ARegion *region,
const float mval[2],
float out[3],
const float zfac);
+/**
+ * Calculate a 3d origin from 2d window coordinates.
+ * \note Orthographic views have a less obvious origin,
+ * Since far clip can be a very large value resulting in numeric precision issues,
+ * the origin in this case is close to zero coordinate.
+ *
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as event->mval converted to floats).
+ * \param out: The resulting normalized world-space direction vector.
+ */
void ED_view3d_win_to_origin(const struct ARegion *region, const float mval[2], float out[3]);
+/**
+ * Calculate a 3d direction vector from 2d window coordinates.
+ * This direction vector starts and the view in the direction of the 2d window coordinates.
+ * In orthographic view all window coordinates yield the same vector.
+ *
+ * \note doesn't rely on ED_view3d_calc_zfac
+ * for perspective view, get the vector direction to
+ * the mouse cursor as a normalized vector.
+ *
+ * \param region: The region (used for the window width and height).
+ * \param mval: The area relative 2d location (such as event->mval converted to floats).
+ * \param out: The resulting normalized world-space direction vector.
+ */
void ED_view3d_win_to_vector(const struct ARegion *region, const float mval[2], float out[3]);
+/**
+ * Calculate a 3d segment from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_end is a far point.
+ * ray_start and ray_end are clipped by the view near and far limits
+ * so points along this line are always in view.
+ * In orthographic view all resulting segments will be parallel.
+ * \param region: The region (used for the window width and height).
+ * \param v3d: The 3d viewport (used for near and far clipping range).
+ * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
+ * \param r_ray_start: The world-space starting point of the segment.
+ * \param r_ray_end: The world-space end point of the segment.
+ * \param do_clip_planes: Optionally clip the ray by the view clipping planes.
+ * \return success, false if the segment is totally clipped.
+ */
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
const struct ARegion *region,
struct View3D *v3d,
const float mval[2],
float r_ray_start[3],
float r_ray_end[3],
- const bool do_clip);
+ const bool do_clip_planes);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d,
const struct Object *ob,
float r_pmat[4][4]);
@@ -515,6 +705,10 @@ void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d,
const float obmat[4][4],
float r_pmat[4][4]);
+/**
+ * Convert between region relative coordinates (x,y) and depth component z and
+ * a point in world space.
+ */
void ED_view3d_project_v3(const struct ARegion *region,
const float world[3],
float r_region_co[3]);
@@ -527,6 +721,9 @@ bool ED_view3d_unproject_v3(
/* end */
void ED_view3d_dist_range_get(const struct View3D *v3d, float r_dist_range[2]);
+/**
+ * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
+ */
bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
@@ -543,6 +740,9 @@ bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph,
float *r_clipend,
float *r_pixsize);
+/**
+ * Use instead of: `GPU_polygon_offset(rv3d->dist, ...)` see bug T37727.
+ */
void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
void ED_view3d_calc_camera_border(const struct Scene *scene,
@@ -572,15 +772,61 @@ void ED_view3d_clipping_calc(struct BoundBox *bb,
const struct ARegion *region,
const struct Object *ob,
const struct rcti *rect);
+/**
+ * Clamp min/max by the viewport clipping.
+ *
+ * \note This is an approximation, with the limitation that the bounding box from the (mix, max)
+ * calculation might not have any geometry inside the clipped region.
+ * Performing a clipping test on each vertex would work well enough for most cases,
+ * although it's not perfect either as edges/faces may intersect the clipping without having any
+ * of their vertices inside it.
+ * A more accurate result would be quite involved.
+ *
+ * \return True when the arguments were clamped.
+ */
bool ED_view3d_clipping_clamp_minmax(const struct RegionView3D *rv3d, float min[3], float max[3]);
void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4]);
+/**
+ * Return true when `co` is hidden by the 3D views clipping planes.
+ *
+ * \param is_local: When true use local (object-space) #ED_view3d_clipping_local must run first,
+ * then all comparisons can be done in local-space.
+ * \return True when `co` is outside all clipping planes.
+ *
+ * \note Callers should check #RV3D_CLIPPING_ENABLED first.
+ */
bool ED_view3d_clipping_test(const struct RegionView3D *rv3d,
const float co[3],
const bool is_local);
float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
+/**
+ * Return a new #RegionView3D.dist value to fit the \a radius.
+ *
+ * \note Depth isn't taken into account, this will fit a flat plane exactly,
+ * but points towards the view (with a perspective projection),
+ * may be within the radius but outside the view. eg:
+ *
+ * <pre>
+ * +
+ * pt --> + /^ radius
+ * / |
+ * / |
+ * view + +
+ * \ |
+ * \ |
+ * \|
+ * +
+ * </pre>
+ *
+ * \param region: Can be NULL if \a use_aspect is false.
+ * \param persp: Allow the caller to tell what kind of perspective to use (ortho/view/camera)
+ * \param use_aspect: Increase the distance to account for non 1:1 view aspect.
+ * \param radius: The radius will be fitted exactly,
+ * typically pre-scaled by a margin (#VIEW3D_MARGIN).
+ */
float ED_view3d_radius_to_dist(const struct View3D *v3d,
const struct ARegion *region,
const struct Depsgraph *depsgraph,
@@ -588,12 +834,26 @@ float ED_view3d_radius_to_dist(const struct View3D *v3d,
const bool use_aspect,
const float radius);
-/* Back-buffer select and draw support. */
+/**
+ * Back-buffer select and draw support.
+ */
void ED_view3d_backbuf_depth_validate(struct ViewContext *vc);
+/**
+ * allow for small values [0.5 - 2.5],
+ * and large values, FLT_MAX by clamping by the area size
+ */
int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist);
void ED_view3d_select_id_validate(struct ViewContext *vc);
+/**
+ * Get the world-space 3d location from a screen-space 2d point.
+ * TODO: Implement #alphaoverride. We don't want to zoom into billboards.
+ *
+ * \param mval: Input screen-space pixel location.
+ * \param mouse_worldloc: Output world-space location.
+ * \param fallback_depth_pt: Use this points depth when no depth can be found.
+ */
bool ED_view3d_autodist(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
@@ -602,6 +862,9 @@ bool ED_view3d_autodist(struct Depsgraph *depsgraph,
const bool alphaoverride,
const float fallback_depth_pt[3]);
+/**
+ * No 4x4 sampling, run #ED_view3d_depth_override first.
+ */
bool ED_view3d_autodist_simple(struct ARegion *region,
const int mval[2],
float mouse_worldloc[3],
@@ -635,9 +898,21 @@ typedef enum {
eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *scene,
const struct Object *obact);
+/**
+ * Optionally cache data for multiple calls to #view3d_opengl_select
+ *
+ * just avoid GPU_select headers outside this file
+ */
void view3d_opengl_select_cache_begin(void);
void view3d_opengl_select_cache_end(void);
+/**
+ * \warning be sure to account for a negative return value
+ * This is an error, "Too many objects in select buffer"
+ * and no action should be taken (can crash blender) if this happens
+ *
+ * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
+ */
int view3d_opengl_select_ex(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
@@ -665,28 +940,57 @@ void ED_view3d_viewcontext_init(struct bContext *C,
struct ViewContext *vc,
struct Depsgraph *depsgraph);
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
+/**
+ * Use this call when executing an operator,
+ * event system doesn't set for each event the OpenGL drawing context.
+ */
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *region);
-/* XXX should move to BLI_math */
+/** XXX: should move to BLI_math */
bool edge_inside_circle(const float cent[2],
float radius,
const float screen_co_a[2],
const float screen_co_b[2]);
-/* get 3d region from context, also if mouse is in header or toolbar */
+/**
+ * Get 3D region from context, also if mouse is in header or toolbar.
+ */
struct RegionView3D *ED_view3d_context_rv3d(struct bContext *C);
+/**
+ * Ideally would return an rv3d but in some cases the region is needed too
+ * so return that, the caller can then access the `region->regiondata`.
+ */
bool ED_view3d_context_user_region(struct bContext *C,
struct View3D **r_v3d,
struct ARegion **r_region);
+/**
+ * Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
+ * Also works if \a v3d is not the active space.
+ */
bool ED_view3d_area_user_region(const struct ScrArea *area,
const struct View3D *v3d,
struct ARegion **r_region);
bool ED_operator_rv3d_user_region_poll(struct bContext *C);
+/**
+ * Most of the time this isn't needed since you could assume the view matrix was
+ * set while drawing, however when functions like mesh_foreachScreenVert are
+ * called by selection tools, we can't be sure this object was the last.
+ *
+ * for example, transparent objects are drawn after edit-mode and will cause
+ * the rv3d mat's to change and break selection.
+ *
+ * 'ED_view3d_init_mats_rv3d' should be called before
+ * view3d_project_short_clip and view3d_project_short_noclip in cases where
+ * these functions are not used during draw_object
+ */
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d);
void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *rv3d);
#ifdef DEBUG
+/**
+ * Ensure we correctly initialize.
+ */
void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d);
void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d);
#else
@@ -705,6 +1009,9 @@ void ED_draw_object_facemap(struct Depsgraph *depsgraph,
struct RenderEngineType *ED_view3d_engine_type(const struct Scene *scene, int drawtype);
bool ED_view3d_context_activate(struct bContext *C);
+/**
+ * Set the correct matrices
+ */
void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
struct wmWindow *win,
struct Depsgraph *depsgraph,
@@ -715,13 +1022,22 @@ void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
const float winmat[4][4],
const struct rcti *rect);
+/**
+ * `mval` comes from event->mval, only use within region handlers.
+ */
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
const int mval[2],
int *r_material_slot);
bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
+/**
+ * 'clip' is used to know if our clip setting has changed.
+ */
void ED_view3d_quadview_update(struct ScrArea *area, struct ARegion *region, bool do_clip);
+/**
+ * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
+ */
void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct View3D *v3d,
@@ -744,23 +1060,48 @@ void ED_view3d_datamask(const struct bContext *C,
const struct Scene *scene,
const struct View3D *v3d,
struct CustomData_MeshMasks *r_cddata_masks);
+/**
+ * Goes over all modes and view3d settings.
+ */
void ED_view3d_screen_datamask(const struct bContext *C,
const struct Scene *scene,
const struct bScreen *screen,
struct CustomData_MeshMasks *r_cddata_masks);
bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
+/**
+ * For viewport operators that exit camera perspective.
+ *
+ * \note This differs from simply setting `rv3d->persp = persp` because it
+ * sets the `ofs` and `dist` values of the viewport so it matches the camera,
+ * otherwise switching out of camera view may jump to a different part of the scene.
+ */
void ED_view3d_persp_switch_from_camera(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
const char persp);
+/**
+ * Action to take when rotating the view,
+ * handle auto-perspective and logic for switching out of views.
+ *
+ * shared with NDOF.
+ */
bool ED_view3d_persp_ensure(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct ARegion *region);
-/* camera lock functions */
+/* Camera lock functions */
+
+/**
+ * \return true when the 3D Viewport is locked to its camera.
+ */
bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
-/* copy the camera to the view before starting a view transformation */
+/**
+ * Copy the camera to the view before starting a view transformation.
+ *
+ * Apply the camera object transformation to the 3D Viewport.
+ * (needed so we can use regular 3D Viewport manipulation operators, that sync back to the camera).
+ */
void ED_view3d_camera_lock_init_ex(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
@@ -768,7 +1109,13 @@ void ED_view3d_camera_lock_init_ex(const struct Depsgraph *depsgraph,
void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d);
-/* copy the view to the camera, return true if */
+/**
+ * Copy the view to the camera, return true if.
+ *
+ * Apply the 3D Viewport transformation back to the camera object.
+ *
+ * \return true if the camera is moved.
+ */
bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d);
@@ -778,6 +1125,12 @@ bool ED_view3d_camera_autokey(const struct Scene *scene,
struct bContext *C,
const bool do_rotate,
const bool do_translate);
+/**
+ * Call after modifying a locked view.
+ *
+ * \note Not every view edit currently auto-keys (numeric-pad for eg),
+ * this is complicated because of smooth-view.
+ */
bool ED_view3d_camera_lock_autokey(struct View3D *v3d,
struct RegionView3D *rv3d,
struct bContext *C,
@@ -789,14 +1142,41 @@ void ED_view3d_lock_clear(struct View3D *v3d);
#define VIEW3D_MARGIN 1.4f
#define VIEW3D_DIST_FALLBACK 1.0f
+/**
+ * This function solves the problem of having to switch between camera and non-camera views.
+ *
+ * When viewing from the perspective of \a mat, and having the view center \a ofs,
+ * this calculates a distance from \a ofs to the matrix \a mat.
+ * Using \a fallback_dist when the distance would be too small.
+ *
+ * \param mat: A matrix use for the view-point (typically the camera objects matrix).
+ * \param ofs: Orbit center (negated), matching #RegionView3D.ofs, which is typically passed in.
+ * \param fallback_dist: The distance to use if the object is too near or in front of \a ofs.
+ * \returns A newly calculated distance or the fallback.
+ */
float ED_view3d_offset_distance(const float mat[4][4],
const float ofs[3],
const float fallback_dist);
+/**
+ * Set the dist without moving the view (compensate with #RegionView3D.ofs)
+ *
+ * \note take care that #RegionView3d.viewinv is up to date, #ED_view3d_update_viewmat first.
+ */
void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist);
+/**
+ * Change the distance & offset to match the depth of \a dist_co along the view axis.
+ *
+ * \param dist_co: A world-space location to use for the new depth.
+ * \param dist_min: Resulting distances below this will be ignored.
+ * \return Success if the distance was set.
+ */
bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d,
const float dist_co[3],
const float dist_min);
+/**
+ * Could move this elsewhere, but tied into #ED_view3d_grid_scale
+ */
float ED_scene_grid_scale(const struct Scene *scene, const char **r_grid_unit);
float ED_view3d_grid_scale(const struct Scene *scene,
struct View3D *v3d,
@@ -805,14 +1185,24 @@ void ED_view3d_grid_steps(const struct Scene *scene,
struct View3D *v3d,
struct RegionView3D *rv3d,
float r_grid_steps[8]);
+/**
+ * Simulates the grid scale that is actually viewed.
+ * The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
+ * Currently the simulation is only done when RV3D_VIEW_IS_AXIS.
+ */
float ED_view3d_grid_view_scale(struct Scene *scene,
struct View3D *v3d,
struct ARegion *region,
const char **r_grid_unit);
+/**
+ * \note The info that this uses is updated in #ED_refresh_viewport_fps,
+ * which currently gets called during #SCREEN_OT_animation_step.
+ */
void ED_scene_draw_fps(const struct Scene *scene, int xoffset, int *yoffset);
-/* render */
+/* Render */
+
void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *region);
void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *area);
@@ -825,7 +1215,10 @@ void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrAr
#define XRAY_ACTIVE(v3d) (XRAY_ENABLED(v3d) && ((v3d)->shading.type < OB_MATERIAL))
/* view3d_draw_legacy.c */
-/* Try avoid using these more move out of legacy. */
+
+/**
+ * Try avoid using these more move out of legacy.
+ */
void ED_view3d_draw_bgpic_test(const struct Scene *scene,
struct Depsgraph *depsgraph,
struct ARegion *region,
@@ -834,6 +1227,7 @@ void ED_view3d_draw_bgpic_test(const struct Scene *scene,
const bool do_camera_frame);
/* view3d_gizmo_preselect_type.c */
+
void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C,
struct wmGizmo *gz,
struct Base **r_base,
@@ -841,11 +1235,17 @@ void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C,
void ED_view3d_gizmo_mesh_preselect_clear(struct wmGizmo *gz);
/* space_view3d.c */
+
void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
struct ARegion *region,
const char *category_override);
/* view3d_view.c */
+
+/**
+ * See if current UUID is valid, otherwise set a valid UUID to v3d,
+ * Try to keep the same UUID previously used to allow users to quickly toggle back and forth.
+ */
bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
diff --git a/source/blender/editors/include/ED_view3d_offscreen.h b/source/blender/editors/include/ED_view3d_offscreen.h
index 8b695e61a35..1da0a282697 100644
--- a/source/blender/editors/include/ED_view3d_offscreen.h
+++ b/source/blender/editors/include/ED_view3d_offscreen.h
@@ -57,6 +57,10 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
const bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
+/**
+ * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen). Similar too
+ * #ED_view_draw_offscreen_imbuf_simple, but takes view/projection matrices as arguments.
+ */
void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3DShading *shading_override,
@@ -76,6 +80,12 @@ void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
+/**
+ * Utility func for ED_view3d_draw_offscreen
+ *
+ * \param ofs: Optional off-screen buffer, can be NULL.
+ * (avoids re-creating when doing multiple GL renders).
+ */
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
struct Scene *scene,
eDrawType drawtype,
@@ -89,6 +99,14 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
const bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
char err_out[256]);
+/**
+ * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
+ *
+ * \param ofs: Optional off-screen buffer can be NULL.
+ * (avoids re-creating when doing multiple GL renders).
+ *
+ * \note used by the sequencer
+ */
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3DShading *shading_override,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index c3c296f89ca..4cf606bf98d 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -774,7 +774,7 @@ DEF_ICON_BLANK(276)
DEF_ICON_BLANK(277)
DEF_ICON_BLANK(772)
DEF_ICON_BLANK(773)
-DEF_ICON_BLANK(774)
+DEF_ICON(CURRENT_FILE)
DEF_ICON(HOME)
DEF_ICON(DOCUMENTS)
DEF_ICON(TEMP)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index aa0dc222614..9df5b17975a 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -258,6 +258,8 @@ enum {
#define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f)
+/* Both these margins should be ignored if the panel doesn't show a background (check
+ * #UI_panel_should_show_background()). */
#define UI_PANEL_MARGIN_X (U.widget_unit * 0.4f)
#define UI_PANEL_MARGIN_Y (U.widget_unit * 0.1f)
@@ -400,9 +402,8 @@ typedef enum {
/** Resize handle (resize uilist). */
UI_BTYPE_GRIP = 57 << 9,
UI_BTYPE_DECORATOR = 58 << 9,
- UI_BTYPE_DATASETROW = 59 << 9,
/* An item in a tree view. Parent items may be collapsible. */
- UI_BTYPE_TREEROW = 60 << 9,
+ UI_BTYPE_TREEROW = 59 << 9,
} eButType;
#define BUTTYPE (63 << 9)
@@ -450,6 +451,14 @@ int UI_draw_roundbox_corner_get(void);
void UI_draw_box_shadow(const struct rctf *rect, unsigned char alpha);
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]);
+/**
+ * Draw title and text safe areas.
+ *
+ * \note This function is to be used with the 2D dashed shader enabled.
+ *
+ * \param pos: is a #PRIM_FLOAT, 2, #GPU_FETCH_FLOAT vertex attribute.
+ * \param rect: The offsets for the view, not the zones.
+ */
void UI_draw_safe_areas(uint pos,
const struct rctf *rect,
const float title_aspect[2],
@@ -461,12 +470,27 @@ enum {
UI_SCROLL_ARROWS = 1 << 1,
UI_SCROLL_NO_OUTLINE = 1 << 2,
};
+/**
+ * Function in use for buttons and for view2d sliders.
+ */
void UI_draw_widget_scroll(struct uiWidgetColors *wcol,
const struct rcti *rect,
const struct rcti *slider,
int state);
-/* Shortening string helper. */
+/**
+ * Shortening string helper.
+ *
+ * Cut off the middle of the text to fit into the given width.
+ *
+ * \note in case this middle clipping would just remove a few chars,
+ * it rather clips right, which is more readable.
+ *
+ * If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep
+ * is preserved at all cost.
+ * Useful for strings with shortcuts
+ * (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
+ */
float UI_text_clip_middle_ex(const struct uiFontStyle *fstyle,
char *str,
float okwidth,
@@ -502,9 +526,11 @@ typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
struct ARegion *butregion,
struct uiButSearch *search_but);
-/* `is_first` is typically used to ignore search filtering when the menu is first opened in order
+/**
+ * `is_first` is typically used to ignore search filtering when the menu is first opened in order
* to display the full list of options. The value will be false after the button's text is edited
- * (for every call except the first). */
+ * (for every call except the first).
+ */
typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
void *arg,
const char *str,
@@ -591,6 +617,7 @@ typedef void (*uiFreeArgFunc)(void *arg);
/* interface_query.c */
bool UI_but_has_tooltip_label(const uiBut *but);
bool UI_but_is_tool(const uiBut *but);
+/* file selectors are exempt from utf-8 checks */
bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->type == UI_BTYPE_DECORATOR)
@@ -612,10 +639,17 @@ struct uiList *UI_list_find_mouse_over(const struct ARegion *region, const struc
typedef struct uiPopupMenu uiPopupMenu;
uiPopupMenu *UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL();
+/**
+ * Only return handler, and set optional title.
+ * \param block_name: Assigned to uiBlock.name (useful info for debugging).
+ */
uiPopupMenu *UI_popup_menu_begin_ex(struct bContext *C,
const char *title,
const char *block_name,
int icon) ATTR_NONNULL();
+/**
+ * Set the whole structure to work.
+ */
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup);
bool UI_popup_menu_end_or_cancel(struct bContext *C, struct uiPopupMenu *head);
struct uiLayout *UI_popup_menu_layout(uiPopupMenu *pup);
@@ -624,7 +658,14 @@ void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_
int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports)
ATTR_NONNULL(1, 2);
+/**
+ * Allow setting menu return value from externals.
+ * E.g. WM might need to do this for exiting files correctly.
+ */
void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
+/**
+ * Setting the button makes the popup open from the button instead of the cursor.
+ */
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but);
/* interface_region_popover.c */
@@ -636,8 +677,17 @@ int UI_popover_panel_invoke(struct bContext *C,
bool keep_open,
struct ReportList *reports);
+/**
+ * Only return handler, and set optional title.
+ *
+ * \param from_active_button: Use the active button for positioning,
+ * use when the popover is activated from an operator instead of directly from the button.
+ */
uiPopover *UI_popover_begin(struct bContext *C, int menu_width, bool from_active_button)
ATTR_NONNULL(1);
+/**
+ * Set the whole structure to work.
+ */
void UI_popover_end(struct bContext *C, struct uiPopover *pup, struct wmKeyMap *keymap);
struct uiLayout *UI_popover_layout(uiPopover *pup);
void UI_popover_once_clear(uiPopover *pup);
@@ -715,6 +765,9 @@ uiBlock *UI_block_begin(const struct bContext *C,
eUIEmbossType emboss);
void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2], int r_xy[2]);
void UI_block_end(const struct bContext *C, uiBlock *block);
+/**
+ * Uses local copy of style, to scale things down, and allow widgets to change stuff.
+ */
void UI_block_draw(const struct bContext *C, struct uiBlock *block);
void UI_blocklist_update_window_matrix(const struct bContext *C, const struct ListBase *lb);
void UI_blocklist_update_view_for_buttons(const struct bContext *C, const struct ListBase *lb);
@@ -729,19 +782,36 @@ void UI_block_theme_style_set(uiBlock *block, char theme_style);
eUIEmbossType UI_block_emboss_get(uiBlock *block);
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss);
bool UI_block_is_search_only(const uiBlock *block);
+/**
+ * Use when a block must be searched to give accurate results
+ * for the whole region but shouldn't be displayed.
+ */
void UI_block_set_search_only(uiBlock *block, bool search_only);
+/**
+ * Can be called with C==NULL.
+ */
void UI_block_free(const struct bContext *C, uiBlock *block);
-void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
-void UI_blocklist_free_inactive(const struct bContext *C, struct ListBase *lb);
-void UI_screen_free_active_but(const struct bContext *C, struct bScreen *screen);
+/**
+ * Can be called with C==NULL.
+ */
+void UI_blocklist_free(const struct bContext *C, struct ARegion *region);
+void UI_blocklist_free_inactive(const struct bContext *C, struct ARegion *region);
+
+/**
+ * Is called by notifier.
+ */
+void UI_screen_free_active_but_highlight(const struct bContext *C, struct bScreen *screen);
+void UI_region_free_active_but_all(struct bContext *context, struct ARegion *region);
void UI_block_region_set(uiBlock *block, struct ARegion *region);
void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr);
void UI_block_lock_clear(uiBlock *block);
-/* Automatic aligning, horizontal or vertical. */
+/**
+ * Automatic aligning, horizontal or vertical.
+ */
void UI_block_align_begin(uiBlock *block);
void UI_block_align_end(uiBlock *block);
@@ -756,16 +826,34 @@ typedef enum {
UI_BLOCK_BOUNDS_PIE_CENTER,
} eBlockBoundsCalc;
+/**
+ * Used for various cases.
+ */
void UI_block_bounds_set_normal(struct uiBlock *block, int addval);
+/**
+ * Used for pull-downs.
+ */
void UI_block_bounds_set_text(uiBlock *block, int addval);
+/**
+ * Used for block popups.
+ */
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2]);
+/**
+ * Used for menu popups.
+ */
void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offset[2]);
+/**
+ * Used for centered popups, i.e. splash.
+ */
void UI_block_bounds_set_centered(uiBlock *block, int addval);
void UI_block_bounds_set_explicit(uiBlock *block, int minx, int miny, int maxx, int maxy);
int UI_blocklist_min_y_get(struct ListBase *lb);
void UI_block_direction_set(uiBlock *block, char direction);
+/**
+ * This call escapes if there's alignment flags.
+ */
void UI_block_order_flip(uiBlock *block);
void UI_block_flag_enable(uiBlock *block, int flag);
void UI_block_flag_disable(uiBlock *block, int flag);
@@ -774,7 +862,14 @@ void UI_block_translate(uiBlock *block, int x, int y);
int UI_but_return_value_get(uiBut *but);
void UI_but_drag_set_id(uiBut *but, struct ID *id);
+/**
+ * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
+ * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
+ */
void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale);
+/**
+ * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
+ */
void UI_but_drag_set_asset(uiBut *but,
const struct AssetHandle *asset,
const char *path,
@@ -786,11 +881,18 @@ void UI_but_drag_set_asset(uiBut *but,
void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr);
void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free);
void UI_but_drag_set_name(uiBut *but, const char *name);
+/**
+ * Value from button itself.
+ */
void UI_but_drag_set_value(uiBut *but);
void UI_but_drag_set_image(
uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free);
uiBut *UI_but_active_drop_name_button(const struct bContext *C);
+/**
+ * Returns true if highlighted button allows drop of names.
+ * called in region context.
+ */
bool UI_but_active_drop_name(const struct bContext *C);
bool UI_but_active_drop_color(struct bContext *C);
@@ -805,7 +907,13 @@ void UI_but_disable(uiBut *but, const char *disabled_hint);
void UI_but_type_set_menu_from_pulldown(uiBut *but);
-/* special button case, only draw it when used actively, for outliner etc */
+/**
+ * Special button case, only draw it when used actively, for outliner etc.
+ *
+ * Needed for temporarily rename buttons, such as in outliner or file-select,
+ * they should keep calling #uiDefBut to keep them alive.
+ * \return false when button removed.
+ */
bool UI_but_active_only_ex(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
@@ -815,10 +923,17 @@ bool UI_but_active_only(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
uiBut *but);
+/**
+ * \warning This must run after other handlers have been added,
+ * otherwise the handler won't be removed, see: T71112.
+ */
bool UI_block_active_only_flagged_buttons(const struct bContext *C,
struct ARegion *region,
struct uiBlock *block);
+/**
+ * Simulate button click.
+ */
void UI_but_execute(const struct bContext *C, struct ARegion *region, uiBut *but);
bool UI_but_online_manual_id(const uiBut *but,
@@ -1022,6 +1137,9 @@ uiBut *uiDefButO_ptr(uiBlock *block,
short height,
const char *tip);
+/**
+ * If a1==1.0 then a2 is an extra icon blending factor (alpha 0.0 - 1.0).
+ */
uiBut *uiDefIconBut(uiBlock *block,
int type,
int retval,
@@ -1207,6 +1325,7 @@ uiBut *uiDefIconButO_ptr(uiBlock *block,
uiBut *uiDefButImage(
uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4]);
uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short height);
+/* Button containing both string label and icon */
uiBut *uiDefIconTextBut(uiBlock *block,
int type,
int retval,
@@ -1477,7 +1596,10 @@ enum {
UI_TEMPLATE_ID_FILTER_AVAILABLE = 1,
};
+/***************************** ID Utilities *******************************/
+
int UI_icon_from_id(const struct ID *id);
+/** See: #BKE_report_type_str */
int UI_icon_from_report_type(int type);
int UI_icon_colorid_from_report_type(int type);
int UI_text_colorid_from_report_type(int type);
@@ -1542,6 +1664,9 @@ uiBut *uiDefBlockButN(uiBlock *block,
short height,
const char *tip);
+/**
+ * Block button containing icon.
+ */
uiBut *uiDefIconBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -1552,6 +1677,9 @@ uiBut *uiDefIconBlockBut(uiBlock *block,
short width,
short height,
const char *tip);
+/**
+ * Block button containing both string label and icon.
+ */
uiBut *uiDefIconTextBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -1572,6 +1700,11 @@ uiBut *uiDefKeyevtButS(uiBlock *block,
short height,
short *spoin,
const char *tip);
+
+/**
+ * Short pointers hard-coded.
+ * \param modkeypoin: will be set to #KM_SHIFT, #KM_ALT, #KM_CTRL, #KM_OSKEY bits.
+ */
uiBut *uiDefHotKeyevtButS(uiBlock *block,
int retval,
const char *str,
@@ -1583,6 +1716,10 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block,
const short *modkeypoin,
const char *tip);
+/**
+ * \param arg: A pointer to string/name, use #UI_but_func_search_set() below to make this work.
+ * here `a1` and `a2`, if set, control thumbnail preview rows/cols.
+ */
uiBut *uiDefSearchBut(uiBlock *block,
void *arg,
int retval,
@@ -1595,6 +1732,10 @@ uiBut *uiDefSearchBut(uiBlock *block,
float a1,
float a2,
const char *tip);
+/**
+ * Same parameters as for #uiDefSearchBut, with additional operator type and properties,
+ * used by callback to call again the right op with the right options (properties values).
+ */
uiBut *uiDefSearchButO_ptr(uiBlock *block,
struct wmOperatorType *ot,
struct IDProperty *properties,
@@ -1638,6 +1779,12 @@ uiBut *uiDefAutoButR(uiBlock *block,
int y,
int width,
int height);
+/**
+ * \a check_prop callback filters functions to avoid drawing certain properties,
+ * in cases where PROP_HIDDEN flag can't be used for a property.
+ *
+ * \param prop_activate_init: Property to activate on initial popup (#UI_BUT_ACTIVATE_ON_INIT).
+ */
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
struct PointerRNA *ptr,
bool (*check_prop)(struct PointerRNA *ptr,
@@ -1648,7 +1795,19 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
eButLabelAlign label_align,
const bool compact);
-/* use inside searchfunc to add items */
+/**
+ * Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
+ *
+ * Use inside searchfunc to add items.
+ *
+ * \param items: Stores the items.
+ * \param name: Text to display for the item.
+ * \param poin: Opaque pointer (for use by the caller).
+ * \param iconid: The icon, #ICON_NONE for no icon.
+ * \param state: The buttons state flag, compatible with #uiBut.flag,
+ * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE.
+ * \return false if there is nothing to add.
+ */
bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
@@ -1656,6 +1815,21 @@ bool UI_search_item_add(uiSearchItems *items,
int state,
const uint8_t name_prefix_offset);
+/**
+ * \note The item-pointer (referred to below) is a per search item user pointer
+ * passed to #UI_search_item_add (stored in #uiSearchItems.pointers).
+ *
+ * \param search_create_fn: Function to create the menu.
+ * \param search_update_fn: Function to refresh search content after the search text has changed.
+ * \param arg: user value.
+ * \param free_arg: Set to true if the argument is newly allocated memory for every redraw and
+ * should be freed when the button is destroyed.
+ * \param search_arg_free_fn: When non-null, use this function to free \a arg.
+ * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument.
+ * The second argument as the active item-pointer
+ * \param active: When non-null, this item-pointer item will be visible and selected,
+ * otherwise the first item will be selected.
+ */
void UI_but_func_search_set(uiBut *but,
uiButSearchCreateFn search_create_fn,
uiButSearchUpdateFn search_update_fn,
@@ -1666,21 +1840,28 @@ void UI_but_func_search_set(uiBut *but,
void *active);
void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn);
void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn);
+/**
+ * \param search_sep_string: when not NULL, this string is used as a separator,
+ * showing the icon and highlighted text after the last instance of this string.
+ */
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string);
void UI_but_func_search_set_results_are_suggestions(uiBut *but, const bool value);
-/* height in pixels, it's using hardcoded values still */
+/**
+ * Height in pixels, it's using hard-coded values still.
+ */
int UI_searchbox_size_y(void);
int UI_searchbox_size_x(void);
-/* check if a string is in an existing search box */
+/**
+ * Check if a string is in an existing search box.
+ */
int UI_search_items_find_index(uiSearchItems *items, const char *name);
+/**
+ * Adds a hint to the button which draws right aligned, grayed out and never clipped.
+ */
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
-void UI_but_datasetrow_indentation_set(uiBut *but, int indentation);
-void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type);
-void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain);
-uint8_t UI_but_datasetrow_component_get(uiBut *but);
-uint8_t UI_but_datasetrow_domain_get(uiBut *but);
+
void UI_but_treerow_indentation_set(uiBut *but, int indentation);
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
@@ -1708,7 +1889,14 @@ void UI_but_func_drawextra_set(
void UI_but_func_menu_step_set(uiBut *but, uiMenuStepFunc func);
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg);
+/**
+ * Recreate tool-tip (use to update dynamic tips)
+ */
void UI_but_tooltip_refresh(struct bContext *C, uiBut *but);
+/**
+ * Removes tool-tip timer from active but
+ * (meaning tool-tip is disabled until it's re-enabled again).
+ */
void UI_but_tooltip_timer_remove(struct bContext *C, uiBut *but);
bool UI_textbutton_activate_rna(const struct bContext *C,
@@ -1717,6 +1905,10 @@ bool UI_textbutton_activate_rna(const struct bContext *C,
const char *rna_prop_id);
bool UI_textbutton_activate_but(const struct bContext *C, uiBut *but);
+/**
+ * push a new event onto event queue to activate the given button
+ * (usually a text-field) upon entering a popup
+ */
void UI_but_focus_on_enter_event(struct wmWindow *win, uiBut *but);
void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
@@ -1754,24 +1946,58 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname);
void UI_panels_begin(const struct bContext *C, struct ARegion *region);
void UI_panels_end(const struct bContext *C, struct ARegion *region, int *r_x, int *r_y);
+/**
+ * Draw panels, selected (panels currently being dragged) on top.
+ */
void UI_panels_draw(const struct bContext *C, struct ARegion *region);
struct Panel *UI_panel_find_by_type(struct ListBase *lb, const struct PanelType *pt);
+/**
+ * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL.
+ */
struct Panel *UI_panel_begin(struct ARegion *region,
struct ListBase *lb,
uiBlock *block,
struct PanelType *pt,
struct Panel *panel,
bool *r_open);
+/**
+ * Create the panel header button group, used to mark which buttons are part of
+ * panel headers for the panel search process that happens later. This Should be
+ * called before adding buttons for the panel's header layout.
+ */
void UI_panel_header_buttons_begin(struct Panel *panel);
+/**
+ * Finish the button group for the panel header to avoid putting panel body buttons in it.
+ */
void UI_panel_header_buttons_end(struct Panel *panel);
void UI_panel_end(struct Panel *panel, int width, int height);
+/**
+ * Set a context for this entire panel and its current layout. This should be used whenever panel
+ * callbacks that are called outside of regular drawing might require context. Currently it affects
+ * the #PanelType.reorder callback only.
+ */
+void UI_panel_context_pointer_set(struct Panel *panel, const char *name, struct PointerRNA *ptr);
+
+/**
+ * Get the panel's expansion state, taking into account
+ * expansion set from property search if it applies.
+ */
bool UI_panel_is_closed(const struct Panel *panel);
bool UI_panel_is_active(const struct Panel *panel);
+/**
+ * For button layout next to label.
+ */
void UI_panel_label_offset(const struct uiBlock *block, int *r_x, int *r_y);
+bool UI_panel_should_show_background(const struct ARegion *region,
+ const struct PanelType *panel_type);
int UI_panel_size_y(const struct Panel *panel);
bool UI_panel_is_dragging(const struct Panel *panel);
+/**
+ * Find whether a panel or any of its sub-panels contain a property that matches the search filter,
+ * depending on the search process running in #UI_block_apply_search_filter earlier.
+ */
bool UI_panel_matches_search_filter(const struct Panel *panel);
bool UI_panel_can_be_pinned(const struct Panel *panel);
@@ -1784,6 +2010,9 @@ const char *UI_panel_category_active_get(struct ARegion *region, bool set_fallba
void UI_panel_category_active_set(struct ARegion *region, const char *idname);
void UI_panel_category_active_set_default(struct ARegion *region, const char *idname);
void UI_panel_category_clear_all(struct ARegion *region);
+/**
+ * Draw vertical tabs on the left side of the region, one tab per category.
+ */
void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_active);
/* Panel custom data. */
@@ -1793,17 +2022,40 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
/* Polyinstantiated panels for representing a list of data. */
+/**
+ * Called in situations where panels need to be added dynamically rather than
+ * having only one panel corresponding to each #PanelType.
+ */
struct Panel *UI_panel_add_instanced(const struct bContext *C,
struct ARegion *region,
struct ListBase *panels,
const char *panel_idname,
struct PointerRNA *custom_data);
+/**
+ * Remove instanced panels from the region's panel list.
+ *
+ * \note Can be called with NULL \a C, but it should be avoided because
+ * handlers might not be removed.
+ */
void UI_panels_free_instanced(const struct bContext *C, struct ARegion *region);
#define INSTANCED_PANEL_UNIQUE_STR_LEN 16
+/**
+ * Find a unique key to append to the #PanelType.idname for the lookup to the panel's #uiBlock.
+ * Needed for instanced panels, where there can be multiple with the same type and identifier.
+ */
void UI_list_panel_unique_str(struct Panel *panel, char *r_name);
typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+/**
+ * Check if the instanced panels in the region's panels correspond to the list of data the panels
+ * represent. Returns false if the panels have been reordered or if the types from the list data
+ * don't match in any way.
+ *
+ * \param data: The list of data to check against the instanced panels.
+ * \param panel_idname_func: Function to find the #PanelType.idname for each item in the data list.
+ * For a readability and generality, this lookup happens separately for each type of panel list.
+ */
bool UI_panel_list_matches_data(struct ARegion *region,
struct ListBase *data,
uiListPanelIDFromDataFunc panel_idname_func);
@@ -1828,6 +2080,7 @@ void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers)
* be used to reinitialize some internal state if user preferences change. */
void UI_init(void);
+/* after reading userdef file */
void UI_init_userdef(void);
void UI_reinit_font(void);
void UI_exit(void);
@@ -1943,8 +2196,18 @@ uiLayout *UI_block_layout(uiBlock *block,
const struct uiStyle *style);
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
+/**
+ * Used for property search when the layout process needs to be cancelled in order to avoid
+ * computing the locations for buttons, but the layout items created while adding the buttons
+ * must still be freed.
+ */
void UI_block_layout_free(uiBlock *block);
+/**
+ * Apply property search behavior, setting panel flags and deactivating buttons that don't match.
+ *
+ * \note Must not be run after #UI_block_layout_resolve.
+ */
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter);
void UI_region_message_subscribe(struct ARegion *region, struct wmMsgBus *mbus);
@@ -1955,11 +2218,23 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr);
struct bContextStore *uiLayoutGetContextStore(uiLayout *layout);
void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct wmOperatorType *UI_but_operatortype_get_from_enum_menu(struct uiBut *but,
struct PropertyRNA **r_prop);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct MenuType *UI_but_menutype_get(uiBut *but);
+/**
+ * This is a bit of a hack but best keep it in one place at least.
+ */
struct PanelType *UI_but_paneltype_get(uiBut *but);
void UI_menutype_draw(struct bContext *C, struct MenuType *mt, struct uiLayout *layout);
+/**
+ * Used for popup panels only.
+ */
void UI_paneltype_draw(struct bContext *C, struct PanelType *pt, struct uiLayout *layout);
/* Only for convenience. */
@@ -2001,10 +2276,20 @@ eUIEmbossType uiLayoutGetEmboss(uiLayout *layout);
bool uiLayoutGetPropSep(uiLayout *layout);
bool uiLayoutGetPropDecorate(uiLayout *layout);
-/* layout specifiers */
+/* Layout create functions. */
+
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
+/**
+ * See #uiLayoutColumnWithHeading().
+ */
uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
+/**
+ * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
+ * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
+ * first split-column, the heading is added there instead. Otherwise the heading inserted with a
+ * new row.
+ */
uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
uiLayout *uiLayoutGridFlow(uiLayout *layout,
@@ -2056,6 +2341,9 @@ void uiTemplateIDPreview(uiLayout *layout,
int cols,
int filter,
const bool hide_buttons);
+/**
+ * Version of #uiTemplateID using tabs.
+ */
void uiTemplateIDTabs(uiLayout *layout,
struct bContext *C,
struct PointerRNA *ptr,
@@ -2063,11 +2351,23 @@ void uiTemplateIDTabs(uiLayout *layout,
const char *newop,
const char *menu,
int filter);
+/**
+ * This is for selecting the type of ID-block to use,
+ * and then from the relevant type choosing the block to use.
+ *
+ * \param propname: property identifier for property that ID-pointer gets stored to.
+ * \param proptypename: property identifier for property
+ * used to determine the type of ID-pointer that can be used.
+ */
void uiTemplateAnyID(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
const char *proptypename,
const char *text);
+/**
+ * Search menu to pick an item from a collection.
+ * A version of uiTemplateID that works for non-ID types.
+ */
void uiTemplateSearch(uiLayout *layout,
struct bContext *C,
struct PointerRNA *ptr,
@@ -2086,6 +2386,13 @@ void uiTemplateSearchPreview(uiLayout *layout,
const char *unlinkop,
const int rows,
const int cols);
+/**
+ * This is creating/editing RNA-Paths
+ *
+ * - ptr: struct which holds the path property
+ * - propname: property identifier for property that path gets stored to
+ * - root_ptr: struct that path gets built from
+ */
void uiTemplatePathBuilder(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2093,7 +2400,13 @@ void uiTemplatePathBuilder(uiLayout *layout,
const char *text);
void uiTemplateModifiers(uiLayout *layout, struct bContext *C);
void uiTemplateGpencilModifiers(uiLayout *layout, struct bContext *C);
+/**
+ * Check if the shader effect panels don't match the data and rebuild the panels if so.
+ */
void uiTemplateShaderFx(uiLayout *layout, struct bContext *C);
+/**
+ * Check if the constraint panels don't match the data and rebuild the panels if so.
+ */
void uiTemplateConstraints(uiLayout *layout, struct bContext *C, bool use_bone_constraints);
uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
@@ -2120,7 +2433,13 @@ void uiTemplateColorRamp(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
bool expand);
+/**
+ * \param icon_scale: Scale of the icon, 1x == button height.
+ */
void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale);
+/**
+ * \param icon_scale: Scale of the icon, 1x == button height.
+ */
void uiTemplateIconView(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2138,7 +2457,14 @@ void uiTemplateCurveMapping(uiLayout *layout,
bool brush,
bool neg_slope,
bool tone);
+/**
+ * Template for a path creation widget intended for custom bevel profiles.
+ * This section is quite similar to #uiTemplateCurveMapping, but with reduced complexity.
+ */
void uiTemplateCurveProfile(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+/**
+ * This template now follows User Preference for type - name is not correct anymore.
+ */
void uiTemplateColorPicker(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2154,6 +2480,10 @@ void uiTemplateCryptoPicker(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
int icon);
+/**
+ * \todo for now, grouping of layers is determined by dividing up the length of
+ * the array of layer bitflags
+ */
void uiTemplateLayers(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
@@ -2188,6 +2518,11 @@ void uiTemplateOperatorSearch(uiLayout *layout);
void UI_but_func_menu_search(uiBut *but);
void uiTemplateMenuSearch(uiLayout *layout);
+/**
+ * Draw Operator property buttons for redoing execution with different settings.
+ * This function does not initialize the layout,
+ * functions can be called on the layout before and after.
+ */
void uiTemplateOperatorPropertyButs(const struct bContext *C,
uiLayout *layout,
struct wmOperator *op,
@@ -2273,6 +2608,9 @@ void uiTemplateNodeView(uiLayout *layout,
struct bNode *node,
struct bNodeSocket *input);
void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
+/**
+ * Button to quickly show texture in Properties Editor texture tab.
+ */
void uiTemplateTextureShow(uiLayout *layout,
const struct bContext *C,
struct PointerRNA *ptr,
@@ -2329,9 +2667,15 @@ void uiTemplateAssetView(struct uiLayout *layout,
const char *drag_opname,
struct PointerRNA *r_drag_op_properties);
+/**
+ * \return: A RNA pointer for the operator properties.
+ */
struct PointerRNA *UI_list_custom_activate_operator_set(struct uiList *ui_list,
const char *opname,
bool create_properties);
+/**
+ * \return: A RNA pointer for the operator properties.
+ */
struct PointerRNA *UI_list_custom_drag_operator_set(struct uiList *ui_list,
const char *opname,
bool create_properties);
@@ -2350,6 +2694,9 @@ void uiItemEnumO(uiLayout *layout,
int icon,
const char *propname,
int value);
+/**
+ * For use in cases where we have.
+ */
void uiItemEnumO_value(uiLayout *layout,
const char *name,
int icon,
@@ -2428,6 +2775,9 @@ void uiItemFullR(uiLayout *layout,
int flag,
const char *name,
int icon);
+/**
+ * Use a wrapper function since re-implementing all the logic in this function would be messy.
+ */
void uiItemFullR_with_popover(uiLayout *layout,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
@@ -2491,6 +2841,11 @@ void uiItemsFullEnumO(uiLayout *layout,
struct IDProperty *properties,
wmOperatorCallContext context,
int flag);
+/**
+ * Create UI items for enum items in \a item_array.
+ *
+ * A version of #uiItemsFullEnumO that takes pre-calculated item array.
+ */
void uiItemsFullEnumO_items(uiLayout *layout,
struct wmOperatorType *ot,
struct PointerRNA ptr,
@@ -2507,33 +2862,59 @@ typedef struct uiPropertySplitWrapper {
uiLayout *decorate_column;
} uiPropertySplitWrapper;
+/**
+ * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
+ * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
+ * special needs.
+ */
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
void uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
+/**
+ * Helper to add a label and creates a property split layout if needed.
+ */
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon);
-/* label icon for dragging */
+/**
+ * Label icon for dragging.
+ */
void uiItemLDrag(uiLayout *layout, struct PointerRNA *ptr, const char *name, int icon);
-/* menu */
+/**
+ * Menu.
+ */
void uiItemM_ptr(uiLayout *layout, struct MenuType *mt, const char *name, int icon);
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon);
-/* menu contents */
+/**
+ * Menu contents.
+ */
void uiItemMContents(uiLayout *layout, const char *menuname);
-/* Decorators */
+
+/* Decorators. */
+
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
+ */
void uiItemDecoratorR_prop(uiLayout *layout,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
+ */
void uiItemDecoratorR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int index);
-/* value */
+/** Value item */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval);
-/* separator */
+/** Separator item */
void uiItemS(uiLayout *layout);
+/** Separator item */
void uiItemS_ex(uiLayout *layout, float factor);
-/* Special separator. */
+/** Flexible spacing. */
void uiItemSpacer(uiLayout *layout);
+/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, const struct bContext *C, struct PanelType *pt, const char *name, int icon);
void uiItemPopoverPanel(uiLayout *layout,
@@ -2548,7 +2929,13 @@ void uiItemPopoverPanelFromGroup(uiLayout *layout,
const char *context,
const char *category);
+/**
+ * Level items.
+ */
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg);
+/**
+ * Version of #uiItemMenuF that free's `argN`.
+ */
void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN);
void uiItemMenuEnumFullO_ptr(uiLayout *layout,
struct bContext *C,
@@ -2586,9 +2973,15 @@ void uiItemTabsEnumR_prop(uiLayout *layout,
bool icon_only);
/* Only for testing, inspecting layouts. */
+/**
+ * Evaluate layout items as a Python dictionary.
+ */
const char *UI_layout_introspect(uiLayout *layout);
-/* Helper to add a big icon and create a split layout for alert boxes. */
+/**
+ * Helper to add a big icon and create a split layout for alert popups.
+ * Returns the layout to place further items into the alert box.
+ */
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon);
/* UI Operators */
@@ -2598,6 +2991,9 @@ typedef struct uiDragColorHandle {
} uiDragColorHandle;
void ED_operatortypes_ui(void);
+/**
+ * \brief User Interface Keymap
+ */
void ED_keymap_ui(struct wmKeyConfig *keyconf);
void ED_dropboxes_ui(void);
void ED_uilisttypes_ui(void);
@@ -2611,10 +3007,28 @@ bool UI_context_copy_to_selected_list(struct bContext *C,
struct ListBase *r_lb,
bool *r_use_path_from_id,
char **r_path);
+bool UI_context_copy_to_selected_check(struct PointerRNA *ptr,
+ struct PointerRNA *ptr_link,
+ struct PropertyRNA *prop,
+ const char *path,
+ bool use_path_from_id,
+ struct PointerRNA *r_ptr,
+ struct PropertyRNA **r_prop);
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
+/**
+ * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
+ * if set. Does not traverse into parent menus, which may be wanted in some
+ * cases.
+ */
uiBut *UI_context_active_but_get_respect_menu(const struct bContext *C);
+/**
+ * Version of #UI_context_active_but_get that also returns RNA property info.
+ * Helper function for insert keyframe, reset to default, etc operators.
+ *
+ * \return active button, NULL if none found or if it doesn't contain valid RNA data.
+ */
uiBut *UI_context_active_but_prop_get(const struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
@@ -2623,12 +3037,18 @@ void UI_context_active_but_prop_handle(struct bContext *C);
void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region);
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
+/**
+ * Helper function for insert keyframe, reset to default, etc operators.
+ */
void UI_context_update_anim_flag(const struct bContext *C);
void UI_context_active_but_prop_get_filebrowser(const struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
bool *r_is_undo,
bool *r_is_userdef);
+/**
+ * For new/open operators.
+ */
void UI_context_active_but_prop_get_templateID(struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop);
@@ -2639,6 +3059,9 @@ uiBut *UI_region_but_find_rect_over(const struct ARegion *region, const struct r
uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
const int xy[2],
bool only_clip);
+/**
+ * Try to find a search-box region opened from a button in \a button_region.
+ */
struct ARegion *UI_region_searchbox_region_get(const struct ARegion *button_region);
/* uiFontStyle.align */
@@ -2669,12 +3092,24 @@ void UI_fontstyle_draw(const struct uiFontStyle *fs,
const char *str,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params);
+/**
+ * Drawn same as above, but at 90 degree angle.
+ */
void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
const uchar col[4]);
+/**
+ * Similar to #UI_fontstyle_draw
+ * but ignore alignment, shadow & no clipping rect.
+ *
+ * For drawing on-screen labels.
+ */
void UI_fontstyle_draw_simple(
const struct uiFontStyle *fs, float x, float y, const char *str, const uchar col[4]);
+/**
+ * Same as #UI_fontstyle_draw but draw a colored backdrop.
+ */
void UI_fontstyle_draw_simple_backdrop(const struct uiFontStyle *fs,
float x,
float y,
@@ -2684,15 +3119,30 @@ void UI_fontstyle_draw_simple_backdrop(const struct uiFontStyle *fs,
int UI_fontstyle_string_width(const struct uiFontStyle *fs,
const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+/**
+ * Return the width of `str` with the spacing & kerning of `fs` with `aspect`
+ * (representing #uiBlock.aspect) applied.
+ *
+ * When calculating text width, the UI layout logic calculate widths without scale,
+ * only applying scale when drawing. This causes problems for fonts since kerning at
+ * smaller sizes often makes them wider than a scaled down version of the larger text.
+ * Resolve this by calculating the text at the on-screen size,
+ * returning the result scaled back to 1:1. See T92361.
+ */
int UI_fontstyle_string_width_with_block_aspect(const struct uiFontStyle *fs,
const char *str,
const float aspect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
int UI_fontstyle_height_max(const struct uiFontStyle *fs);
+/**
+ * Triangle 'icon' for panel header and other cases.
+ */
void UI_draw_icon_tri(float x, float y, char dir, const float[4]);
-const struct uiStyle *UI_style_get(void); /* use for fonts etc */
+/* XXX: read a style configure */
+const struct uiStyle *UI_style_get(void); /* use for fonts etc */
+/* for drawing, scaled with DPI setting */
const struct uiStyle *UI_style_get_dpi(void); /* DPI scaled settings for drawing */
/* linker workaround ack! */
@@ -2701,25 +3151,56 @@ void UI_template_fix_linking(void);
/* UI_OT_editsource helpers */
bool UI_editsource_enable_check(void);
void UI_editsource_active_but_test(uiBut *but);
+/**
+ * Remove the editsource data for \a old_but and reinsert it for \a new_but. Use when the button
+ * was reallocated, e.g. to have a new type (#ui_but_change_type()).
+ */
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but);
+/**
+ * Adjust the view so the rectangle of \a but is in view, with some extra margin.
+ *
+ * It's important that this is only executed after buttons received their final #uiBut.rect. E.g.
+ * #UI_panels_end() modifies them, so if that is executed, this function must not be called before
+ * it.
+ *
+ * \param region: The region the button is placed in. Make sure this is actually the one the button
+ * is placed in, not just the context region.
+ */
void UI_but_ensure_in_view(const struct bContext *C, struct ARegion *region, const uiBut *but);
/* UI_butstore_ helpers */
typedef struct uiButStore uiButStore;
typedef struct uiButStoreElem uiButStoreElem;
+/**
+ * Create a new button store, the caller must manage and run #UI_butstore_free
+ */
uiButStore *UI_butstore_create(uiBlock *block);
+/**
+ * NULL all pointers, don't free since the owner needs to be able to inspect.
+ */
void UI_butstore_clear(uiBlock *block);
+/**
+ * Map freed buttons from the old block and update pointers.
+ */
void UI_butstore_update(uiBlock *block);
void UI_butstore_free(uiBlock *block, uiButStore *bs);
bool UI_butstore_is_valid(uiButStore *bs);
bool UI_butstore_is_registered(uiBlock *block, uiBut *but);
void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p);
+/**
+ * Update the pointer for a registered button.
+ */
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src);
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
/* ui_interface_region_tooltip.c */
+
+/**
+ * \param is_label: When true, show a small tip that only shows the name, otherwise show the full
+ * tooltip.
+ */
struct ARegion *UI_tooltip_create_from_button(struct bContext *C,
struct ARegion *butregion,
uiBut *but,
@@ -2741,6 +3222,13 @@ typedef struct {
char hint[UI_MAX_DRAW_STR];
} uiSearchItemTooltipData;
+/**
+ * Create a tooltip from search-item tooltip data \a item_tooltip data.
+ * To be called from a callback set with #UI_but_func_search_set_tooltip().
+ *
+ * \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
+ * which is passed to the tooltip callback.
+ */
struct ARegion *UI_tooltip_create_from_search_item_generic(
struct bContext *C,
const struct ARegion *searchbox_region,
@@ -2759,6 +3247,10 @@ struct ARegion *UI_tooltip_create_from_search_item_generic(
/* Typical UI text */
#define UI_FSTYLE_WIDGET (const uiFontStyle *)&(UI_style_get()->widget)
+/**
+ * Returns the best "UI" precision for given floating value,
+ * so that e.g. 10.000001 rather gets drawn as '10'...
+ */
int UI_calc_float_precision(int prec, double value);
/* widget batched drawing */
@@ -2767,6 +3259,12 @@ void UI_widgetbase_draw_cache_flush(void);
void UI_widgetbase_draw_cache_end(void);
/* Use for resetting the theme. */
+/**
+ * Initialize default theme.
+ *
+ * \note When you add new colors, created & saved themes need initialized
+ * use function below, #init_userdef_do_versions.
+ */
void UI_theme_init_default(void);
void UI_style_init_default(void);
@@ -2780,12 +3278,28 @@ void UI_interface_tag_script_reload(void);
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
+/**
+ * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
+ * support dragging, i.e. it won't create a drag-controller upon request.
+ * \return True if dragging started successfully, otherwise false.
+ */
bool UI_tree_view_item_drag_start(struct bContext *C, uiTreeViewItemHandle *item_);
bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
const struct wmDrag *drag,
const char **r_disabled_hint);
char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item, const struct wmDrag *drag);
-bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const struct ListBase *drags);
+/**
+ * Let a tree-view item handle a drop event.
+ * \return True if the drop was handled by the tree-view item.
+ */
+bool UI_tree_view_item_drop_handle(struct bContext *C,
+ const uiTreeViewItemHandle *item_,
+ const struct ListBase *drags);
+/**
+ * Can \a item_handle be renamed right now? Not that this isn't just a mere wrapper around
+ * #AbstractTreeViewItem::can_rename(). This also checks if there is another item being renamed,
+ * and returns false if so.
+ */
bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle);
void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle);
@@ -2793,6 +3307,9 @@ void UI_tree_view_item_context_menu_build(struct bContext *C,
const uiTreeViewItemHandle *item,
uiLayout *column);
+/**
+ * \param xy: Coordinate to find a tree-row item at, in window space.
+ */
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *region,
const int xy[2]) ATTR_NONNULL(1, 2);
uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index b14ee6c4a59..d18ec009108 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -66,6 +66,9 @@ void attribute_search_add_items(
} // namespace blender::ui
+/**
+ * Override this for all available tree types.
+ */
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 37cf7229ffb..242b8504ae1 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -64,23 +64,39 @@ typedef enum eAlertIcon {
struct ImBuf *UI_icon_alert_imbuf_get(eAlertIcon icon);
-/*
+/**
* Resizable Icons for Blender
*/
void UI_icons_init(void);
+/**
+ * Reload the textures for internal icons.
+ * This function will release the previous textures.
+ */
void UI_icons_reload_internal_textures(void);
+/**
+ * NOTE: returns unscaled by DPI.
+ */
int UI_icon_get_width(int icon_id);
int UI_icon_get_height(int icon_id);
bool UI_icon_get_theme_color(int icon_id, unsigned char color[4]);
+/**
+ * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored.
+ */
void UI_icon_render_id(const struct bContext *C,
struct Scene *scene,
struct ID *id,
const enum eIconSizes size,
const bool use_job);
+/**
+ * Render size for preview images and icons
+ */
int UI_icon_preview_to_render_size(enum eIconSizes size);
+/**
+ * Draws icon with dpi scale factor.
+ */
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha);
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 61da496d344..98e141c65b5 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -351,7 +351,7 @@ typedef enum ThemeColorID {
TH_VERTEX_BEVEL,
} ThemeColorID;
-/* specific defines per space should have higher define values */
+/* Specific defines per space should have higher define values. */
struct bTheme;
@@ -362,93 +362,144 @@ struct bThemeState {
/* THE CODERS API FOR THEMES: */
-/* returns one value, not scaled */
+/**
+ * Get individual values, not scaled.
+ */
float UI_GetThemeValuef(int colorid);
+/**
+ * Get individual values, not scaled.
+ */
int UI_GetThemeValue(int colorid);
+/* Versions of #UI_GetThemeValue & #UI_GetThemeValuef, which take a space-type */
+
float UI_GetThemeValueTypef(int colorid, int spacetype);
int UI_GetThemeValueType(int colorid, int spacetype);
-/* get three color values, scaled to 0.0-1.0 range */
+/**
+ * Get three color values, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColor3fv(int colorid, float col[3]);
void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3]);
void UI_GetThemeColorBlend3f(int colorid1, int colorid2, float fac, float r_col[3]);
void UI_GetThemeColorBlend4f(int colorid1, int colorid2, float fac, float r_col[4]);
-/* get the color, range 0.0-1.0, complete with shading offset */
+/**
+ * Get the color, range 0.0-1.0, complete with shading offset.
+ */
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3]);
void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]);
void UI_GetThemeColorShade4ubv(int colorid, int offset, unsigned char col[4]);
-/* get three color values, range 0-255,
- * complete with shading offset for the RGB components and blending. */
+/**
+ * Get three color values, range 0-255,
+ * complete with shading offset for the RGB components and blending.
+ */
void UI_GetThemeColorBlendShade3ubv(
int colorid1, int colorid2, float fac, int offset, unsigned char col[3]);
-/* get four color values, scaled to 0.0-1.0 range */
+/**
+ * Get four color values, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColor4fv(int colorid, float col[4]);
-/* get four color values from specified space type, scaled to 0.0-1.0 range */
+/**
+ * Get four color values from specified space type, scaled to 0.0-1.0 range.
+ */
void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4]);
-/* get four color values, range 0.0-1.0, complete with shading offset for the RGB components */
+/**
+ * Get four color values, range 0.0-1.0, complete with shading offset for the RGB components.
+ */
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]);
void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]);
-/* get four color values ranged between 0 and 255; includes the alpha channel */
+/**
+ * Get four color values ranged between 0 and 255; includes the alpha channel.
+ */
void UI_GetThemeColorShadeAlpha4ubv(int colorid,
int coloffset,
int alphaoffset,
unsigned char col[4]);
-/* get four color values, range 0.0-1.0,
- * complete with shading offset for the RGB components and blending. */
+/**
+ * Get four color values, range 0.0-1.0,
+ * complete with shading offset for the RGB components and blending.
+ */
void UI_GetThemeColorBlendShade3fv(
int colorid1, int colorid2, float fac, int offset, float col[3]);
void UI_GetThemeColorBlendShade4fv(
int colorid1, int colorid2, float fac, int offset, float col[4]);
-/* get the 3 or 4 byte values */
+/**
+ * Get the 3 or 4 byte values.
+ */
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]);
+/**
+ * Get the color, in char pointer.
+ */
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4]);
-/* get a theme color from specified space type */
+/**
+ * Get a theme color from specified space type.
+ */
void UI_GetThemeColorType3fv(int colorid, int spacetype, float col[3]);
void UI_GetThemeColorType3ubv(int colorid, int spacetype, unsigned char col[3]);
void UI_GetThemeColorType4ubv(int colorid, int spacetype, unsigned char col[4]);
-/* get theme color for coloring monochrome icons */
+/**
+ * Get theme color for coloring monochrome icons.
+ */
bool UI_GetIconThemeColor4ubv(int colorid, unsigned char col[4]);
-/* shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor) */
+/**
+ * Shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor).
+ */
void UI_GetColorPtrShade3ubv(const unsigned char cp1[3], unsigned char col[3], int offset);
-/* get a 3 byte color, blended and shaded between two other char color pointers */
+/**
+ * Get a 3 byte color, blended and shaded between two other char color pointers.
+ */
void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3],
const unsigned char cp2[3],
unsigned char col[3],
float fac,
int offset);
-/* sets the font color
- * (for anything fancy use UI_GetThemeColor[Fancy] then BLF_color) */
+/**
+ * Sets the font color
+ * (for anything fancy use UI_GetThemeColor[Fancy] then BLF_color).
+ */
void UI_FontThemeColor(int fontid, int colorid);
-/* Clear the frame-buffer using the input colorid. */
+/**
+ * Clear the frame-buffer using the input colorid.
+ */
void UI_ThemeClearColor(int colorid);
-/* internal (blender) usage only, for init and set active */
+/**
+ * Internal (blender) usage only, for init and set active.
+ */
void UI_SetTheme(int spacetype, int regionid);
-/* get current theme */
+/**
+ * Get current theme.
+ */
struct bTheme *UI_GetTheme(void);
+/**
+ * For the rare case we need to temp swap in a different theme (off-screen render).
+ */
void UI_Theme_Store(struct bThemeState *theme_state);
void UI_Theme_Restore(struct bThemeState *theme_state);
-/* return shadow width outside menus and popups */
+/**
+ * Return shadow width outside menus and popups.
+ */
int UI_ThemeMenuShadowWidth(void);
-/* only for buttons in theme editor! */
+/**
+ * Only for buttons in theme editor!
+ */
const unsigned char *UI_ThemeGetColorPtr(struct bTheme *btheme, int spacetype, int colorid);
void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], const char axis);
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 0d18eedeac9..8208f8daf5d 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -17,8 +17,8 @@
/** \file
* \ingroup editorui
*
- * API for simple creation of tree UIs supporting advanced features.
- * https://wiki.blender.org/wiki/Source/Interface/Views
+ * API for simple creation of tree UIs supporting typically needed features.
+ * https://wiki.blender.org/wiki/Source/Interface/Views/Tree_Views
*/
#pragma once
@@ -36,7 +36,6 @@
#include "UI_resources.h"
struct bContext;
-struct PointerRNA;
struct uiBlock;
struct uiBut;
struct uiButTreeRow;
@@ -53,14 +52,17 @@ class AbstractTreeViewItemDragController;
/* ---------------------------------------------------------------------- */
/** \name Tree-View Item Container
+ *
+ * Base class for tree-view and tree-view items, so both can contain children.
* \{ */
/**
- * Helper base class to expose common child-item data and functionality to both #AbstractTreeView
- * and #AbstractTreeViewItem.
+ * Both the tree-view (as the root of the tree) and the items can have children. This is the base
+ * class for both, to store and manage child items. Children are owned by their parent container
+ * (tree-view or item).
*
- * That means this type can be used whenever either a #AbstractTreeView or a
- * #AbstractTreeViewItem is needed.
+ * That means this type can be used whenever either an #AbstractTreeView or an
+ * #AbstractTreeViewItem is needed, but the #TreeViewOrItem alias is a better name to use then.
*/
class TreeViewItemContainer {
friend class AbstractTreeView;
@@ -112,37 +114,10 @@ class TreeViewItemContainer {
ENUM_OPERATORS(TreeViewItemContainer::IterOptions,
TreeViewItemContainer::IterOptions::SkipCollapsed);
-/** \} */
-
-/* ---------------------------------------------------------------------- */
-/** \name Tree-View Builders
- * \{ */
-
-class TreeViewBuilder {
- uiBlock &block_;
-
- public:
- TreeViewBuilder(uiBlock &block);
-
- void build_tree_view(AbstractTreeView &tree_view);
-};
-
-class TreeViewLayoutBuilder {
- uiBlock &block_;
-
- friend TreeViewBuilder;
-
- public:
- void build_row(AbstractTreeViewItem &item) const;
- uiBlock &block() const;
- uiLayout *current_layout() const;
-
- private:
- /* Created through #TreeViewBuilder. */
- TreeViewLayoutBuilder(uiBlock &block);
-
- static void polish_layout(const uiBlock &block);
-};
+/** The container class is the base for both the tree-view and the items. This alias gives it a
+ * clearer name for handles that accept both. Use whenever something wants to act on child-items,
+ * irrespective of if they are stored at root level or as children of some other item. */
+using TreeViewOrItem = TreeViewItemContainer;
/** \} */
@@ -151,8 +126,8 @@ class TreeViewLayoutBuilder {
* \{ */
class AbstractTreeView : public TreeViewItemContainer {
- friend AbstractTreeViewItem;
- friend TreeViewBuilder;
+ friend class AbstractTreeViewItem;
+ friend class TreeViewBuilder;
/**
* Only one item can be renamed at a time. So the tree is informed about the renaming state to
@@ -169,15 +144,16 @@ class AbstractTreeView : public TreeViewItemContainer {
/** Only one item can be renamed at a time. */
bool is_renaming() const;
+
+ protected:
+ virtual void build_tree() = 0;
+
/**
* Check if the tree is fully (re-)constructed. That means, both #build_tree() and
* #update_from_old() have finished.
*/
bool is_reconstructed() const;
- protected:
- virtual void build_tree() = 0;
-
private:
/**
* Match the tree-view against an earlier version of itself (if any) and copy the old UI state
@@ -185,10 +161,10 @@ class AbstractTreeView : public TreeViewItemContainer {
* #AbstractTreeViewItem.update_from_old().
*/
void update_from_old(uiBlock &new_block);
- static void update_children_from_old_recursive(const TreeViewItemContainer &new_items,
- const TreeViewItemContainer &old_items);
+ static void update_children_from_old_recursive(const TreeViewOrItem &new_items,
+ const TreeViewOrItem &old_items);
static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item,
- const TreeViewItemContainer &items);
+ const TreeViewOrItem &items);
/**
* Items may want to do additional work when state changes. But these state changes can only be
@@ -196,7 +172,6 @@ class AbstractTreeView : public TreeViewItemContainer {
* the actual state changes are done in a delayed manner through this function.
*/
void change_state_delayed();
- void build_layout_from_tree(const TreeViewLayoutBuilder &builder);
};
/** \} */
@@ -215,21 +190,18 @@ class AbstractTreeView : public TreeViewItemContainer {
class AbstractTreeViewItem : public TreeViewItemContainer {
friend class AbstractTreeView;
friend class TreeViewLayoutBuilder;
-
- public:
- using IsActiveFn = std::function<bool()>;
+ /* Higher-level API. */
+ friend class TreeViewItemAPIWrapper;
private:
bool is_open_ = false;
bool is_active_ = false;
bool is_renaming_ = false;
- IsActiveFn is_active_fn_;
-
protected:
- /** This label is used for identifying an item (together with its parent's labels). */
+ /** This label is used for identifying an item within its parent. */
std::string label_{};
- /** Every item gets a button of type during the layout building #UI_BTYPE_TREEROW. */
+ /** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */
uiButTreeRow *tree_row_but_ = nullptr;
public:
@@ -238,33 +210,59 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
virtual void build_row(uiLayout &row) = 0;
virtual void build_context_menu(bContext &C, uiLayout &column) const;
+ AbstractTreeView &get_tree_view() const;
+
+ void begin_renaming();
+ void toggle_collapsed();
+ void set_collapsed(bool collapsed);
+ /**
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_collapsed() const;
+ /**
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_active() const;
+
+ protected:
+ /**
+ * Called when the items state changes from inactive to active.
+ */
virtual void on_activate();
/**
- * Set a custom callback to check if this item should be active. There's a version without
- * arguments for checking if the item is currently in an active state.
+ * If the result is not empty, it controls whether the item should be active or not,
+ * usually depending on the data that the view represents.
*/
- virtual void is_active(IsActiveFn is_active_fn);
+ virtual std::optional<bool> should_be_active() const;
/**
* Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if
* another item is already being renamed.
*/
- virtual bool can_rename() const;
+ virtual bool supports_renaming() const;
/**
* Try renaming the item, or the data it represents. Can assume
- * #AbstractTreeViewItem::can_rename() returned true. Sub-classes that override this should
- * usually call this, unless they have a custom #AbstractTreeViewItem.matches().
+ * #AbstractTreeViewItem::supports_renaming() returned true. Sub-classes that override this
+ * should usually call this, unless they have a custom #AbstractTreeViewItem.matches().
*
* \return True if the renaming was successful.
*/
virtual bool rename(StringRefNull new_name);
/**
+ * Return whether the item can be collapsed. Used to disable collapsing for items with children.
+ */
+ virtual bool supports_collapsing() const;
+
+ /**
* Copy persistent state (e.g. is-collapsed flag, selection, etc.) from a matching item of
* the last redraw to this item. If sub-classes introduce more advanced state they should
* override this and make it update their state accordingly.
*/
virtual void update_from_old(const AbstractTreeViewItem &old);
+
/**
* Compare this item to \a other to check if they represent the same data.
* Used to recognize an item from a previous redraw, to be able to keep its state (e.g.
@@ -288,47 +286,28 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
*/
virtual std::unique_ptr<AbstractTreeViewItemDropController> create_drop_controller() const;
- void begin_renaming();
- void end_renaming();
-
- AbstractTreeView &get_tree_view() const;
- int count_parents() const;
- void deactivate();
/**
- * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
- * can't be sure about the item state.
+ * Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate()
+ * function and ensures this item's parents are not collapsed (so the item is visible).
+ * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
+ * actual item state is unknown, possibly calling state-change update functions incorrectly.
*/
- bool is_active() const;
+ void activate();
+ void deactivate();
+
/**
* Can be called from the #AbstractTreeViewItem::build_row() implementation, but not earlier. The
* hovered state can't be queried reliably otherwise.
* Note that this does a linear lookup in the old block, so isn't too great performance-wise.
*/
bool is_hovered() const;
- void toggle_collapsed();
- /**
- * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
- * can't be sure about the item state.
- */
- bool is_collapsed() const;
- void set_collapsed(bool collapsed);
bool is_collapsible() const;
bool is_renaming() const;
void ensure_parents_uncollapsed();
- bool matches_including_parents(const AbstractTreeViewItem &other) const;
uiButTreeRow *tree_row_button();
- protected:
- /**
- * Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate()
- * function and ensures this item's parents are not collapsed (so the item is visible).
- * Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
- * actual item state is unknown, possibly calling state-change update functions incorrectly.
- */
- void activate();
-
private:
static void rename_button_fn(bContext *, void *, char *);
static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but);
@@ -338,13 +317,16 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
/** See #AbstractTreeView::change_state_delayed() */
void change_state_delayed();
+ void end_renaming();
void add_treerow_button(uiBlock &block);
void add_indent(uiLayout &row) const;
void add_collapse_chevron(uiBlock &block) const;
void add_rename_button(uiLayout &row);
+ bool matches_including_parents(const AbstractTreeViewItem &other) const;
bool has_active_child() const;
+ int count_parents() const;
};
/** \} */
@@ -358,11 +340,18 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* custom implementation of #AbstractTreeViewItem::create_drag_controller().
*/
class AbstractTreeViewItemDragController {
+ protected:
+ AbstractTreeView &tree_view_;
+
public:
+ AbstractTreeViewItemDragController(AbstractTreeView &tree_view);
virtual ~AbstractTreeViewItemDragController() = default;
virtual int get_drag_type() const = 0;
virtual void *create_drag_data() const = 0;
+ virtual void on_drag_start();
+
+ template<class TreeViewType> inline TreeViewType &tree_view() const;
};
/**
@@ -398,7 +387,7 @@ class AbstractTreeViewItemDropController {
* Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
* controller is for.
*/
- virtual bool on_drop(const wmDrag &drag) = 0;
+ virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0;
template<class TreeViewType> inline TreeViewType &tree_view() const;
};
@@ -416,6 +405,7 @@ class AbstractTreeViewItemDropController {
*/
class BasicTreeViewItem : public AbstractTreeViewItem {
public:
+ using IsActiveFn = std::function<bool()>;
using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>;
BIFIconID icon;
@@ -423,7 +413,11 @@ class BasicTreeViewItem : public AbstractTreeViewItem {
void build_row(uiLayout &row) override;
void add_label(uiLayout &layout, StringRefNull label_override = "");
- void on_activate(ActivateFn fn);
+ void set_on_activate_fn(ActivateFn fn);
+ /**
+ * Set a custom callback to check if this item should be active.
+ */
+ void set_is_active_fn(IsActiveFn fn);
protected:
/**
@@ -433,15 +427,33 @@ class BasicTreeViewItem : public AbstractTreeViewItem {
*/
ActivateFn activate_fn_;
+ IsActiveFn is_active_fn_;
+
private:
static void tree_row_click_fn(struct bContext *C, void *arg1, void *arg2);
+ std::optional<bool> should_be_active() const override;
void on_activate() override;
};
/** \} */
/* ---------------------------------------------------------------------- */
+/** \name Tree-View Builder
+ * \{ */
+
+class TreeViewBuilder {
+ uiBlock &block_;
+
+ public:
+ TreeViewBuilder(uiBlock &block);
+
+ void build_tree_view(AbstractTreeView &tree_view);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
template<class ItemT, typename... Args>
inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
@@ -453,6 +465,13 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
}
+template<class TreeViewType> TreeViewType &AbstractTreeViewItemDragController::tree_view() const
+{
+ static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
+ "Type must derive from and implement the AbstractTreeView interface");
+ return static_cast<TreeViewType &>(tree_view_);
+}
+
template<class TreeViewType> TreeViewType &AbstractTreeViewItemDropController::tree_view() const
{
static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 122e5a7d839..37246c2fe8f 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -118,21 +118,46 @@ typedef struct View2DScrollers View2DScrollers;
/* ----------------------------------------- */
/* Prototypes: */
-/* refresh and validation (of view rects) */
+/**
+ * Refresh and validation (of view rects).
+ *
+ * Initialize all relevant View2D data (including view rects if first time)
+ * and/or refresh mask sizes after view resize.
+ *
+ * - For some of these presets, it is expected that the region will have defined some
+ * additional settings necessary for the customization of the 2D viewport to its requirements
+ * - This function should only be called from region init() callbacks, where it is expected that
+ * this is called before #UI_view2d_size_update(),
+ * as this one checks that the rects are properly initialized.
+ */
void UI_view2d_region_reinit(struct View2D *v2d, short type, int winx, int winy);
void UI_view2d_curRect_validate(struct View2D *v2d);
+/**
+ * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot).
+ * This does not take into account if zooming the view on an axis
+ * will improve the view (if allowed).
+ */
void UI_view2d_curRect_reset(struct View2D *v2d);
bool UI_view2d_area_supports_sync(struct ScrArea *area);
+/**
+ * Called by menus to activate it, or by view2d operators
+ * to make sure 'related' views stay in synchrony.
+ */
void UI_view2d_sync(struct bScreen *screen, struct ScrArea *area, struct View2D *v2dcur, int flag);
-/* Perform all required updates after `v2d->cur` as been modified.
+/**
+ * Perform all required updates after `v2d->cur` as been modified.
* This includes like validation view validation (#UI_view2d_curRect_validate).
*
- * Current intent is to use it from user code, such as view navigation and zoom operations. */
+ * Current intent is to use it from user code, such as view navigation and zoom operations.
+ */
void UI_view2d_curRect_changed(const struct bContext *C, struct View2D *v2d);
void UI_view2d_totRect_set(struct View2D *v2d, int width, int height);
+/**
+ * Change the size of the maximum viewable area (i.e. 'tot' rect).
+ */
void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize);
void UI_view2d_mask_from_win(const struct View2D *v2d, struct rcti *r_mask);
@@ -140,16 +165,40 @@ void UI_view2d_mask_from_win(const struct View2D *v2d, struct rcti *r_mask);
void UI_view2d_zoom_cache_reset(void);
/* view matrix operations */
+/**
+ * Set view matrices to use 'cur' rect as viewing frame for View2D drawing.
+ */
void UI_view2d_view_ortho(const struct View2D *v2d);
+/**
+ * Set view matrices to only use one axis of 'cur' only
+ *
+ * \param xaxis: if non-zero, only use cur x-axis,
+ * otherwise use cur-yaxis (mostly this will be used for x).
+ */
void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, const bool xaxis);
+/**
+ * Restore view matrices after drawing.
+ */
void UI_view2d_view_restore(const struct bContext *C);
/* grid drawing */
+
+/**
+ * Draw a multi-level grid in given 2d-region.
+ */
void UI_view2d_multi_grid_draw(
const struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
+/**
+ * Draw a multi-level grid of dots, with a dynamic number of levels based on the fading.
+ *
+ * \param grid_color_id: The theme color used for the points. Faded dynamically based on zoom.
+ * \param min_step: The base size of the grid. At different zoom levels, the visible grid may have
+ * a larger step size.
+ * \param grid_levels: The maximum grid depth. Larger grid levels will subdivide the grid more.
+ */
void UI_view2d_dot_grid_draw(const struct View2D *v2d,
int grid_color_id,
- float step,
+ float min_step,
int grid_levels);
void UI_view2d_draw_lines_y__values(const struct View2D *v2d);
@@ -171,7 +220,9 @@ float UI_view2d_grid_resolution_x__frames_or_seconds(const struct View2D *v2d,
bool display_seconds);
float UI_view2d_grid_resolution_y__values(const struct View2D *v2d);
-/* scale indicator text drawing */
+/**
+ * Scale indicator text drawing.
+ */
void UI_view2d_draw_scale_y__values(const struct ARegion *region,
const struct View2D *v2d,
const struct rcti *rect,
@@ -193,25 +244,52 @@ void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *region,
bool display_seconds,
int colorid);
-/* scrollbar drawing */
+/* Scroll-bar drawing. */
+
+/**
+ * Calculate relevant scroller properties.
+ */
void UI_view2d_scrollers_calc(struct View2D *v2d,
const struct rcti *mask_custom,
struct View2DScrollers *r_scrollers);
+/**
+ * Draw scroll-bars in the given 2D-region.
+ */
void UI_view2d_scrollers_draw(struct View2D *v2d, const struct rcti *mask_custom);
-/* list view tools */
+/* List view tools. */
+
+/**
+ * Get the 'cell' (row, column) that the given 2D-view coordinates
+ * (i.e. in 'tot' rect space) lie in.
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
+ * \param r_column, r_row: The 'coordinates' of the relevant 'cell'.
+ */
void UI_view2d_listview_view_to_cell(float columnwidth,
float rowheight,
float startx,
float starty,
float viewx,
float viewy,
- int *column,
- int *row);
+ int *r_column,
+ int *r_row);
+
+/* Coordinate conversion. */
-/* coordinate conversion */
float UI_view2d_region_to_view_x(const struct View2D *v2d, float x);
float UI_view2d_region_to_view_y(const struct View2D *v2d, float y);
+/**
+ * Convert from screen/region space to 2d-View space
+ *
+ * \param x, y: coordinates to convert
+ * \param r_view_x, r_view_y: resultant coordinates
+ */
void UI_view2d_region_to_view(
const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL();
void UI_view2d_region_to_view_rctf(const struct View2D *v2d,
@@ -220,9 +298,24 @@ void UI_view2d_region_to_view_rctf(const struct View2D *v2d,
float UI_view2d_view_to_region_x(const struct View2D *v2d, float x);
float UI_view2d_view_to_region_y(const struct View2D *v2d, float y);
+/**
+ * Convert from 2d-View space to screen/region space
+ * \note Coordinates are clamped to lie within bounds of region
+ *
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
+ */
bool UI_view2d_view_to_region_clip(
const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
+/**
+ * Convert from 2d-view space to screen/region space
+ *
+ * \note Coordinates are NOT clamped to lie within bounds of region.
+ *
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
+ */
void UI_view2d_view_to_region(
const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
void UI_view2d_view_to_region_fl(const struct View2D *v2d,
@@ -238,21 +331,64 @@ bool UI_view2d_view_to_region_rcti_clip(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
-/* utilities */
+/* Utilities. */
+
+/**
+ * View2D data by default resides in region, so get from region stored in context.
+ */
struct View2D *UI_view2d_fromcontext(const struct bContext *C);
+/**
+ * Same as above, but it returns region-window. Utility for pull-downs or buttons.
+ */
struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C);
+/**
+ * Get scrollbar sizes of the current 2D view.
+ * The size will be zero if the view has its scrollbars disabled.
+ */
void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_y);
+/**
+ * Calculate the scale per-axis of the drawing-area
+ *
+ * Is used to inverse correct drawing of icons, etc. that need to follow view
+ * but not be affected by scale
+ *
+ * \param r_x, r_y: scale on each axis
+ */
void UI_view2d_scale_get(const struct View2D *v2d, float *r_x, float *r_y);
float UI_view2d_scale_get_x(const struct View2D *v2d);
float UI_view2d_scale_get_y(const struct View2D *v2d);
+/**
+ * Same as `UI_view2d_scale_get() - 1.0f / x, y`.
+ */
void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y);
+/**
+ * Simple functions for consistent center offset access.
+ * Used by node editor to shift view center for each individual node tree.
+ */
void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_center_set(struct View2D *v2d, float x, float y);
+/**
+ * Simple pan function
+ * (0.0, 0.0) bottom left
+ * (0.5, 0.5) center
+ * (1.0, 1.0) top right.
+ */
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac);
+/**
+ * Check if mouse is within scrollers
+ *
+ * \param xy: Mouse coordinates in screen (not region) space.
+ * \param r_scroll: Return argument for the mapped view2d scroll flag.
+ *
+ * \return appropriate code for match.
+ * - 'h' = in horizontal scroller.
+ * - 'v' = in vertical scroller.
+ * - 0 = not in scroller.
+ */
char UI_view2d_mouse_in_scrollers_ex(const struct ARegion *region,
const struct View2D *v2d,
const int xy[2],
@@ -268,13 +404,18 @@ char UI_view2d_rect_in_scrollers(const struct ARegion *region,
const struct View2D *v2d,
const struct rcti *rect) ATTR_NONNULL(1, 2, 3);
-/* cached text drawing in v2d, to allow pixel-aligned draw as post process */
+/**
+ * Cached text drawing in v2d, to allow pixel-aligned draw as post process.
+ */
void UI_view2d_text_cache_add(struct View2D *v2d,
float x,
float y,
const char *str,
size_t str_len,
const unsigned char col[4]);
+/**
+ * No clip (yet).
+ */
void UI_view2d_text_cache_add_rectf(struct View2D *v2d,
const struct rctf *rect_view,
const char *str,
@@ -282,10 +423,15 @@ void UI_view2d_text_cache_add_rectf(struct View2D *v2d,
const unsigned char col[4]);
void UI_view2d_text_cache_draw(struct ARegion *region);
-/* operators */
+/* Operators. */
+
void ED_operatortypes_view2d(void);
void ED_keymap_view2d(struct wmKeyConfig *keyconf);
+/**
+ * Will start timer if appropriate.
+ * the arguments are the desired situation.
+ */
void UI_view2d_smooth_view(struct bContext *C,
struct ARegion *region,
const struct rctf *cur,
@@ -294,13 +440,16 @@ void UI_view2d_smooth_view(struct bContext *C,
#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#define UI_TIME_SCRUB_MARGIN_Y (23 * UI_DPI_FAC)
-/* Gizmo Types */
+/* Gizmo Types. */
/* view2d_gizmo_navigate.c */
-/* Caller passes in own idname. */
+
+/**
+ * Caller defines the name for gizmo group.
+ */
void VIEW2D_GGT_navigate_impl(struct wmGizmoGroupType *gzgt, const char *idname);
-/* Edge pan */
+/* Edge pan. */
/**
* Custom-data for view panning operators.
@@ -361,11 +510,15 @@ void UI_view2d_edge_pan_init(struct bContext *C,
void UI_view2d_edge_pan_reset(struct View2DEdgePanData *vpd);
-/* Apply transform to view (i.e. adjust 'cur' rect). */
+/**
+ * Apply transform to view (i.e. adjust 'cur' rect).
+ */
void UI_view2d_edge_pan_apply(struct bContext *C, struct View2DEdgePanData *vpd, const int xy[2])
ATTR_NONNULL(1, 2, 3);
-/* Apply transform to view using mouse events. */
+/**
+ * Apply transform to view using mouse events.
+ */
void UI_view2d_edge_pan_apply_event(struct bContext *C,
struct View2DEdgePanData *vpd,
const struct wmEvent *event);
@@ -382,7 +535,9 @@ void UI_view2d_edge_pan_operator_properties_ex(struct wmOperatorType *ot,
float delay,
float zoom_influence);
-/* Initialize panning data with operator settings. */
+/**
+ * Initialize panning data with operator settings.
+ */
void UI_view2d_edge_pan_operator_init(struct bContext *C,
struct View2DEdgePanData *vpd,
struct wmOperator *op);
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 2a8f40b2631..bc3075f9de8 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -73,7 +73,7 @@ set(SRC
interface_template_asset_view.cc
interface_template_list.cc
interface_template_attribute_search.cc
- interface_template_search_menu.c
+ interface_template_search_menu.cc
interface_template_search_operator.c
interface_templates.c
interface_undo.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index c59c2d5d517..df508b87ce4 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -25,7 +25,7 @@
#include <float.h>
#include <limits.h>
#include <math.h>
-#include <stddef.h> /* offsetof() */
+#include <stddef.h> /* `offsetof()` */
#include <string.h>
#include "MEM_guardedalloc.h"
@@ -37,6 +37,7 @@
#include "DNA_workspace_types.h"
#include "BLI_alloca.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
@@ -201,7 +202,6 @@ float ui_block_to_window_scale(const ARegion *region, uiBlock *block)
return max_y - min_y;
}
-/* for mouse cursor */
void ui_window_to_block_fl(const ARegion *region, uiBlock *block, float *r_x, float *r_y)
{
const int getsizex = BLI_rcti_size_x(&region->winrct) + 1;
@@ -355,10 +355,6 @@ static void ui_update_window_matrix(const wmWindow *window, const ARegion *regio
}
}
-/**
- * Popups will add a margin to #ARegion.winrct for shadow,
- * for interactivity (point-inside tests for eg), we want the winrct without the margin added.
- */
void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect)
{
uiBlock *block = region->uiblocks.first;
@@ -599,7 +595,6 @@ static void ui_block_bounds_calc_popup(
}
}
-/* used for various cases */
void UI_block_bounds_set_normal(uiBlock *block, int addval)
{
if (block == NULL) {
@@ -610,14 +605,12 @@ void UI_block_bounds_set_normal(uiBlock *block, int addval)
block->bounds_type = UI_BLOCK_BOUNDS;
}
-/* Used for pull-downs. */
void UI_block_bounds_set_text(uiBlock *block, int addval)
{
block->bounds = addval;
block->bounds_type = UI_BLOCK_BOUNDS_TEXT;
}
-/* used for block popups */
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
{
block->bounds = addval;
@@ -632,7 +625,6 @@ void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offs
}
}
-/* used for menu popups */
void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offset[2])
{
block->bounds = addval;
@@ -645,7 +637,6 @@ void UI_block_bounds_set_menu(uiBlock *block, int addval, const int bounds_offse
}
}
-/* used for centered popups, i.e. splash */
void UI_block_bounds_set_centered(uiBlock *block, int addval)
{
block->bounds = addval;
@@ -987,11 +978,6 @@ static bool ui_but_update_from_old_block(const bContext *C,
return found_active;
}
-/**
- * Needed for temporarily rename buttons, such as in outliner or file-select,
- * they should keep calling #uiDefBut to keep them alive.
- * \return false when button removed.
- */
bool UI_but_active_only_ex(
const bContext *C, ARegion *region, uiBlock *block, uiBut *but, const bool remove_on_failure)
{
@@ -1039,10 +1025,6 @@ bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBu
return UI_but_active_only_ex(C, region, block, but, true);
}
-/**
- * \warning This must run after other handlers have been added,
- * otherwise the handler won't be removed, see: T71112.
- */
bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, uiBlock *block)
{
/* Running this command before end-block has run, means buttons that open menus
@@ -1073,7 +1055,6 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, ui
return done;
}
-/* simulate button click */
void UI_but_execute(const bContext *C, ARegion *region, uiBut *but)
{
void *active_back;
@@ -1186,9 +1167,6 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
}
}
-/* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR'
- * since this is really long its unlikely to be an issue,
- * but this could be supported */
void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip)
{
if (do_strip && (but->flag & UI_BUT_HAS_SEP_CHAR)) {
@@ -1855,11 +1833,6 @@ static void ui_but_validate(const uiBut *but)
}
#endif
-/**
- * Check if the operator \a ot poll is successful with the context given by \a but (optionally).
- * \param but: The button that might store context. Can be NULL for convenience (e.g. if there is
- * no button to take context from, but we still want to poll the operator).
- */
bool ui_but_context_poll_operator_ex(bContext *C,
const uiBut *but,
const wmOperatorCallParams *optype_params)
@@ -2015,7 +1988,6 @@ static bool ui_but_pixelrect_in_view(const ARegion *region, const rcti *rect)
return BLI_rcti_isect(&region->winrct, &rect_winspace, NULL);
}
-/* uses local copy of style, to scale things down, and allow widgets to change stuff */
void UI_block_draw(const bContext *C, uiBlock *block)
{
uiStyle style = *UI_style_get_dpi(); /* XXX pass on as arg */
@@ -2061,24 +2033,11 @@ void UI_block_draw(const bContext *C, uiBlock *block)
ui_draw_menu_back(&style, block, &rect);
}
else if (block->panel) {
- bool show_background = region->alignment != RGN_ALIGN_FLOAT;
- if (show_background) {
- if (block->panel->type && (block->panel->type->flag & PANEL_TYPE_NO_HEADER)) {
- if (region->regiontype == RGN_TYPE_TOOLS) {
- /* We never want a background around active tools. */
- show_background = false;
- }
- else {
- /* Without a header there is no background except for region overlap. */
- show_background = region->overlap != 0;
- }
- }
- }
ui_draw_aligned_panel(&style,
block,
&rect,
UI_panel_category_is_visible(region),
- show_background,
+ UI_panel_should_show_background(region, block->panel->type),
region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE);
}
@@ -2150,11 +2109,6 @@ void UI_region_message_subscribe(ARegion *region, struct wmMsgBus *mbus)
/* ************* EVENTS ************* */
-/**
- * Check if the button is pushed, this is only meaningful for some button types.
- *
- * \return (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOTHING)
- */
int ui_but_is_pushed_ex(uiBut *but, double *value)
{
int is_push = 0;
@@ -2290,7 +2244,6 @@ void UI_block_lock_clear(uiBlock *block)
* this either works with the pointed to data, or can work with
* an edit override pointer while dragging for example */
-/* for buttons pointing to color for example */
void ui_but_v3_get(uiBut *but, float vec[3])
{
if (but->editvec) {
@@ -2338,7 +2291,6 @@ void ui_but_v3_get(uiBut *but, float vec[3])
}
}
-/* for buttons pointing to color for example */
void ui_but_v3_set(uiBut *but, const float vec[3])
{
if (but->editvec) {
@@ -2450,9 +2402,6 @@ bool ui_but_is_unit(const uiBut *but)
return true;
}
-/**
- * Check if this button is similar enough to be grouped with another.
- */
bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b)
{
if (but_a->type != but_b->type) {
@@ -2488,9 +2437,6 @@ bool ui_but_is_rna_valid(uiBut *but)
return false;
}
-/**
- * Checks if the button supports cycling next/previous menu items (ctrl+mouse-wheel).
- */
bool ui_but_supports_cycling(const uiBut *but)
{
return (ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_LISTBOX) ||
@@ -2697,7 +2643,6 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
return BKE_scene_unit_scale(unit, RNA_SUBTYPE_UNIT_VALUE(unit_type), value);
}
-/* str will be overwritten */
void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
{
if (!ui_but_is_unit(but)) {
@@ -2789,12 +2734,6 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
return (float)step_final;
}
-/**
- * \param float_precision: For number buttons the precision
- * to use or -1 to fallback to the button default.
- * \param use_exp_float: Use exponent representation of floats
- * when out of reasonable range (outside of 1e3/1e-3).
- */
void ui_but_string_get_ex(uiBut *but,
char *str,
const size_t maxlen,
@@ -2920,12 +2859,6 @@ void ui_but_string_get(uiBut *but, char *str, const size_t maxlen)
ui_but_string_get_ex(but, str, maxlen, -1, false, NULL);
}
-/**
- * A version of #ui_but_string_get_ex for dynamic buffer sizes
- * (where #ui_but_string_get_max_length returns 0).
- *
- * \param r_str_size: size of the returned string (including terminator).
- */
char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
{
char *str = NULL;
@@ -3284,9 +3217,10 @@ void ui_but_range_set_hard(uiBut *but)
}
}
-/* NOTE: this could be split up into functions which handle arrays and not. */
void ui_but_range_set_soft(uiBut *but)
{
+ /* This could be split up into functions which handle arrays and not. */
+
/* Ideally we would not limit this, but practically it's more than
* enough. Worst case is very long vectors won't use a smart soft-range,
* which isn't so bad. */
@@ -3461,7 +3395,6 @@ static void ui_but_free(const bContext *C, uiBut *but)
MEM_freeN(but);
}
-/* can be called with C==NULL */
void UI_block_free(const bContext *C, uiBlock *block)
{
UI_butstore_clear(block);
@@ -3520,23 +3453,35 @@ void UI_blocklist_draw(const bContext *C, const ListBase *lb)
}
}
-/* can be called with C==NULL */
-void UI_blocklist_free(const bContext *C, ListBase *lb)
+void UI_blocklist_free(const bContext *C, ARegion *region)
{
+ ListBase *lb = &region->uiblocks;
uiBlock *block;
while ((block = BLI_pophead(lb))) {
UI_block_free(C, block);
}
+ if (region->runtime.block_name_map != NULL) {
+ BLI_ghash_free(region->runtime.block_name_map, NULL, NULL);
+ region->runtime.block_name_map = NULL;
+ }
}
-void UI_blocklist_free_inactive(const bContext *C, ListBase *lb)
+void UI_blocklist_free_inactive(const bContext *C, ARegion *region)
{
+ ListBase *lb = &region->uiblocks;
+
LISTBASE_FOREACH_MUTABLE (uiBlock *, block, lb) {
if (!block->handle) {
if (block->active) {
block->active = false;
}
else {
+ if (region->runtime.block_name_map != NULL) {
+ uiBlock *b = BLI_ghash_lookup(region->runtime.block_name_map, block->name);
+ if (b == block) {
+ BLI_ghash_remove(region->runtime.block_name_map, b->name, NULL, NULL);
+ }
+ }
BLI_remlink(lb, block);
UI_block_free(C, block);
}
@@ -3552,7 +3497,10 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
/* each listbase only has one block with this name, free block
* if is already there so it can be rebuilt from scratch */
if (lb) {
- oldblock = BLI_findstring(lb, block->name, offsetof(uiBlock, name));
+ if (region->runtime.block_name_map == NULL) {
+ region->runtime.block_name_map = BLI_ghash_str_new(__func__);
+ }
+ oldblock = (uiBlock *)BLI_ghash_lookup(region->runtime.block_name_map, block->name);
if (oldblock) {
oldblock->active = false;
@@ -3562,6 +3510,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
/* at the beginning of the list! for dynamical menus/blocks */
BLI_addhead(lb, block);
+ BLI_ghash_reinsert(region->runtime.block_name_map, block->name, block, NULL, NULL);
}
block->oldblock = oldblock;
@@ -3633,10 +3582,6 @@ bool UI_block_is_search_only(const uiBlock *block)
return block->flag & UI_BLOCK_SEARCH_ONLY;
}
-/**
- * Use when a block must be searched to give accurate results
- * for the whole region but shouldn't be displayed.
- */
void UI_block_set_search_only(uiBlock *block, bool search_only)
{
SET_FLAG_FROM_TEST(block->flag, search_only, UI_BLOCK_SEARCH_ONLY);
@@ -3977,10 +3922,6 @@ static void ui_but_alloc_info(const eButType type,
alloc_size = sizeof(uiButCurveProfile);
alloc_str = "uiButCurveProfile";
break;
- case UI_BTYPE_DATASETROW:
- alloc_size = sizeof(uiButDatasetRow);
- alloc_str = "uiButDatasetRow";
- break;
case UI_BTYPE_TREEROW:
alloc_size = sizeof(uiButTreeRow);
alloc_str = "uiButTreeRow";
@@ -4012,13 +3953,6 @@ static uiBut *ui_but_alloc(const eButType type)
return MEM_callocN(alloc_size, alloc_str);
}
-/**
- * Reallocate the button (new address is returned) for a new button type.
- * This should generally be avoided and instead the correct type be created right away.
- *
- * \note Only the #uiBut data can be kept. If the old button used a derived type (e.g. #uiButTab),
- * the data that is not inside #uiBut will be lost.
- */
uiBut *ui_but_change_type(uiBut *but, eButType new_type)
{
if (but->type == new_type) {
@@ -4183,7 +4117,6 @@ static uiBut *ui_def_but(uiBlock *block,
UI_BTYPE_BLOCK,
UI_BTYPE_BUT_MENU,
UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_DATASETROW,
UI_BTYPE_TREEROW,
UI_BTYPE_POPOVER)) {
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
@@ -4253,9 +4186,6 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag)
}
}
-/**
- * Avoid using this where possible since it's better not to ask for an icon in the first place.
- */
void ui_def_but_icon_clear(uiBut *but)
{
but->icon = ICON_NONE;
@@ -5309,7 +5239,6 @@ uiBut *uiDefButO(uiBlock *block,
return uiDefButO_ptr(block, type, ot, opcontext, str, x, y, width, height, tip);
}
-/* if a1==1.0 then a2 is an extra icon blending factor (alpha 0.0 - 1.0) */
uiBut *uiDefIconBut(uiBlock *block,
int type,
int retval,
@@ -5689,7 +5618,6 @@ uiBut *uiDefIconButO(uiBlock *block,
return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
}
-/* Button containing both string label and icon */
uiBut *uiDefIconTextBut(uiBlock *block,
int type,
int retval,
@@ -6120,7 +6048,6 @@ void UI_block_direction_set(uiBlock *block, char direction)
block->direction = direction;
}
-/* this call escapes if there's alignment flags */
void UI_block_order_flip(uiBlock *block)
{
float centy, miny = 10000, maxy = -10000;
@@ -6224,19 +6151,12 @@ void UI_but_drag_set_id(uiBut *but, ID *id)
but->dragpoin = (void *)id;
}
-/**
- * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`).
- * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image.
- */
void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
{
but->imb = imb;
but->imb_scale = scale;
}
-/**
- * \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
- */
void UI_but_drag_set_asset(uiBut *but,
const AssetHandle *asset,
const char *path,
@@ -6298,7 +6218,6 @@ void UI_but_drag_set_name(uiBut *but, const char *name)
but->dragpoin = (void *)name;
}
-/* value from button itself */
void UI_but_drag_set_value(uiBut *but)
{
but->dragtype = WM_DRAG_VALUE;
@@ -6561,7 +6480,6 @@ uiBut *uiDefIconMenuBut(uiBlock *block,
return but;
}
-/* Block button containing both string label and icon */
uiBut *uiDefIconTextBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -6590,7 +6508,6 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block,
return but;
}
-/* Block button containing icon */
uiBut *uiDefIconBlockBut(uiBlock *block,
uiBlockCreateFunc func,
void *arg,
@@ -6643,8 +6560,6 @@ uiBut *uiDefKeyevtButS(uiBlock *block,
return but;
}
-/* short pointers hardcoded */
-/* modkeypoin will be set to KM_SHIFT, KM_ALT, KM_CTRL, KM_OSKEY bits */
uiBut *uiDefHotKeyevtButS(uiBlock *block,
int retval,
const char *str,
@@ -6675,8 +6590,6 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block,
return but;
}
-/* arg is pointer to string/name, use UI_but_func_search_set() below to make this work */
-/* here a1 and a2, if set, control thumbnail preview rows/cols */
uiBut *uiDefSearchBut(uiBlock *block,
void *arg,
int retval,
@@ -6702,21 +6615,6 @@ uiBut *uiDefSearchBut(uiBlock *block,
return but;
}
-/**
- * \note The item-pointer (referred to below) is a per search item user pointer
- * passed to #UI_search_item_add (stored in #uiSearchItems.pointers).
- *
- * \param search_create_fn: Function to create the menu.
- * \param search_update_fn: Function to refresh search content after the search text has changed.
- * \param arg: user value.
- * \param free_arg: Set to true if the argument is newly allocated memory for every redraw and
- * should be freed when the button is destroyed.
- * \param search_arg_free_fn: When non-null, use this function to free \a arg.
- * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument.
- * The second argument as the active item-pointer
- * \param active: When non-null, this item-pointer item will be visible and selected,
- * otherwise the first item will be selected.
- */
void UI_but_func_search_set(uiBut *but,
uiButSearchCreateFn search_create_fn,
uiButSearchUpdateFn search_update_fn,
@@ -6783,10 +6681,6 @@ void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn co
but_search->item_context_menu_fn = context_menu_fn;
}
-/**
- * \param search_sep_string: when not NULL, this string is used as a separator,
- * showing the icon and highlighted text after the last instance of this string.
- */
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
{
uiButSearch *but_search = (uiButSearch *)but;
@@ -6839,7 +6733,7 @@ static void operator_enum_search_update_fn(const struct bContext *C,
StringSearch *search = BLI_string_search_new();
for (const EnumPropertyItem *item = all_items; item->identifier; item++) {
- BLI_string_search_add(search, item->name, (void *)item);
+ BLI_string_search_add(search, item->name, (void *)item, 0);
}
const EnumPropertyItem **filtered_items;
@@ -6883,10 +6777,6 @@ static void operator_enum_search_exec_fn(struct bContext *UNUSED(C), void *but,
}
}
-/**
- * Same parameters as for uiDefSearchBut, with additional operator type and properties,
- * used by callback to call again the right op with the right options (properties values).
- */
uiBut *uiDefSearchButO_ptr(uiBlock *block,
wmOperatorType *ot,
IDProperty *properties,
@@ -6924,15 +6814,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
-void UI_but_datasetrow_indentation_set(uiBut *but, int indentation)
-{
- uiButDatasetRow *but_dataset = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset->indentation = indentation;
- BLI_assert(indentation >= 0);
-}
-
void UI_but_treerow_indentation_set(uiBut *but, int indentation)
{
uiButTreeRow *but_row = (uiButTreeRow *)but;
@@ -6942,46 +6823,11 @@ void UI_but_treerow_indentation_set(uiBut *but, int indentation)
BLI_assert(indentation >= 0);
}
-/**
- * Adds a hint to the button which draws right aligned, grayed out and never clipped.
- */
void UI_but_hint_drawstr_set(uiBut *but, const char *string)
{
ui_but_add_shortcut(but, string, false);
}
-void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset_row->geometry_component_type = geometry_component_type;
-}
-
-void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- but_dataset_row->attribute_domain = attribute_domain;
-}
-
-uint8_t UI_but_datasetrow_component_get(uiBut *but)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- return but_dataset_row->geometry_component_type;
-}
-
-uint8_t UI_but_datasetrow_domain_get(uiBut *but)
-{
- uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
-
- return but_dataset_row->attribute_domain;
-}
-
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
{
but->flag |= UI_BUT_NODE_LINK;
@@ -7008,10 +6854,6 @@ void UI_but_number_precision_set(uiBut *but, float precision)
BLI_assert(precision > -2);
}
-/**
- * push a new event onto event queue to activate the given button
- * (usually a text-field) upon entering a popup
- */
void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
{
wmEvent event;
@@ -7314,7 +7156,6 @@ void UI_init(void)
ui_resources_init();
}
-/* after reading userdef file */
void UI_init_userdef(void)
{
/* Initialize UI variables from values set in the preferences. */
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index 3149675ac04..35af557a560 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -377,13 +377,6 @@ static void ui_block_align_but_to_region(uiBut *but, const ARegion *region)
}
}
-/**
- * Compute the alignment of all 'align groups' of buttons in given block.
- *
- * This is using an order-independent algorithm,
- * i.e. alignment of buttons should be OK regardless of order in which
- * they are added to the block.
- */
void ui_block_align_calc(uiBlock *block, const ARegion *region)
{
int num_buttons = 0;
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 3101b3222c4..1d6623f3490 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -180,10 +180,6 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but)
but->flag = (but->flag & ~flag_copy) | (flag & flag_copy);
}
-/**
- * \a str can be NULL to only perform check if \a but has an expression at all.
- * \return if button has an expression.
- */
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
{
FCurve *fcu;
@@ -241,7 +237,6 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
return false;
}
-/* create new expression for button (i.e. a "scripted driver"), if it can be created... */
bool ui_but_anim_expression_create(uiBut *but, const char *str)
{
bContext *C = but->block->evil_C;
diff --git a/source/blender/editors/interface/interface_button_group.c b/source/blender/editors/interface/interface_button_group.c
index 7054498d469..6449e1eb329 100644
--- a/source/blender/editors/interface/interface_button_group.c
+++ b/source/blender/editors/interface/interface_button_group.c
@@ -28,10 +28,6 @@
/** \name Button Groups
* \{ */
-/**
- * Every function that adds a set of buttons must create another group,
- * then #ui_def_but adds buttons to the current group (the last).
- */
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag)
{
/* Don't create a new group if there is a "lock" on new groups. */
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 72e7203c6ea..190b2d12ed9 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -1242,9 +1242,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
/** \name Panel Context Menu
* \{ */
-/**
- * menu to show when right clicking on the panel header
- */
void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
{
bScreen *screen = CTX_wm_screen(C);
diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc
index 3f5efd187d8..0b774b79a5c 100644
--- a/source/blender/editors/interface/interface_context_path.cc
+++ b/source/blender/editors/interface/interface_context_path.cc
@@ -80,6 +80,6 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path)
}
}
-} // namespace blender::ui
-
/** \} */
+
+} // namespace blender::ui
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index e45a5fc61c6..285c82b0fb3 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -194,8 +194,6 @@ void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const flo
/* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
-/* based on UI_draw_roundbox_gl_mode,
- * check on making a version which allows us to skip some sides */
void ui_draw_but_TAB_outline(const rcti *rect,
float rad,
uchar highlight[3],
@@ -348,14 +346,6 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
#endif
}
-/**
- * Draw title and text safe areas.
- *
- * \note This function is to be used with the 2D dashed shader enabled.
- *
- * \param pos: is a #PRIM_FLOAT, 2, #GPU_FETCH_FLOAT vertex attribute.
- * \param x1, x2, y1, y2: The offsets for the view, not the zones.
- */
void UI_draw_safe_areas(uint pos,
const rctf *rect,
const float title_aspect[2],
@@ -1351,7 +1341,10 @@ void ui_draw_but_COLORBAND(uiBut *but, const uiWidgetColors *UNUSED(wcol), const
immUnbindProgram();
}
-void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
+void ui_draw_but_UNITVEC(uiBut *but,
+ const uiWidgetColors *wcol,
+ const rcti *rect,
+ const float radius)
{
/* sphere color */
const float diffuse[3] = {1.0f, 1.0f, 1.0f};
@@ -1368,7 +1361,7 @@ void ui_draw_but_UNITVEC(uiBut *but, const uiWidgetColors *wcol, const rcti *rec
.ymax = rect->ymax,
},
true,
- 5.0f,
+ radius,
wcol->inner,
255);
@@ -1750,9 +1743,6 @@ static bool point_draw_handles(CurveProfilePoint *point)
ELEM(point->flag, PROF_H1_SELECT, PROF_H2_SELECT);
}
-/**
- * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE.
- */
void ui_draw_but_CURVEPROFILE(ARegion *region,
uiBut *but,
const uiWidgetColors *wcol,
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 395ecc77ef4..27fa2e5a22f 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -103,8 +103,10 @@ wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
/* -------------------------------------------------------------------- */
/* Utility Functions
*/
+
/** \name Generic Shared Functions
* \{ */
+
static void eyedropper_draw_cursor_text_ex(const int x, const int y, const char *name)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
@@ -141,15 +143,6 @@ void eyedropper_draw_cursor_text_region(const int x, const int y, const char *na
eyedropper_draw_cursor_text_ex(x, y, name);
}
-/**
- * Utility to retrieve a button representing a RNA property that is currently under the cursor.
- *
- * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
- * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
- * upon to provide this information, as it is not updated until the operator finishes.
- *
- * \return A button under the mouse which relates to some RNA Property, or NULL
- */
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index c3633e11f83..0ac6ea4021b 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -268,28 +268,28 @@ static bool eyedropper_cryptomatte_sample_fl(
return false;
}
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (!ar) {
+ ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (!region) {
return false;
}
- int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
+ int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
float fpos[2] = {-1.0f, -1.0};
switch (sa->spacetype) {
case SPACE_IMAGE: {
SpaceImage *sima = sa->spacedata.first;
- ED_space_image_get_position(sima, ar, mval, fpos);
+ ED_space_image_get_position(sima, region, mval, fpos);
break;
}
case SPACE_NODE: {
Main *bmain = CTX_data_main(C);
SpaceNode *snode = sa->spacedata.first;
- ED_space_node_get_position(bmain, snode, ar, mval, fpos);
+ ED_space_node_get_position(bmain, snode, region, mval, fpos);
break;
}
case SPACE_CLIP: {
SpaceClip *sc = sa->spacedata.first;
- ED_space_clip_get_position(sc, ar, mval, fpos);
+ ED_space_clip_get_position(sc, region, mval, fpos);
break;
}
default: {
@@ -322,13 +322,6 @@ static bool eyedropper_cryptomatte_sample_fl(
return false;
}
-/**
- * \brief get the color from the screen.
- *
- * Special check for image or nodes where we MAY have HDR pixels which don't display.
- *
- * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
- */
void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
{
/* we could use some clever */
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h
index f9f3fcfb5d1..17bb78a7861 100644
--- a/source/blender/editors/interface/interface_eyedropper_intern.h
+++ b/source/blender/editors/interface/interface_eyedropper_intern.h
@@ -23,8 +23,18 @@
#pragma once
/* interface_eyedropper.c */
+
void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name);
void eyedropper_draw_cursor_text_region(const int x, const int y, const char *name);
+/**
+ * Utility to retrieve a button representing a RNA property that is currently under the cursor.
+ *
+ * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
+ * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
+ * upon to provide this information, as it is not updated until the operator finishes.
+ *
+ * \return A button under the mouse which relates to some RNA Property, or NULL
+ */
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event);
void datadropper_win_area_find(const struct bContext *C,
const int mval[2],
@@ -33,6 +43,14 @@ void datadropper_win_area_find(const struct bContext *C,
struct ScrArea **r_area);
/* interface_eyedropper_color.c (expose for color-band picker) */
+
+/**
+ * \brief get the color from the screen.
+ *
+ * Special check for image or nodes where we MAY have HDR pixels which don't display.
+ *
+ * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
+ */
void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]);
/* Used for most eye-dropper operators. */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 8a744a1edbe..d720b52a59e 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -439,11 +439,11 @@ typedef struct uiHandleButtonData {
float ungrab_mval[2];
#endif
- /* menu open (watch UI_screen_free_active_but) */
+ /* Menu open, see: #UI_screen_free_active_but_highlight. */
uiPopupBlockHandle *menu;
int menuretval;
- /* search box (watch UI_screen_free_active_but) */
+ /* Search box see: #UI_screen_free_active_but_highlight. */
ARegion *searchbox;
#ifdef USE_KEYNAV_LIMIT
struct uiKeyNavLock searchbox_keynav_state;
@@ -555,7 +555,6 @@ bool ui_but_is_editing(const uiBut *but)
return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING));
}
-/* assumes event type is MOUSEPAN */
void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
{
static int lastdy = 0;
@@ -594,11 +593,6 @@ static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but
(but_a->rnaprop == but_b->rnaprop));
}
-/**
- * Finds the pressed button in an aligned row (typically an expanded enum).
- *
- * \param direction: Use when there may be multiple buttons pressed.
- */
uiBut *ui_but_find_select_in_enum(uiBut *but, int direction)
{
uiBut *but_iter = but;
@@ -1266,12 +1260,22 @@ static void ui_apply_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
{
if (data->str) {
+ /* This is intended to avoid unnecessary updates when the value stays the same, however there
+ * are issues with the current implementation. It does not work with multi-button editing
+ * (T89996) or operator popups where a number button requires an update even if the value is
+ * unchanged (T89996).
+ *
+ * Trying to detect changes at this level is not reliable. Instead it could be done at the
+ * level of RNA update/set, skipping RNA update if RNA set did not change anything, instead
+ * of skipping all button updates. */
+#if 0
double value;
/* Check if the string value is a number and cancel if it's equal to the startvalue. */
if (ui_but_string_eval_number(C, but, data->str, &value) && (value == data->startvalue)) {
data->cancel = true;
return;
}
+#endif
if (ui_but_string_set(C, but, data->str)) {
data->value = ui_but_value_get(but);
@@ -1783,7 +1787,7 @@ static bool ui_but_is_drag_toggle(const uiBut *but)
static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore *selctx_data)
{
- PointerRNA lptr, idptr;
+ PointerRNA lptr;
PropertyRNA *lprop;
bool success = false;
@@ -1817,68 +1821,48 @@ static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore
if (i >= selctx_data->elems_len) {
break;
}
+
+ if (!UI_context_copy_to_selected_check(
+ &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) {
+ selctx_data->elems_len -= 1;
+ i -= 1;
+ continue;
+ }
+
uiSelectContextElem *other = &selctx_data->elems[i];
- /* TODO: de-duplicate copy_to_selected_button. */
- if (link->ptr.data != ptr.data) {
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.owner_id, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ other->ptr = lptr;
+ if (is_array) {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
}
- else {
- lptr = link->ptr;
- lprop = prop;
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
}
-
- /* lptr might not be the same as link->ptr! */
- if ((lptr.data != ptr.data) && (lprop == prop) && RNA_property_editable(&lptr, lprop)) {
- other->ptr = lptr;
- if (is_array) {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
- }
- /* ignored for now */
+ /* ignored for now */
# if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
- }
-# endif
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
}
- else {
- if (rna_type == PROP_FLOAT) {
- other->val_f = RNA_property_float_get(&lptr, lprop);
- }
- else if (rna_type == PROP_INT) {
- other->val_i = RNA_property_int_get(&lptr, lprop);
- }
- /* ignored for now */
-# if 0
- else if (rna_type == PROP_BOOLEAN) {
- other->val_b = RNA_property_boolean_get(&lptr, lprop);
- }
- else if (rna_type == PROP_ENUM) {
- other->val_i = RNA_property_enum_get(&lptr, lprop);
- }
# endif
- }
-
- continue;
+ }
+ else {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get(&lptr, lprop);
}
+ /* ignored for now */
+# if 0
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_ENUM) {
+ other->val_i = RNA_property_enum_get(&lptr, lprop);
+ }
+# endif
}
-
- selctx_data->elems_len -= 1;
- i -= 1;
}
-
success = (selctx_data->elems_len != 0);
}
}
@@ -2334,9 +2318,6 @@ static void ui_apply_but(
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
break;
- case UI_BTYPE_DATASETROW:
- ui_apply_but_ROW(C, block, but, data);
- break;
case UI_BTYPE_TAB:
ui_apply_but_TAB(C, but, data);
break;
@@ -2985,11 +2966,6 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
/** \name Button Text Selection/Editing
* \{ */
-/**
- * Use handling code to set a string for the button. Handles the case where the string is set for a
- * search button while the search menu is open, so the results are updated accordingly.
- * This is basically the same as pasting the string into the button.
- */
void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
{
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
@@ -3555,6 +3531,12 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
if ((ui_searchbox_apply(but, data->searchbox) == false) &&
(ui_searchbox_find_index(data->searchbox, but->editstr) == -1) &&
!but_search->results_are_suggestions) {
+
+ if (but->flag & UI_BUT_VALUE_CLEAR) {
+ /* It is valid for _VALUE_CLEAR flavor to have no active element
+ * (it's a valid way to unlink). */
+ but->editstr[0] = '\0';
+ }
data->cancel = true;
/* ensure menu (popup) too is closed! */
@@ -8012,7 +7994,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_CHECKBOX:
case UI_BTYPE_CHECKBOX_N:
case UI_BTYPE_ROW:
- case UI_BTYPE_DATASETROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
case UI_BTYPE_TREEROW:
@@ -8185,9 +8166,6 @@ static void ui_blocks_set_tooltips(ARegion *region, const bool enable)
}
}
-/**
- * Recreate tool-tip (use to update dynamic tips)
- */
void UI_but_tooltip_refresh(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -8199,10 +8177,6 @@ void UI_but_tooltip_refresh(bContext *C, uiBut *but)
}
}
-/**
- * Removes tool-tip timer from active but
- * (meaning tool-tip is disabled until it's re-enabled again).
- */
void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
@@ -8770,11 +8744,6 @@ uiBut *UI_context_active_but_get(const bContext *C)
return ui_context_button_active(CTX_wm_region(C), NULL);
}
-/*
- * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
- * if set. Does not traverse into parent menus, which may be wanted in some
- * cases.
- */
uiBut *UI_context_active_but_get_respect_menu(const bContext *C)
{
ARegion *region_menu = CTX_wm_menu(C);
@@ -8798,12 +8767,6 @@ uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
return ui_block_find_mouse_over_ex(region, xy, only_clip);
}
-/**
- * Version of #UI_context_active_but_get that also returns RNA property info.
- * Helper function for insert keyframe, reset to default, etc operators.
- *
- * \return active button, NULL if none found or if it doesn't contain valid RNA data.
- */
uiBut *UI_context_active_but_prop_get(const bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
@@ -8879,16 +8842,12 @@ wmOperator *UI_context_active_operator_get(const struct bContext *C)
return NULL;
}
-/**
- * Try to find a search-box region opened from a button in \a button_region.
- */
ARegion *UI_region_searchbox_region_get(const ARegion *button_region)
{
uiBut *but = UI_region_active_but_get(button_region);
return (but != NULL) ? but->active->searchbox : NULL;
}
-/* helper function for insert keyframe, reset to default, etc operators */
void UI_context_update_anim_flag(const bContext *C)
{
Scene *scene = CTX_data_scene(C);
@@ -8937,10 +8896,6 @@ void UI_context_update_anim_flag(const bContext *C)
}
}
-/**
- * In some cases we may want to update the view (#View2D) in-between layout definition and drawing.
- * E.g. to make sure a button is visible while editing.
- */
void ui_but_update_view_for_active(const bContext *C, const uiBlock *block)
{
uiBut *active_but = ui_block_active_but_get(block);
@@ -9000,11 +8955,6 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *reg
return WM_UI_HANDLER_CONTINUE;
}
-/**
- * Exported to interface.c: #UI_but_active_only()
- * \note The region is only for the button.
- * The context needs to be set by the caller.
- */
void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
{
wmWindow *win = CTX_wm_window(C);
@@ -9022,12 +8972,6 @@ void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
ui_do_button(C, but->block, but, &event);
}
-/**
- * Simulate moving the mouse over a button (or navigating to it with arrow keys).
- *
- * exported so menus can start with a highlighted button,
- * even if the mouse isn't over it
- */
void ui_but_activate_over(bContext *C, ARegion *region, uiBut *but)
{
button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
@@ -11267,10 +11211,6 @@ static int ui_handle_menus_recursive(bContext *C,
return retval;
}
-/**
- * Allow setting menu return value from externals.
- * E.g. WM might need to do this for exiting files correctly.
- */
void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable)
{
uiPopupBlockHandle *menu = block->handle;
@@ -11344,8 +11284,7 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
return;
}
- UI_blocklist_free(C, &region->uiblocks);
-
+ UI_blocklist_free(C, region);
bScreen *screen = CTX_wm_screen(C);
if (screen == NULL) {
return;
@@ -11669,8 +11608,19 @@ bool UI_textbutton_activate_but(const bContext *C, uiBut *actbut)
/** \name Public Utilities
* \{ */
-/* is called by notifier */
-void UI_screen_free_active_but(const bContext *C, bScreen *screen)
+void UI_region_free_active_but_all(bContext *C, ARegion *region)
+{
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->active == NULL) {
+ continue;
+ }
+ ui_but_active_free(C, but);
+ }
+ }
+}
+
+void UI_screen_free_active_but_highlight(const bContext *C, bScreen *screen)
{
wmWindow *win = CTX_wm_window(C);
@@ -11704,8 +11654,6 @@ uiBut *UI_but_active_drop_name_button(const bContext *C)
return NULL;
}
-/* returns true if highlighted button allows drop of names */
-/* called in region context */
bool UI_but_active_drop_name(const bContext *C)
{
return UI_but_active_drop_name_button(C) != NULL;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index d0a7716b4dd..ca5d08ba40e 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -830,8 +830,6 @@ static void free_icons_textures(void)
}
}
-/* Reload the textures for internal icons.
- * This function will release the previous textures. */
void UI_icons_reload_internal_textures(void)
{
bTheme *btheme = UI_GetTheme();
@@ -1182,7 +1180,6 @@ static DrawInfo *icon_ensure_drawinfo(Icon *icon)
return di;
}
-/* NOTE:, returns unscaled by DPI. */
int UI_icon_get_width(int icon_id)
{
Icon *icon = BKE_icon_get(icon_id);
@@ -1242,8 +1239,6 @@ void UI_icons_init()
#endif
}
-/* Render size for preview images and icons
- */
int UI_icon_preview_to_render_size(enum eIconSizes size)
{
switch (size) {
@@ -1270,7 +1265,7 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
else if (!prv_img->rect[size]) {
prv_img->w[size] = render_size;
prv_img->h[size] = render_size;
- prv_img->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED);
+ prv_img->flag[size] |= PRV_CHANGED;
prv_img->changed_timestamp[size] = 0;
prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect");
}
@@ -1419,6 +1414,7 @@ static void icon_set_image(const bContext *C,
const bool delay = prv_img->rect[size] != NULL;
icon_create_rect(prv_img, size);
+ prv_img->flag[size] |= PRV_RENDERING;
if (use_job && (!id || BKE_previewimg_id_supports_jobs(id))) {
/* Job (background) version */
@@ -2030,18 +2026,26 @@ static void ui_id_preview_image_render_size(
}
}
-/**
- * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored.
- */
void UI_icon_render_id(
const bContext *C, Scene *scene, ID *id, const enum eIconSizes size, const bool use_job)
{
PreviewImage *pi = BKE_previewimg_id_ensure(id);
-
if (pi == NULL) {
return;
}
+ /* For objects, first try if a preview can created via the object data. */
+ if (GS(id->name) == ID_OB) {
+ Object *ob = (Object *)id;
+ if (ED_preview_id_is_supported(ob->data)) {
+ id = ob->data;
+ }
+ }
+
+ if (!ED_preview_id_is_supported(id)) {
+ return;
+ }
+
ui_id_preview_image_render_size(C, scene, id, pi, size, use_job);
}
@@ -2461,7 +2465,6 @@ int UI_icon_color_from_collection(const Collection *collection)
return icon;
}
-/* draws icon with dpi scale factor */
void UI_icon_draw(float x, float y, int icon_id)
{
UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 8c33e2d1cc9..dc8744aaae9 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -351,15 +351,6 @@ typedef struct uiButProgressbar {
float progress;
} uiButProgressbar;
-/** Derived struct for #UI_BTYPE_DATASETROW. */
-typedef struct uiButDatasetRow {
- uiBut but;
-
- uint8_t geometry_component_type;
- uint8_t attribute_domain;
- int indentation;
-} uiButDatasetRow;
-
/** Derived struct for #UI_BTYPE_TREEROW. */
typedef struct uiButTreeRow {
uiBut but;
@@ -629,6 +620,9 @@ extern void ui_block_to_window_rctf(const struct ARegion *region,
rctf *rct_dst,
const rctf *rct_src);
extern float ui_block_to_window_scale(const struct ARegion *region, uiBlock *block);
+/**
+ * For mouse cursor.
+ */
extern void ui_window_to_block_fl(const struct ARegion *region,
uiBlock *block,
float *x,
@@ -646,23 +640,52 @@ extern void ui_window_to_region_rctf(const struct ARegion *region,
rctf *rect_dst,
const rctf *rct_src);
extern void ui_region_to_window(const struct ARegion *region, int *x, int *y);
+/**
+ * Popups will add a margin to #ARegion.winrct for shadow,
+ * for interactivity (point-inside tests for eg), we want the winrct without the margin added.
+ */
extern void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect);
+/**
+ * Reallocate the button (new address is returned) for a new button type.
+ * This should generally be avoided and instead the correct type be created right away.
+ *
+ * \note Only the #uiBut data can be kept. If the old button used a derived type (e.g. #uiButTab),
+ * the data that is not inside #uiBut will be lost.
+ */
uiBut *ui_but_change_type(uiBut *but, eButType new_type);
extern double ui_but_value_get(uiBut *but);
extern void ui_but_value_set(uiBut *but, double value);
+/**
+ * For picker, while editing HSV.
+ */
extern void ui_but_hsv_set(uiBut *but);
+/**
+ * For buttons pointing to color for example.
+ */
extern void ui_but_v3_get(uiBut *but, float vec[3]);
+/**
+ * For buttons pointing to color for example.
+ */
extern void ui_but_v3_set(uiBut *but, const float vec[3]);
extern void ui_hsvcircle_vals_from_pos(
const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist);
+/**
+ * Cursor in HSV circle, in float units -1 to 1, to map on radius.
+ */
extern void ui_hsvcircle_pos_from_vals(
const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *xpos, float *ypos);
extern void ui_hsvcube_pos_from_vals(
const struct uiButHSVCube *hsv_but, const rcti *rect, const float *hsv, float *xp, float *yp);
+/**
+ * \param float_precision: For number buttons the precision
+ * to use or -1 to fallback to the button default.
+ * \param use_exp_float: Use exponent representation of floats
+ * when out of reasonable range (outside of 1e3/1e-3).
+ */
extern void ui_but_string_get_ex(uiBut *but,
char *str,
const size_t maxlen,
@@ -670,7 +693,16 @@ extern void ui_but_string_get_ex(uiBut *but,
const bool use_exp_float,
bool *r_use_exp_float) ATTR_NONNULL(1, 2);
extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL();
+/**
+ * A version of #ui_but_string_get_ex for dynamic buffer sizes
+ * (where #ui_but_string_get_max_length returns 0).
+ *
+ * \param r_str_size: size of the returned string (including terminator).
+ */
extern char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size);
+/**
+ * \param str: will be overwritten.
+ */
extern void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
extern bool ui_but_string_set(struct bContext *C, uiBut *but, const char *str) ATTR_NONNULL();
extern bool ui_but_string_eval_number(struct bContext *C,
@@ -678,12 +710,22 @@ extern bool ui_but_string_eval_number(struct bContext *C,
const char *str,
double *value) ATTR_NONNULL();
extern int ui_but_string_get_max_length(uiBut *but);
-/* Clear & exit the active button's string. */
+/**
+ * Clear & exit the active button's string..
+ */
extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) ATTR_NONNULL();
+/**
+ * Use handling code to set a string for the button. Handles the case where the string is set for a
+ * search button while the search menu is open, so the results are updated accordingly.
+ * This is basically the same as pasting the string into the button.
+ */
extern void ui_but_set_string_interactive(struct bContext *C, uiBut *but, const char *value);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
void ui_def_but_icon(uiBut *but, const int icon, const int flag);
+/**
+ * Avoid using this where possible since it's better not to ask for an icon in the first place.
+ */
void ui_def_but_icon_clear(uiBut *but);
void ui_but_extra_operator_icons_free(uiBut *but);
@@ -696,6 +738,11 @@ void ui_but_range_set_hard(uiBut *but);
void ui_but_range_set_soft(uiBut *but);
bool ui_but_context_poll_operator(struct bContext *C, struct wmOperatorType *ot, const uiBut *but);
+/**
+ * Check if the operator \a ot poll is successful with the context given by \a but (optionally).
+ * \param but: The button that might store context. Can be NULL for convenience (e.g. if there is
+ * no button to take context from, but we still want to poll the operator).
+ */
bool ui_but_context_poll_operator_ex(struct bContext *C,
const uiBut *but,
const struct wmOperatorCallParams *optype_params);
@@ -706,10 +753,21 @@ extern PropertyScaleType ui_but_scale_type(const uiBut *but) ATTR_WARN_UNUSED_RE
extern bool ui_but_is_float(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Check if this button is similar enough to be grouped with another.
+ */
extern bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Checks if the button supports cycling next/previous menu items (ctrl+mouse-wheel).
+ */
extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Check if the button is pushed, this is only meaningful for some button types.
+ *
+ * \return (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOTHING)
+ */
extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -804,6 +862,7 @@ struct uiPopupBlockHandle {
/* interface_region_*.c */
/* interface_region_tooltip.c */
+
/* exposed as public API in UI_interface.h */
/* interface_region_color_picker.c */
@@ -811,6 +870,10 @@ void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3]);
void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3]);
void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3]);
+/**
+ * Returns true if the button is for a color with gamma baked in,
+ * or if it's a color picker for such a button.
+ */
bool ui_but_is_color_gamma(uiBut *but);
void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3]);
@@ -820,7 +883,10 @@ uiBlock *ui_block_func_COLOR(struct bContext *C, uiPopupBlockHandle *handle, voi
ColorPicker *ui_block_colorpicker_create(struct uiBlock *block);
/* interface_region_search.c */
-/* Search-box for string button. */
+
+/**
+ * Search-box for string button.
+ */
struct ARegion *ui_searchbox_create_generic(struct bContext *C,
struct ARegion *butregion,
uiButSearch *search_but);
@@ -831,8 +897,14 @@ struct ARegion *ui_searchbox_create_menu(struct bContext *C,
struct ARegion *butregion,
uiButSearch *search_but);
+/**
+ * x and y in screen-coords.
+ */
bool ui_searchbox_inside(struct ARegion *region, const int xy[2]) ATTR_NONNULL(1, 2);
int ui_searchbox_find_index(struct ARegion *region, const char *name);
+/**
+ * Region is the search box itself.
+ */
void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset);
int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str);
bool ui_searchbox_event(struct bContext *C,
@@ -840,16 +912,26 @@ bool ui_searchbox_event(struct bContext *C,
uiBut *but,
struct ARegion *butregion,
const struct wmEvent *event);
+/**
+ * String validated to be of correct length (but->hardmax).
+ */
bool ui_searchbox_apply(uiBut *but, struct ARegion *region);
void ui_searchbox_free(struct bContext *C, struct ARegion *region);
+/**
+ * XXX weak: search_func adds all partial matches.
+ */
void ui_but_search_refresh(uiButSearch *but);
/* interface_region_menu_popup.c */
+
int ui_but_menu_step(uiBut *but, int direction);
bool ui_but_menu_step_poll(const uiBut *but);
uiBut *ui_popup_menu_memory_get(struct uiBlock *block);
void ui_popup_menu_memory_set(uiBlock *block, struct uiBut *but);
+/**
+ * Called for creating new popups and refreshing existing ones.
+ */
uiBlock *ui_popup_block_refresh(struct bContext *C,
uiPopupBlockHandle *handle,
struct ARegion *butregion,
@@ -869,6 +951,7 @@ uiPopupBlockHandle *ui_popup_menu_create(struct bContext *C,
void *arg);
/* interface_region_popover.c */
+
uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C,
struct ARegion *butregion,
uiBut *but,
@@ -876,6 +959,10 @@ uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C,
void *arg);
/* interface_region_menu_pie.c */
+
+/**
+ * Set up data for defining a new pie menu level and add button that invokes it.
+ */
void ui_pie_menu_level_create(uiBlock *block,
struct wmOperatorType *ot,
const char *propname,
@@ -886,6 +973,10 @@ void ui_pie_menu_level_create(uiBlock *block,
int flag);
/* interface_region_popup.c */
+
+/**
+ * Translate any popup regions (so we can drag them).
+ */
void ui_popup_translate(struct ARegion *region, const int mdiff[2]);
void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle);
void ui_popup_block_scrolltest(struct uiBlock *block);
@@ -893,10 +984,19 @@ void ui_popup_block_scrolltest(struct uiBlock *block);
/* end interface_region_*.c */
/* interface_panel.c */
+
+/**
+ * Handle region panel events like opening and closing panels, changing categories, etc.
+ *
+ * \note Could become a modal key-map.
+ */
extern int ui_handler_panel_region(struct bContext *C,
const struct wmEvent *event,
struct ARegion *region,
const uiBut *active_but);
+/**
+ * Draw a panel integrated in buttons-window, tool/property lists etc.
+ */
extern void ui_draw_aligned_panel(const struct uiStyle *style,
const uiBlock *block,
const rcti *rect,
@@ -906,14 +1006,20 @@ extern void ui_draw_aligned_panel(const struct uiStyle *style,
void ui_panel_tag_search_filter_match(struct Panel *panel);
/* interface_draw.c */
+
extern void ui_draw_dropshadow(
const rctf *rct, float radius, float aspect, float alpha, int select);
+/**
+ * Draws in resolution of 48x4 colors.
+ */
void ui_draw_gradient(const rcti *rect,
const float hsv[3],
const eButGradientType type,
const float alpha);
+/* based on UI_draw_roundbox_gl_mode,
+ * check on making a version which allows us to skip some sides */
void ui_draw_but_TAB_outline(const rcti *rect,
float rad,
uchar highlight[3],
@@ -931,11 +1037,17 @@ void ui_draw_but_VECTORSCOPE(struct ARegion *region,
const struct uiWidgetColors *wcol,
const rcti *rect);
void ui_draw_but_COLORBAND(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
-void ui_draw_but_UNITVEC(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
+void ui_draw_but_UNITVEC(uiBut *but,
+ const struct uiWidgetColors *wcol,
+ const rcti *rect,
+ const float radius);
void ui_draw_but_CURVE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
+/**
+ * Draws the curve profile widget. Somewhat similar to ui_draw_but_CURVE.
+ */
void ui_draw_but_CURVEPROFILE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
@@ -950,8 +1062,19 @@ void ui_draw_but_TRACKPREVIEW(struct ARegion *region,
const rcti *rect);
/* interface_undo.c */
+
+/**
+ * Start the undo stack.
+ *
+ * \note The current state should be pushed immediately after calling this.
+ */
struct uiUndoStack_Text *ui_textedit_undo_stack_create(void);
void ui_textedit_undo_stack_destroy(struct uiUndoStack_Text *undo_stack);
+/**
+ * Push the information in the arguments to a new state in the undo stack.
+ *
+ * \note Currently the total length of the undo stack is not limited.
+ */
void ui_textedit_undo_push(struct uiUndoStack_Text *undo_stack,
const char *text,
int cursor_index);
@@ -960,10 +1083,25 @@ const char *ui_textedit_undo(struct uiUndoStack_Text *undo_stack,
int *r_cursor_index);
/* interface_handlers.c */
+
extern void ui_handle_afterfunc_add_operator(struct wmOperatorType *ot,
wmOperatorCallContext opcontext);
+/**
+ * Assumes event type is MOUSEPAN.
+ */
extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
+/**
+ * Exported to interface.c: #UI_but_active_only()
+ * \note The region is only for the button.
+ * The context needs to be set by the caller.
+ */
extern void ui_but_activate_event(struct bContext *C, struct ARegion *region, uiBut *but);
+/**
+ * Simulate moving the mouse over a button (or navigating to it with arrow keys).
+ *
+ * exported so menus can start with a highlighted button,
+ * even if the mouse isn't over it
+ */
extern void ui_but_activate_over(struct bContext *C, struct ARegion *region, uiBut *but);
extern void ui_but_execute_begin(struct bContext *C,
struct ARegion *region,
@@ -974,13 +1112,25 @@ extern void ui_but_execute_end(struct bContext *C,
uiBut *but,
void *active_back);
extern void ui_but_active_free(const struct bContext *C, uiBut *but);
+/**
+ * In some cases we may want to update the view (#View2D) in-between layout definition and drawing.
+ * E.g. to make sure a button is visible while editing.
+ */
extern void ui_but_update_view_for_active(const struct bContext *C, const uiBlock *block);
extern int ui_but_menu_direction(uiBut *but);
extern void ui_but_text_password_hide(char password_str[128], uiBut *but, const bool restore);
+/**
+ * Finds the pressed button in an aligned row (typically an expanded enum).
+ *
+ * \param direction: Use when there may be multiple buttons pressed.
+ */
extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction);
bool ui_but_is_editing(const uiBut *but);
float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
+/* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR'
+ * since this is really long its unlikely to be an issue,
+ * but this could be supported */
void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip);
void ui_but_clipboard_free(void);
bool ui_but_rna_equals(const uiBut *a, const uiBut *b);
@@ -1045,6 +1195,9 @@ void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const flo
void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow);
void ui_draw_tooltip_background(const struct uiStyle *style, uiBlock *block, rcti *rect);
+/**
+ * Conversion from old to new buttons, so still messy.
+ */
extern void ui_draw_but(const struct bContext *C,
struct ARegion *region,
struct uiStyle *style,
@@ -1065,6 +1218,15 @@ typedef enum {
* get clipped before the normal text. */
UI_MENU_ITEM_SEPARATOR_HINT,
} uiMenuItemSeparatorType;
+/**
+ * Helper call to draw a menu item without a button.
+ *
+ * \param state: The state of the button,
+ * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
+ * \param separator_type: The kind of separator which controls if and how the string is clipped.
+ * \param r_xmax: The right hand position of the text, this takes into the icon,
+ * padding and text clipping when there is not enough room to display the full text.
+ */
void ui_draw_menu_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -1078,6 +1240,10 @@ void ui_draw_preview_item(const struct uiFontStyle *fstyle,
int iconid,
int state,
eFontStyle_Align text_align);
+/**
+ * Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
+ * state. It just draws the preview and text directly.
+ */
void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -1087,59 +1253,102 @@ void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
#define UI_TEXT_MARGIN_X 0.4f
#define UI_POPUP_MARGIN (UI_DPI_FAC * 12)
-/* Margin at top of screen for popups. Note this value must be sufficient
- * to draw a popover arrow to avoid cropping it. */
+/**
+ * Margin at top of screen for popups.
+ * Note this value must be sufficient to draw a popover arrow to avoid cropping it.
+ */
#define UI_POPUP_MENU_TOP (int)(10 * UI_DPI_FAC)
#define UI_PIXEL_AA_JITTER 8
extern const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2];
/* interface_style.c */
+
+/**
+ * Called on each startup.blend read,
+ * reading without #uiFont will create one.
+ */
void uiStyleInit(void);
/* interface_icons.c */
+
void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big);
int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
/* interface_icons_event.c */
+
void icon_draw_rect_input(
float x, float y, int w, int h, float alpha, short event_type, short event_value);
/* resources.c */
+
void ui_resources_init(void);
void ui_resources_free(void);
/* interface_layout.c */
+
void ui_layout_add_but(uiLayout *layout, uiBut *but);
void ui_layout_remove_but(uiLayout *layout, const uiBut *but);
+/**
+ * \return true if the button was successfully replaced.
+ */
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but);
+/**
+ * \note May reallocate \a but, so the possibly new address is returned.
+ */
uiBut *ui_but_add_search(uiBut *but,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop);
+/**
+ * Check all buttons defined in this layout,
+ * and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
+ * Needed to handle correctly text colors of active (selected) list item.
+ */
void ui_layout_list_set_labels_active(uiLayout *layout);
/* menu callback */
void ui_item_menutype_func(struct bContext *C, struct uiLayout *layout, void *arg_mt);
void ui_item_paneltype_func(struct bContext *C, struct uiLayout *layout, void *arg_pt);
/* interface_button_group.c */
+
+/**
+ * Every function that adds a set of buttons must create another group,
+ * then #ui_def_but adds buttons to the current group (the last).
+ */
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag);
void ui_button_group_add_but(uiBlock *block, uiBut *but);
void ui_button_group_replace_but_ptr(uiBlock *block, const void *old_but_ptr, uiBut *new_but);
void ui_block_free_button_groups(uiBlock *block);
/* interface_align.c */
+
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
int ui_but_align_opposite_to_area_align_get(const struct ARegion *region) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Compute the alignment of all 'align groups' of buttons in given block.
+ *
+ * This is using an order-independent algorithm,
+ * i.e. alignment of buttons should be OK regardless of order in which
+ * they are added to the block.
+ */
void ui_block_align_calc(uiBlock *block, const struct ARegion *region);
/* interface_anim.c */
+
void ui_but_anim_flag(uiBut *but, const struct AnimationEvalContext *anim_eval_context);
void ui_but_anim_copy_driver(struct bContext *C);
void ui_but_anim_paste_driver(struct bContext *C);
+/**
+ * \a str can be NULL to only perform check if \a but has an expression at all.
+ * \return if button has an expression.
+ */
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen);
bool ui_but_anim_expression_set(uiBut *but, const char *str);
+/**
+ * Create new expression for button (i.e. a "scripted driver"), if it can be created.
+ */
bool ui_but_anim_expression_create(uiBut *but, const char *str);
void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, float cfra);
@@ -1147,9 +1356,15 @@ void ui_but_anim_decorate_cb(struct bContext *C, void *arg_but, void *arg_dummy)
void ui_but_anim_decorate_update_from_flag(uiButDecorator *but);
/* interface_query.c */
+
bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Can we mouse over the button or is it hidden/disabled/layout.
+ * \note ctrl is kind of a hack currently,
+ * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
+ */
bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -1180,6 +1395,9 @@ uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2]
uiBut *ui_tree_row_find_active(const struct ARegion *region);
typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
+/**
+ * x and y are only used in case event is NULL.
+ */
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
const int xy[2],
const bool labeledit,
@@ -1226,41 +1444,56 @@ bool ui_region_contains_point_px(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
bool ui_region_contains_rect_px(const struct ARegion *region, const rcti *rect_px);
+/**
+ * Check if the cursor is over any popups.
+ */
struct ARegion *ui_screen_region_find_mouse_over_ex(struct bScreen *screen, const int xy[2])
ATTR_NONNULL(1, 2);
struct ARegion *ui_screen_region_find_mouse_over(struct bScreen *screen,
const struct wmEvent *event);
/* interface_context_menu.c */
+
bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but, const struct wmEvent *event);
+/**
+ * menu to show when right clicking on the panel header
+ */
void ui_popup_context_menu_for_panel(struct bContext *C,
struct ARegion *region,
struct Panel *panel);
/* interface_eyedropper.c */
+
struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf);
/* interface_eyedropper_color.c */
+
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
/* interface_eyedropper_colorband.c */
+
void UI_OT_eyedropper_colorramp(struct wmOperatorType *ot);
void UI_OT_eyedropper_colorramp_point(struct wmOperatorType *ot);
/* interface_eyedropper_datablock.c */
+
void UI_OT_eyedropper_id(struct wmOperatorType *ot);
/* interface_eyedropper_depth.c */
+
void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
/* interface_eyedropper_driver.c */
+
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
/* interface_eyedropper_gpencil_color.c */
+
void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
/* interface_template_asset_view.cc */
+
struct uiListType *UI_UL_asset_view(void);
/**
@@ -1286,12 +1519,15 @@ void ui_rna_collection_search_update_fn(const struct bContext *C,
const bool is_first);
/* interface_ops.c */
+
bool ui_jump_to_target_button_poll(struct bContext *C);
/* interface_queries.c */
+
void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
+
void ui_block_free_views(struct uiBlock *block);
uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiTreeViewHandle *new_view);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index b792c59481c..cbdb284c66b 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1464,11 +1464,6 @@ BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
}
-/**
- * Create UI items for enum items in \a item_array.
- *
- * A version of #uiItemsFullEnumO that takes pre-calculated item array.
- */
void uiItemsFullEnumO_items(uiLayout *layout,
wmOperatorType *ot,
PointerRNA ptr,
@@ -1691,7 +1686,6 @@ void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
}
-/* for use in cases where we have */
void uiItemEnumO_value(uiLayout *layout,
const char *name,
int icon,
@@ -2466,9 +2460,6 @@ void uiItemR(
uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
}
-/**
- * Use a wrapper function since re-implementing all the logic in this function would be messy.
- */
void uiItemFullR_with_popover(uiLayout *layout,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -2722,9 +2713,6 @@ static void ui_rna_collection_search_arg_free_fn(void *ptr)
MEM_freeN(ptr);
}
-/**
- * \note May reallocate \a but, so the possibly new address is returned.
- */
uiBut *ui_but_add_search(
uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
{
@@ -2869,7 +2857,6 @@ void uiItemPointerR(uiLayout *layout,
uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon);
}
-/* menu item */
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
{
MenuType *mt = (MenuType *)arg_mt;
@@ -3015,10 +3002,6 @@ void uiItemMContents(uiLayout *layout, const char *menuname)
UI_menutype_draw(C, mt, layout);
}
-/**
- * Insert a decorator item for a button with the same property as \a prop.
- * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
- */
void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
{
uiBlock *block = layout->root->block;
@@ -3077,10 +3060,6 @@ void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop,
}
}
-/**
- * Insert a decorator item for a button with the same property as \a prop.
- * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
- */
void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
{
PropertyRNA *prop = NULL;
@@ -3099,7 +3078,6 @@ void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, i
uiItemDecoratorR_prop(layout, ptr, prop, index);
}
-/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, const bContext *C, PanelType *pt, const char *name, int icon)
{
@@ -3241,11 +3219,6 @@ void uiItemL(uiLayout *layout, const char *name, int icon)
uiItemL_(layout, name, icon);
}
-/**
- * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
- * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
- * special needs.
- */
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
{
uiPropertySplitWrapper split_wrapper = {NULL};
@@ -3261,9 +3234,6 @@ uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
return split_wrapper;
}
-/*
- * Helper to add a label and creates a property split layout if needed.
- */
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
{
if (layout->item.flag & UI_ITEM_PROP_SEP) {
@@ -3297,7 +3267,6 @@ void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
}
}
-/* value item */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
{
/* label */
@@ -3342,7 +3311,6 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
}
}
-/* separator item */
void uiItemS_ex(uiLayout *layout, float factor)
{
uiBlock *block = layout->root->block;
@@ -3370,13 +3338,11 @@ void uiItemS_ex(uiLayout *layout, float factor)
"");
}
-/* separator item */
void uiItemS(uiLayout *layout)
{
uiItemS_ex(layout, 1.0f);
}
-/* Flexible spacing. */
void uiItemSpacer(uiLayout *layout)
{
uiBlock *block = layout->root->block;
@@ -3409,7 +3375,6 @@ void uiItemSpacer(uiLayout *layout)
"");
}
-/* level items */
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
{
if (!func) {
@@ -3419,9 +3384,6 @@ void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc
ui_item_menu(layout, name, icon, func, arg, NULL, "", false);
}
-/**
- * Version of #uiItemMenuF that free's `argN`.
- */
void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN)
{
if (!func) {
@@ -4730,7 +4692,6 @@ static void ui_layout_heading_set(uiLayout *layout, const char *heading)
}
}
-/* layout create functions */
uiLayout *uiLayoutRow(uiLayout *layout, bool align)
{
uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
@@ -4744,9 +4705,6 @@ uiLayout *uiLayoutRow(uiLayout *layout, bool align)
return litem;
}
-/**
- * See #uiLayoutColumnWithHeading().
- */
uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
{
uiLayout *litem = uiLayoutRow(layout, align);
@@ -4767,12 +4725,6 @@ uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
return litem;
}
-/**
- * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
- * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
- * first split-column, the heading is added there instead. Otherwise the heading inserted with a
- * new row.
- */
uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
{
uiLayout *litem = uiLayoutColumn(layout, align);
@@ -4862,11 +4814,6 @@ uiLayout *uiLayoutBox(uiLayout *layout)
return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX);
}
-/**
- * Check all buttons defined in this layout,
- * and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
- * Needed to handle correctly text colors of active (selected) list item.
- */
void ui_layout_list_set_labels_active(uiLayout *layout)
{
LISTBASE_FOREACH (uiButtonItem *, bitem, &layout->items) {
@@ -5214,11 +5161,6 @@ static bool block_search_filter_tag_buttons(uiBlock *block, const char *search_f
return has_result;
}
-/**
- * Apply property search behavior, setting panel flags and deactivating buttons that don't match.
- *
- * \note Must not be run after #UI_block_layout_resolve.
- */
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter)
{
if (search_filter == NULL || search_filter[0] == '\0') {
@@ -5643,9 +5585,6 @@ void ui_layout_remove_but(uiLayout *layout, const uiBut *but)
BLI_freelinkN(&layout->items, bitem);
}
-/**
- * \return true if the button was successfully replaced.
- */
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
{
uiButtonItem *bitem = ui_layout_find_button_item(layout, old_but_ptr);
@@ -5683,11 +5622,6 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
layout->root->argv = argv;
}
-/**
- * Used for property search when the layout process needs to be cancelled in order to avoid
- * computing the locations for buttons, but the layout items created while adding the buttons
- * must still be freed.
- */
void UI_block_layout_free(uiBlock *block)
{
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
@@ -5759,7 +5693,6 @@ void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but)
}
}
-/* this is a bit of a hack but best keep it in one place at least */
wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop)
{
if (r_prop != NULL) {
@@ -5777,7 +5710,6 @@ wmOperatorType *UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA *
return NULL;
}
-/* this is a bit of a hack but best keep it in one place at least */
MenuType *UI_but_menutype_get(uiBut *but)
{
if (but->menu_create_func == ui_item_menutype_func) {
@@ -5786,7 +5718,6 @@ MenuType *UI_but_menutype_get(uiBut *but)
return NULL;
}
-/* this is a bit of a hack but best keep it in one place at least */
PanelType *UI_but_paneltype_get(uiBut *but)
{
if (but->menu_create_func == ui_item_paneltype_func) {
@@ -5886,9 +5817,6 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout,
}
}
-/**
- * Used for popup panels only.
- */
void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
{
if (layout->context) {
@@ -6009,9 +5937,6 @@ static void ui_layout_introspect_items(DynStr *ds, ListBase *lb)
BLI_dynstr_append(ds, "]");
}
-/**
- * Evaluate layout items as a Python dictionary.
- */
const char *UI_layout_introspect(uiLayout *layout)
{
DynStr *ds = BLI_dynstr_new();
@@ -6031,10 +5956,6 @@ const char *UI_layout_introspect(uiLayout *layout)
/** \name Alert Box with Big Icon
* \{ */
-/**
- * Helper to add a big icon and create a split layout for alert popups.
- * Returns the layout to place further items into the alert box.
- */
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
{
const uiStyle *style = UI_style_get_dpi();
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index c962a1107ae..35b621b0272 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -26,7 +26,8 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
-#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
+#include "DNA_modifier_types.h" /* for handling geometry nodes properties */
+#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
#include "DNA_screen_types.h"
#include "DNA_text_types.h"
@@ -846,6 +847,9 @@ bool UI_context_copy_to_selected_list(bContext *C,
else if (RNA_struct_is_a(ptr->type, &RNA_Keyframe)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_keyframes");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_Action)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_actions");
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) {
*r_lb = CTX_data_collection_get(C, "selected_nla_strips");
}
@@ -982,6 +986,97 @@ bool UI_context_copy_to_selected_list(bContext *C,
return true;
}
+bool UI_context_copy_to_selected_check(PointerRNA *ptr,
+ PointerRNA *ptr_link,
+ PropertyRNA *prop,
+ const char *path,
+ bool use_path_from_id,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop)
+{
+ PointerRNA idptr;
+ PropertyRNA *lprop;
+ PointerRNA lptr;
+
+ if (ptr_link->data == ptr->data) {
+ return false;
+ }
+
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(ptr_link->owner_id, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(ptr_link, path, &lptr, &lprop);
+ }
+ else {
+ lptr = *ptr_link;
+ lprop = prop;
+ }
+
+ if (lptr.data == ptr->data) {
+ /* temp_ptr might not be the same as ptr_link! */
+ return false;
+ }
+
+ /* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
+ * check but we are now more permissive when it comes to ID properties, see below. */
+ if (lprop == NULL) {
+ return false;
+ }
+
+ if (RNA_property_type(lprop) != RNA_property_type(prop)) {
+ return false;
+ }
+
+ /* Check property pointers matching.
+ * For ID properties, these pointers match:
+ * - If the property is API defined on an existing class (and they are equally named).
+ * - Never for ID properties on specific ID (even if they are equally named).
+ * - Never for NodesModifierSettings properties (even if they are equally named).
+ *
+ * Be permissive on ID properties in the following cases:
+ * - #NodesModifierSettings properties
+ * - (special check: only if the node-group matches, since the 'Input_n' properties are name
+ * based and similar on potentially very different node-groups).
+ * - ID properties on specific ID
+ * - (no special check, copying seems OK [even if type does not match -- does not do anything
+ * then])
+ */
+ bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
+ if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
+ RNA_struct_is_a(ptr->type, &RNA_NodesModifier)) {
+ ignore_prop_eq = false;
+
+ NodesModifierData *nmd_link = (NodesModifierData *)lptr.data;
+ NodesModifierData *nmd_src = (NodesModifierData *)ptr->data;
+ if (nmd_link->node_group == nmd_src->node_group) {
+ ignore_prop_eq = true;
+ }
+ }
+
+ if ((lprop != prop) && !ignore_prop_eq) {
+ return false;
+ }
+
+ if (!RNA_property_editable(&lptr, lprop)) {
+ return false;
+ }
+
+ if (r_ptr) {
+ *r_ptr = lptr;
+ }
+ if (r_prop) {
+ *r_prop = lprop;
+ }
+
+ return true;
+}
+
/**
* Called from both exec & poll.
*
@@ -992,7 +1087,7 @@ bool UI_context_copy_to_selected_list(bContext *C,
static bool copy_to_selected_button(bContext *C, bool all, bool poll)
{
Main *bmain = CTX_data_main(C);
- PointerRNA ptr, lptr, idptr;
+ PointerRNA ptr, lptr;
PropertyRNA *prop, *lprop;
bool success = false;
int index;
@@ -1022,32 +1117,8 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
continue;
}
- if (use_path_from_id) {
- /* Path relative to ID. */
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.owner_id, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else if (path) {
- /* Path relative to elements from list. */
- lprop = NULL;
- RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
-
- if (lptr.data == ptr.data) {
- /* lptr might not be the same as link->ptr! */
- continue;
- }
-
- if (lprop != prop) {
- continue;
- }
-
- if (!RNA_property_editable(&lptr, lprop)) {
+ if (!UI_context_copy_to_selected_check(
+ &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) {
continue;
}
@@ -1340,10 +1411,6 @@ void UI_editsource_active_but_test(uiBut *but)
BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
}
-/**
- * Remove the editsource data for \a old_but and reinsert it for \a new_but. Use when the button
- * was reallocated, e.g. to have a new type (#ui_but_change_type()).
- */
void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but)
{
uiEditSourceButStore *but_store = BLI_ghash_lookup(ui_editsource_info->hash, old_but);
@@ -1405,7 +1472,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
int ret;
/* needed else the active button does not get tested */
- UI_screen_free_active_but(C, CTX_wm_screen(C));
+ UI_screen_free_active_but_highlight(C, CTX_wm_screen(C));
// printf("%s: begin\n", __func__);
@@ -1977,7 +2044,7 @@ static int ui_tree_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const w
const ARegion *region = CTX_wm_region(C);
uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, event->xy);
- if (!UI_tree_view_item_drop_handle(hovered_tree_item, event->customdata)) {
+ if (!UI_tree_view_item_drop_handle(C, hovered_tree_item, event->customdata)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
@@ -2082,9 +2149,6 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_eyedropper_gpencil_color);
}
-/**
- * \brief User Interface Keymap
- */
void ED_keymap_ui(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "User Interface", 0, 0);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 6acbaf03476..bc1d3387ad7 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -273,10 +273,6 @@ static Panel *panel_add_instanced(ARegion *region,
return panel;
}
-/**
- * Called in situations where panels need to be added dynamically rather than
- * having only one panel corresponding to each #PanelType.
- */
Panel *UI_panel_add_instanced(const bContext *C,
ARegion *region,
ListBase *panels,
@@ -301,10 +297,6 @@ Panel *UI_panel_add_instanced(const bContext *C,
return new_panel;
}
-/**
- * Find a unique key to append to the #PanelType.idname for the lookup to the panel's #uiBlock.
- * Needed for instanced panels, where there can be multiple with the same type and identifier.
- */
void UI_list_panel_unique_str(Panel *panel, char *r_name)
{
/* The panel sort-order will be unique for a specific panel type because the instanced
@@ -334,12 +326,6 @@ static void panel_delete(const bContext *C, ARegion *region, ListBase *panels, P
MEM_freeN(panel);
}
-/**
- * Remove instanced panels from the region's panel list.
- *
- * \note Can be called with NULL \a C, but it should be avoided because
- * handlers might not be removed.
- */
void UI_panels_free_instanced(const bContext *C, ARegion *region)
{
/* Delete panels with the instanced flag. */
@@ -361,15 +347,6 @@ void UI_panels_free_instanced(const bContext *C, ARegion *region)
}
}
-/**
- * Check if the instanced panels in the region's panels correspond to the list of data the panels
- * represent. Returns false if the panels have been reordered or if the types from the list data
- * don't match in any way.
- *
- * \param data: The list of data to check against the instanced panels.
- * \param panel_idname_func: Function to find the #PanelType.idname for each item in the data list.
- * For a readability and generality, this lookup happens separately for each type of panel list.
- */
bool UI_panel_list_matches_data(ARegion *region,
ListBase *data,
uiListPanelIDFromDataFunc panel_idname_func)
@@ -486,8 +463,12 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
/* Set the bit to tell the interface to instanced the list. */
drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED;
+ CTX_store_set(C, drag_panel->runtime.context);
+
/* Finally, move this panel's list item to the new index in its list. */
drag_panel->type->reorder(C, drag_panel, move_to_index);
+
+ CTX_store_set(C, NULL);
}
/**
@@ -697,9 +678,6 @@ Panel *UI_panel_find_by_type(ListBase *lb, const PanelType *pt)
return NULL;
}
-/**
- * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL.
- */
Panel *UI_panel_begin(
ARegion *region, ListBase *lb, uiBlock *block, PanelType *pt, Panel *panel, bool *r_open)
{
@@ -779,11 +757,6 @@ Panel *UI_panel_begin(
return panel;
}
-/**
- * Create the panel header button group, used to mark which buttons are part of
- * panel headers for the panel search process that happens later. This Should be
- * called before adding buttons for the panel's header layout.
- */
void UI_panel_header_buttons_begin(Panel *panel)
{
uiBlock *block = panel->runtime.block;
@@ -791,9 +764,6 @@ void UI_panel_header_buttons_begin(Panel *panel)
ui_block_new_button_group(block, UI_BUTTON_GROUP_LOCK | UI_BUTTON_GROUP_PANEL_HEADER);
}
-/**
- * Finish the button group for the panel header to avoid putting panel body buttons in it.
- */
void UI_panel_header_buttons_end(Panel *panel)
{
uiBlock *block = panel->runtime.block;
@@ -923,10 +893,6 @@ static void panel_matches_search_filter_recursive(const Panel *panel, bool *filt
}
}
-/**
- * Find whether a panel or any of its sub-panels contain a property that matches the search filter,
- * depending on the search process running in #UI_block_apply_search_filter earlier.
- */
bool UI_panel_matches_search_filter(const Panel *panel)
{
bool search_filter_matches = false;
@@ -1018,10 +984,6 @@ static void region_panels_remove_invisible_layouts(ARegion *region)
}
}
-/**
- * Get the panel's expansion state, taking into account
- * expansion set from property search if it applies.
- */
bool UI_panel_is_closed(const Panel *panel)
{
/* Header-less panels can never be closed, otherwise they could disappear. */
@@ -1047,9 +1009,6 @@ bool UI_panel_is_active(const Panel *panel)
/** \name Drawing
* \{ */
-/**
- * Draw panels, selected (panels currently being dragged) on top.
- */
void UI_panels_draw(const bContext *C, ARegion *region)
{
/* Draw in reverse order, because #uiBlocks are added in reverse order
@@ -1071,7 +1030,6 @@ void UI_panels_draw(const bContext *C, ARegion *region)
#define PNL_ICON UI_UNIT_X /* Could be UI_UNIT_Y too. */
-/* For button layout next to label. */
void UI_panel_label_offset(const uiBlock *block, int *r_x, int *r_y)
{
Panel *panel = block->panel;
@@ -1118,7 +1076,8 @@ static void panel_draw_highlight_border(const Panel *panel,
}
const bTheme *btheme = UI_GetTheme();
- const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f;
+ const float aspect = panel->runtime.block->aspect;
+ const float radius = (btheme->tui.panel_roundness * U.widget_unit * 0.5f) / aspect;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
float color[4];
@@ -1241,7 +1200,8 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
}
const bTheme *btheme = UI_GetTheme();
- const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f;
+ const float aspect = panel->runtime.block->aspect;
+ const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f / aspect;
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
@@ -1288,9 +1248,6 @@ static void panel_draw_aligned_backdrop(const Panel *panel,
immUnbindProgram();
}
-/**
- * Draw a panel integrated in buttons-window, tool/property lists etc.
- */
void ui_draw_aligned_panel(const uiStyle *style,
const uiBlock *block,
const rcti *rect,
@@ -1328,6 +1285,24 @@ void ui_draw_aligned_panel(const uiStyle *style,
}
}
+bool UI_panel_should_show_background(const ARegion *region, const PanelType *panel_type)
+{
+ if (region->alignment == RGN_ALIGN_FLOAT) {
+ return false;
+ }
+
+ if (panel_type && panel_type->flag & PANEL_TYPE_NO_HEADER) {
+ if (region->regiontype == RGN_TYPE_TOOLS) {
+ /* We never want a background around active tools. */
+ return false;
+ }
+ /* Without a header there is no background except for region overlap. */
+ return region->overlap != 0;
+ }
+
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1337,9 +1312,6 @@ void ui_draw_aligned_panel(const uiStyle *style,
#define TABS_PADDING_BETWEEN_FACTOR 4.0f
#define TABS_PADDING_TEXT_FACTOR 6.0f
-/**
- * Draw vertical tabs on the left side of the region, one tab per category.
- */
void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
{
// #define USE_FLAT_INACTIVE
@@ -1740,17 +1712,22 @@ static bool uiAlignPanelStep(ARegion *region, const float factor, const bool dra
const int region_offset_x = panel_region_offset_x_get(region);
for (int i = 0; i < active_panels_len; i++) {
PanelSort *ps = &panel_sort[i];
- const bool no_header = ps->panel->type->flag & PANEL_TYPE_NO_HEADER;
+ const bool show_background = UI_panel_should_show_background(region, ps->panel->type);
ps->panel->runtime.region_ofsx = region_offset_x;
- ps->new_offset_x = region_offset_x + (no_header ? 0 : UI_PANEL_MARGIN_X);
+ ps->new_offset_x = region_offset_x + (show_background ? UI_PANEL_MARGIN_X : 0);
}
/* Y offset. */
for (int i = 0, y = 0; i < active_panels_len; i++) {
PanelSort *ps = &panel_sort[i];
+ const bool show_background = UI_panel_should_show_background(region, ps->panel->type);
+
y -= get_panel_real_size_y(ps->panel);
- y -= UI_PANEL_MARGIN_Y;
+ /* Separate panel boxes a bit further (if they are drawn). */
+ if (show_background) {
+ y -= UI_PANEL_MARGIN_Y;
+ }
ps->new_offset_y = y;
/* The header still draws offset by the size of closed panels, so apply the offset here. */
if (UI_panel_is_closed(ps->panel)) {
@@ -1796,6 +1773,7 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
{
int sizex = 0;
int sizey = 0;
+ bool has_panel_with_background = false;
/* Compute size taken up by panels, for setting in view2d. */
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
@@ -1805,6 +1783,9 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
sizex = max_ii(sizex, pa_sizex);
sizey = min_ii(sizey, pa_sizey);
+ if (UI_panel_should_show_background(region, panel->type)) {
+ has_panel_with_background = true;
+ }
}
}
@@ -1814,6 +1795,11 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
if (sizey == 0) {
sizey = -UI_PANEL_WIDTH;
}
+ /* Extra margin after the list so the view scrolls a few pixels further than the panel border.
+ * Also makes the bottom match the top margin. */
+ if (has_panel_with_background) {
+ sizey -= UI_PANEL_MARGIN_Y;
+ }
*r_x = sizex;
*r_y = sizey;
@@ -2342,11 +2328,6 @@ static int ui_handle_panel_category_cycling(const wmEvent *event,
return WM_UI_HANDLER_CONTINUE;
}
-/**
- * Handle region panel events like opening and closing panels, changing categories, etc.
- *
- * \note Could become a modal key-map.
- */
int ui_handler_panel_region(bContext *C,
const wmEvent *event,
ARegion *region,
@@ -2458,6 +2439,12 @@ static void ui_panel_custom_data_set_recursive(Panel *panel, PointerRNA *custom_
}
}
+void UI_panel_context_pointer_set(Panel *panel, const char *name, PointerRNA *ptr)
+{
+ uiLayoutSetContextPointer(panel->layout, name, ptr);
+ panel->runtime.context = uiLayoutGetContextStore(panel->layout);
+}
+
void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data)
{
BLI_assert(panel->type != NULL);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index bdf93d7c82e..b486ceb8dca 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -69,15 +69,9 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_CHECKBOX,
UI_BTYPE_CHECKBOX_N,
UI_BTYPE_ROW,
- UI_BTYPE_DATASETROW,
UI_BTYPE_TREEROW);
}
-/**
- * Can we mouse over the button or is it hidden/disabled/layout.
- * \note ctrl is kind of a hack currently,
- * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
- */
bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
{
/* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */
@@ -104,7 +98,6 @@ bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
return true;
}
-/* file selectors are exempt from utf-8 checks */
bool UI_but_is_utf8(const uiBut *but)
{
if (but->rnaprop) {
@@ -284,7 +277,6 @@ static uiBut *ui_but_find(const ARegion *region,
return NULL;
}
-/* x and y are only used in case event is NULL... */
uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
const int xy[2],
const bool labeledit,
@@ -798,7 +790,6 @@ bool ui_region_contains_rect_px(const ARegion *region, const rcti *rect_px)
/** \name Screen (#bScreen) Spatial
* \{ */
-/** Check if the cursor is over any popups. */
ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, const int xy[2])
{
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c
index 48952c4f121..2b167c56186 100644
--- a/source/blender/editors/interface/interface_region_color_picker.c
+++ b/source/blender/editors/interface/interface_region_color_picker.c
@@ -115,8 +115,6 @@ void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3])
}
}
-/* Returns true if the button is for a color with gamma baked in,
- * or if it's a color picker for such a button. */
bool ui_but_is_color_gamma(uiBut *but)
{
if (but->rnaprop) {
@@ -183,7 +181,6 @@ static void ui_color_picker_update_hsv(ColorPicker *cpicker,
cpicker->is_init = true;
}
-/* for picker, while editing hsv */
void ui_but_hsv_set(uiBut *but)
{
float rgb_perceptual[3];
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index b50daa0df21..fc4ce6180c3 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -57,6 +57,7 @@
/* -------------------------------------------------------------------- */
/** \name Utilities
* \{ */
+
struct HudRegionData {
short regionid;
};
diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c
index 0ffbdd6911c..677da07d53d 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.c
+++ b/source/blender/editors/interface/interface_region_menu_pie.c
@@ -305,8 +305,7 @@ int UI_pie_menu_invoke_from_rna_enum(struct bContext *C,
/** \} */
/* -------------------------------------------------------------------- */
-/**
- * \name Pie Menu Levels
+/** \name Pie Menu Levels
*
* Pie menus can't contain more than 8 items (yet).
* When using #uiItemsFullEnumO, a "More" button is created that calls
@@ -318,7 +317,6 @@ int UI_pie_menu_invoke_from_rna_enum(struct bContext *C,
* Ideally we'd have some way of handling this for all kinds of pie items, but that's tricky.
*
* - Julian (Feb 2016)
- *
* \{ */
typedef struct PieMenuLevelData {
@@ -372,9 +370,6 @@ static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
UI_pie_menu_end(C, pie);
}
-/**
- * Set up data for defining a new pie menu level and add button that invokes it.
- */
void ui_pie_menu_level_create(uiBlock *block,
wmOperatorType *ot,
const char *propname,
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index 408953f8d0e..a8980b8b122 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -384,10 +384,6 @@ uiPopupBlockHandle *ui_popup_menu_create(
/** \name Popup Menu API with begin & end
* \{ */
-/**
- * Only return handler, and set optional title.
- * \param block_name: Assigned to uiBlock.name (useful info for debugging).
- */
uiPopupMenu *UI_popup_menu_begin_ex(bContext *C,
const char *title,
const char *block_name,
@@ -450,16 +446,12 @@ uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
return UI_popup_menu_begin_ex(C, title, __func__, icon);
}
-/**
- * Setting the button makes the popup open from the button instead of the cursor.
- */
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but)
{
pup->but = but;
pup->butregion = butregion;
}
-/* set the whole structure to work */
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
{
wmWindow *window = CTX_wm_window(C);
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index 5e7e0bfe9b5..1bb589d99fb 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -340,12 +340,6 @@ int UI_popover_panel_invoke(bContext *C, const char *idname, bool keep_open, Rep
/** \name Popup Menu API with begin & end
* \{ */
-/**
- * Only return handler, and set optional title.
- *
- * \param from_active_button: Use the active button for positioning,
- * use when the popover is activated from an operator instead of directly from the button.
- */
uiPopover *UI_popover_begin(bContext *C, int ui_menu_width, bool from_active_button)
{
uiPopover *pup = MEM_callocN(sizeof(uiPopover), "popover menu");
@@ -383,7 +377,6 @@ static void popover_keymap_fn(wmKeyMap *UNUSED(keymap), wmKeyMapItem *UNUSED(kmi
pup->block->handle->menuretval = UI_RETURN_OK;
}
-/* set the whole structure to work */
void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap)
{
wmWindow *window = CTX_wm_window(C);
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 0e53100f91b..33ce47b281b 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -53,9 +53,6 @@
/** \name Utility Functions
* \{ */
-/**
- * Translate any popup regions (so we can drag them).
- */
void ui_popup_translate(ARegion *region, const int mdiff[2])
{
BLI_rcti_translate(&region->winrct, UNPACK2(mdiff));
@@ -554,9 +551,6 @@ static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
}
}
-/**
- * Called for creating new popups and refreshing existing ones.
- */
uiBlock *ui_popup_block_refresh(bContext *C,
uiPopupBlockHandle *handle,
ARegion *butregion,
@@ -743,7 +737,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
if (block_old) {
block->oldblock = block_old;
UI_block_update_from_old(C, block);
- UI_blocklist_free_inactive(C, &region->uiblocks);
+ UI_blocklist_free_inactive(C, region);
}
/* checks which buttons are visible, sets flags to prevent draw (do after region init) */
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index eaf1ed3693b..f4c99fb3c16 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -106,17 +106,6 @@ struct uiSearchboxData {
#define SEARCH_ITEMS 10
-/**
- * Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
- *
- * \param items: Stores the items.
- * \param name: Text to display for the item.
- * \param poin: Opaque pointer (for use by the caller).
- * \param iconid: The icon, #ICON_NONE for no icon.
- * \param state: The buttons state flag, compatible with #uiBut.flag,
- * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE.
- * \return false if there is nothing to add.
- */
bool UI_search_item_add(uiSearchItems *items,
const char *name,
void *poin,
@@ -126,7 +115,7 @@ bool UI_search_item_add(uiSearchItems *items,
{
/* hijack for autocomplete */
if (items->autocpl) {
- UI_autocomplete_update_name(items->autocpl, name);
+ UI_autocomplete_update_name(items->autocpl, name + name_prefix_offset);
return true;
}
@@ -186,12 +175,12 @@ bool UI_search_item_add(uiSearchItems *items,
return true;
}
-int UI_searchbox_size_y(void)
+int UI_searchbox_size_y()
{
return SEARCH_ITEMS * UI_UNIT_Y + 2 * UI_POPUP_MENU_TOP;
}
-int UI_searchbox_size_x(void)
+int UI_searchbox_size_x()
{
return 12 * UI_UNIT_X;
}
@@ -289,7 +278,6 @@ int ui_searchbox_find_index(ARegion *region, const char *name)
return UI_search_items_find_index(&data->items, name);
}
-/* x and y in screen-coords. */
bool ui_searchbox_inside(ARegion *region, const int xy[2])
{
uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
@@ -297,7 +285,6 @@ bool ui_searchbox_inside(ARegion *region, const int xy[2])
return BLI_rcti_isect_pt(&data->bbox, xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin);
}
-/* string validated to be of correct length (but->hardmax) */
bool ui_searchbox_apply(uiBut *but, ARegion *region)
{
uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata);
@@ -326,13 +313,6 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region)
return true;
}
- if (but->flag & UI_BUT_VALUE_CLEAR) {
- /* It is valid for _VALUE_CLEAR flavor to have no active element
- * (it's a valid way to unlink). */
- but->editstr[0] = '\0';
-
- return true;
- }
return false;
}
@@ -477,7 +457,6 @@ static void ui_searchbox_update_fn(bContext *C,
search_but->items_update_fn(C, search_but->arg, str, items, is_first_search);
}
-/* region is the search box itself */
void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset)
{
uiButSearch *search_but = (uiButSearch *)but;
@@ -1032,8 +1011,6 @@ ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiButSearch *
return region;
}
-/* sets red alert if button holds a string it can't find */
-/* XXX weak: search_func adds all partial matches... */
void ui_but_search_refresh(uiButSearch *search_but)
{
uiBut *but = &search_but->but;
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 0d8bdfc5817..e146443faaa 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -1466,10 +1466,6 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon(
return region;
}
-/**
- * \param is_label: When true, show a small tip that only shows the name, otherwise show the full
- * tooltip.
- */
ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
{
return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label);
@@ -1542,13 +1538,6 @@ static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(
return data;
}
-/**
- * Create a tooltip from search-item tooltip data \a item_tooltip data.
- * To be called from a callback set with #UI_but_func_search_set_tooltip().
- *
- * \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
- * which is passed to the tooltip callback.
- */
ARegion *UI_tooltip_create_from_search_item_generic(
bContext *C,
const ARegion *searchbox_region,
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 8bb1e477506..643fa128d08 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -219,7 +219,6 @@ void UI_fontstyle_draw(const uiFontStyle *fs,
UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, NULL);
}
-/* drawn same as above, but at 90 degree angle */
void UI_fontstyle_draw_rotated(const uiFontStyle *fs,
const rcti *rect,
const char *str,
@@ -279,12 +278,6 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs,
}
}
-/**
- * Similar to #UI_fontstyle_draw
- * but ignore alignment, shadow & no clipping rect.
- *
- * For drawing on-screen labels.
- */
void UI_fontstyle_draw_simple(
const uiFontStyle *fs, float x, float y, const char *str, const uchar col[4])
{
@@ -294,9 +287,6 @@ void UI_fontstyle_draw_simple(
BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
}
-/**
- * Same as #UI_fontstyle_draw but draw a colored backdrop.
- */
void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs,
float x,
float y,
@@ -331,7 +321,7 @@ void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs,
}
/* ************** helpers ************************ */
-/* XXX: read a style configure */
+
const uiStyle *UI_style_get(void)
{
#if 0
@@ -344,7 +334,6 @@ const uiStyle *UI_style_get(void)
#endif
}
-/* for drawing, scaled with DPI setting */
const uiStyle *UI_style_get_dpi(void)
{
const uiStyle *style = UI_style_get();
@@ -376,16 +365,6 @@ int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str)
return (int)BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
}
-/**
- * Return the width of `str` with the spacing & kerning of `fs` with `aspect`
- * (representing #uiBlock.aspect) applied.
- *
- * When calculating text width, the UI layout logic calculate widths without scale,
- * only applying scale when drawing. This causes problems for fonts since kerning at
- * smaller sizes often makes them wider than a scaled down version of the larger text.
- * Resolve this by calculating the text at the on-screen size,
- * returning the result scaled back to 1:1. See T92361.
- */
int UI_fontstyle_string_width_with_block_aspect(const uiFontStyle *fs,
const char *str,
const float aspect)
@@ -415,8 +394,6 @@ int UI_fontstyle_height_max(const uiFontStyle *fs)
/* ************** init exit ************************ */
-/* called on each startup.blend read */
-/* reading without uifont will create one */
void uiStyleInit(void)
{
const uiStyle *style = U.uistyles.first;
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 7b2fb8f784e..0a3cff5fa98 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -227,7 +227,7 @@ void uiTemplateAssetView(uiLayout *layout,
if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY) == 0) {
uiItemFullR(row, asset_library_dataptr, asset_library_prop, RNA_NO_INDEX, 0, 0, "", 0);
if (asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
- uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_list_refresh");
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
}
}
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
index 85a6147432b..6d4b7a37bff 100644
--- a/source/blender/editors/interface/interface_template_attribute_search.cc
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -106,7 +106,7 @@ void attribute_search_add_items(StringRefNull str,
continue;
}
- BLI_string_search_add(search, item->name.c_str(), (void *)item);
+ BLI_string_search_add(search, item->name.c_str(), (void *)item, 0);
}
GeometryAttributeInfo **filtered_items;
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 845a7813da2..13e539b5095 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -1276,9 +1276,6 @@ void uiTemplateList(uiLayout *layout,
nullptr);
}
-/**
- * \return: A RNA pointer for the operator properties.
- */
PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
const char *opname,
bool create_properties)
@@ -1298,9 +1295,6 @@ PointerRNA *UI_list_custom_activate_operator_set(uiList *ui_list,
return dyn_data->custom_activate_opptr;
}
-/**
- * \return: A RNA pointer for the operator properties.
- */
PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
const char *opname,
bool create_properties)
@@ -1325,7 +1319,7 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
/** \name List-types Registration
* \{ */
-void ED_uilisttypes_ui(void)
+void ED_uilisttypes_ui()
{
WM_uilisttype_add(UI_UL_asset_view());
}
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.cc
index 26250e105eb..7a079e01e61 100644
--- a/source/blender/editors/interface/interface_template_search_menu.c
+++ b/source/blender/editors/interface/interface_template_search_menu.cc
@@ -21,8 +21,8 @@
* Accessed via the #WM_OT_search_menu operator.
*/
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -85,16 +85,16 @@ struct MenuSearch_Context {
};
struct MenuSearch_Parent {
- struct MenuSearch_Parent *parent;
+ MenuSearch_Parent *parent;
MenuType *parent_mt;
const char *drawstr;
/** Set while writing menu items only. */
- struct MenuSearch_Parent *temp_child;
+ MenuSearch_Parent *temp_child;
};
struct MenuSearch_Item {
- struct MenuSearch_Item *next, *prev;
+ MenuSearch_Item *next, *prev;
const char *drawstr;
const char *drawwstr_full;
/** Support a single level sub-menu nesting (for operator buttons that expand). */
@@ -102,12 +102,12 @@ struct MenuSearch_Item {
int icon;
int state;
- struct MenuSearch_Parent *menu_parent;
+ MenuSearch_Parent *menu_parent;
MenuType *mt;
- enum {
- MENU_SEARCH_TYPE_OP = 1,
- MENU_SEARCH_TYPE_RNA = 2,
+ enum Type {
+ Operator = 1,
+ RNA = 2,
} type;
union {
@@ -129,8 +129,8 @@ struct MenuSearch_Item {
} rna;
};
- /** Set when we need each menu item to be able to set its own context. may be NULL. */
- struct MenuSearch_Context *wm_context;
+ /** Set when we need each menu item to be able to set its own context. may be nullptr. */
+ MenuSearch_Context *wm_context;
};
struct MenuSearch_Data {
@@ -148,15 +148,15 @@ struct MenuSearch_Data {
static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
{
- const struct MenuSearch_Item *menu_item_a = menu_item_a_v;
- const struct MenuSearch_Item *menu_item_b = menu_item_b_v;
+ const MenuSearch_Item *menu_item_a = (MenuSearch_Item *)menu_item_a_v;
+ const MenuSearch_Item *menu_item_b = (MenuSearch_Item *)menu_item_b_v;
return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
}
static const char *strdup_memarena(MemArena *memarena, const char *str)
{
const uint str_size = strlen(str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size);
memcpy(str_dst, str, str_size);
return str_dst;
}
@@ -164,50 +164,53 @@ static const char *strdup_memarena(MemArena *memarena, const char *str)
static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
{
const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size);
BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
return str_dst;
}
-static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data,
+static bool menu_items_from_ui_create_item_from_button(MenuSearch_Data *data,
MemArena *memarena,
struct MenuType *mt,
const char *drawstr_submenu,
uiBut *but,
- struct MenuSearch_Context *wm_context)
+ MenuSearch_Context *wm_context)
{
- struct MenuSearch_Item *item = NULL;
+ MenuSearch_Item *item = nullptr;
/* Use override if the name is empty, this can happen with popovers. */
- const char *drawstr_override = NULL;
+ const char *drawstr_override = nullptr;
const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ?
strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0');
- if (but->optype != NULL) {
+ if (but->optype != nullptr) {
if (drawstr_is_empty) {
drawstr_override = WM_operatortype_name(but->optype, but->opptr);
}
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_OP;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::Operator;
item->op.type = but->optype;
item->op.opcontext = but->opcontext;
item->op.context = but->context;
item->op.opptr = but->opptr;
- but->opptr = NULL;
+ but->opptr = nullptr;
}
- else if (but->rnaprop != NULL) {
+ else if (but->rnaprop != nullptr) {
const int prop_type = RNA_property_type(but->rnaprop);
if (drawstr_is_empty) {
if (prop_type == PROP_ENUM) {
const int value_enum = (int)but->hardmax;
EnumPropertyItem enum_item;
- if (RNA_property_enum_item_from_value_gettexted(
- but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) {
+ if (RNA_property_enum_item_from_value_gettexted((bContext *)but->block->evil_C,
+ &but->rnapoin,
+ but->rnaprop,
+ value_enum,
+ &enum_item)) {
drawstr_override = enum_item.name;
}
else {
@@ -229,8 +232,8 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
prop_type);
}
else {
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_RNA;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::RNA;
item->rna.ptr = but->rnapoin;
item->rna.prop = but->rnaprop;
@@ -242,13 +245,12 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
}
}
- if (item != NULL) {
+ if (item != nullptr) {
/* Handle shared settings. */
- if (drawstr_override != NULL) {
+ if (drawstr_override != nullptr) {
const char *drawstr_suffix = drawstr_sep ? drawstr_sep : "";
- char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix);
- item->drawstr = strdup_memarena(memarena, drawstr_alloc);
- MEM_freeN(drawstr_alloc);
+ std::string drawstr = std::string("(") + drawstr_override + ")" + drawstr_suffix;
+ item->drawstr = strdup_memarena(memarena, drawstr.c_str());
}
else {
item->drawstr = strdup_memarena(memarena, but->drawstr);
@@ -258,7 +260,7 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
item->state = (but->flag &
(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR));
item->mt = mt;
- item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL;
+ item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : nullptr;
item->wm_context = wm_context;
@@ -272,11 +274,11 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d
/**
* Populate a fake button from a menu item (use for context menu).
*/
-static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
+static bool menu_items_to_ui_button(MenuSearch_Item *item, uiBut *but)
{
bool changed = false;
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
+ case MenuSearch_Item::Type::Operator: {
but->optype = item->op.type;
but->opcontext = item->op.opcontext;
but->context = item->op.context;
@@ -284,7 +286,7 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
changed = true;
break;
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
const int prop_type = RNA_property_type(item->rna.prop);
but->rnapoin = item->rna.ptr;
@@ -302,12 +304,12 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
if (changed) {
STRNCPY(but->drawstr, item->drawstr);
char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
if (drawstr_sep) {
*drawstr_sep = '\0';
}
- but->icon = item->icon;
+ but->icon = (BIFIconID)item->icon;
but->str = but->strdata;
}
@@ -327,13 +329,13 @@ static void menu_types_add_from_keymap_items(bContext *C,
{
wmWindowManager *wm = CTX_wm_manager(C);
ListBase *handlers[] = {
- region ? &region->handlers : NULL,
- area ? &area->handlers : NULL,
+ region ? &region->handlers : nullptr,
+ area ? &area->handlers : nullptr,
&win->handlers,
};
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
- if (handlers[handler_index] == NULL) {
+ if (handlers[handler_index] == nullptr) {
continue;
}
LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
@@ -345,7 +347,7 @@ static void menu_types_add_from_keymap_items(bContext *C,
continue;
}
- if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) {
+ if (handler_base->poll == nullptr || handler_base->poll(region, win->eventstate)) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
@@ -382,16 +384,16 @@ static void menu_types_add_from_keymap_items(bContext *C,
/**
* Display all operators (last). Developer-only convenience feature.
*/
-static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data)
+static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data)
{
/* Add to temporary list so we can sort them separately. */
- ListBase operator_items = {NULL, NULL};
+ ListBase operator_items = {nullptr, nullptr};
MemArena *memarena = data->memarena;
GHashIterator iter;
for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
BLI_ghashIterator_step(&iter)) {
- wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+ wmOperatorType *ot = (wmOperatorType *)BLI_ghashIterator_getValue(&iter);
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
continue;
@@ -400,13 +402,13 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
if (WM_operator_poll((bContext *)C, ot)) {
const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
- struct MenuSearch_Item *item = NULL;
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_OP;
+ MenuSearch_Item *item = nullptr;
+ item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MenuSearch_Item::Type::Operator;
item->op.type = ot;
item->op.opcontext = WM_OP_INVOKE_DEFAULT;
- item->op.context = NULL;
+ item->op.context = nullptr;
char idname_as_py[OP_MAX_TYPENAME];
char uiname[256];
@@ -417,7 +419,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
item->drawwstr_full = strdup_memarena(memarena, uiname);
item->drawstr = ot_ui_name;
- item->wm_context = NULL;
+ item->wm_context = nullptr;
BLI_addtail(&operator_items, item);
}
@@ -434,7 +436,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d
* - Look up predefined editor-menus.
* - Look up key-map items which call menus.
*/
-static struct MenuSearch_Data *menu_items_from_ui_create(
+static MenuSearch_Data *menu_items_from_ui_create(
bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
{
MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -444,12 +446,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
const uiStyle *style = UI_style_get_dpi();
/* Convert into non-ui structure. */
- struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__);
+ MenuSearch_Data *data = (MenuSearch_Data *)MEM_callocN(sizeof(*data), __func__);
DynStr *dyn_str = BLI_dynstr_new_memarena();
/* Use a stack of menus to handle and discover new menus in passes. */
- LinkNode *menu_stack = NULL;
+ LinkNode *menu_stack = nullptr;
/* Tag menu types not to add, either because they have already been added
* or they have been blacklisted.
@@ -466,7 +468,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
+ if (mt != nullptr) {
BLI_gset_add(menu_tagged, mt);
}
}
@@ -483,7 +485,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
for (WM_menutype_iter(&iter); (!BLI_ghashIterator_done(&iter));
(BLI_ghashIterator_step(&iter))) {
- MenuType *mt = BLI_ghashIterator_getValue(&iter);
+ MenuType *mt = (MenuType *)BLI_ghashIterator_getValue(&iter);
if (BLI_str_endswith(mt->idname, "_context_menu")) {
BLI_gset_add(menu_tagged, mt);
}
@@ -494,34 +496,33 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
- BLI_gset_remove(menu_tagged, mt, NULL);
+ if (mt != nullptr) {
+ BLI_gset_remove(menu_tagged, mt, nullptr);
}
}
}
/* Collect contexts, one for each 'ui_type'. */
- struct MenuSearch_Context *wm_contexts = NULL;
+ MenuSearch_Context *wm_contexts = nullptr;
- const EnumPropertyItem *space_type_ui_items = NULL;
+ const EnumPropertyItem *space_type_ui_items = nullptr;
int space_type_ui_items_len = 0;
bool space_type_ui_items_free = false;
/* Text used as prefix for top-bar menu items. */
- const char *global_menu_prefix = NULL;
+ const char *global_menu_prefix = nullptr;
if (include_all_areas) {
bScreen *screen = WM_window_get_active_screen(win);
/* First create arrays for ui_type. */
- PropertyRNA *prop_ui_type = NULL;
+ PropertyRNA *prop_ui_type = nullptr;
{
/* This must be a valid pointer, with only it's type checked. */
- ScrArea area_dummy = {
- /* Anything besides #SPACE_EMPTY is fine,
- * as this value is only included in the enum when set. */
- .spacetype = SPACE_TOPBAR,
- };
+ ScrArea area_dummy = {nullptr};
+ /* Anything besides #SPACE_EMPTY is fine,
+ * as this value is only included in the enum when set. */
+ area_dummy.spacetype = SPACE_TOPBAR;
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy, &ptr);
prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
@@ -532,7 +533,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
&space_type_ui_items_len,
&space_type_ui_items_free);
- wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
+ wm_contexts = (MenuSearch_Context *)BLI_memarena_calloc(
+ memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
for (int i = 0; i < space_type_ui_items_len; i++) {
wm_contexts[i].space_type_ui_index = -1;
}
@@ -540,7 +542,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
- if (region != NULL) {
+ if (region != nullptr) {
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr);
const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
@@ -573,16 +575,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len;
space_type_ui_index += 1) {
- ScrArea *area = NULL;
- ARegion *region = NULL;
- struct MenuSearch_Context *wm_context = NULL;
+ ScrArea *area = nullptr;
+ ARegion *region = nullptr;
+ MenuSearch_Context *wm_context = nullptr;
if (include_all_areas) {
if (space_type_ui_index == -1) {
/* First run without any context, to populate the top-bar without. */
- wm_context = NULL;
- area = NULL;
- region = NULL;
+ wm_context = nullptr;
+ area = nullptr;
+ region = nullptr;
}
else {
wm_context = &wm_contexts[space_type_ui_index];
@@ -607,7 +609,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
* from the buttons, however this is quite involved and can be avoided as by convention
* each space-type has a single root-menu that headers use. */
{
- const char *idname_array[2] = {NULL};
+ const char *idname_array[2] = {nullptr};
int idname_array_len = 0;
/* Use negative for global (no area) context, populate the top-bar. */
@@ -623,8 +625,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
case space_type: \
break
- if (area != NULL) {
- SpaceLink *sl = area->spacedata.first;
+ if (area != nullptr) {
+ SpaceLink *sl = (SpaceLink *)area->spacedata.first;
switch ((eSpace_Type)area->spacetype) {
SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
@@ -656,7 +658,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
for (int i = 0; i < idname_array_len; i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
+ if (mt != nullptr) {
/* Check if this exists because of 'include_all_areas'. */
if (BLI_gset_add(menu_tagged, mt)) {
BLI_linklist_prepend(&menu_stack, mt);
@@ -669,8 +671,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
bool has_keymap_menu_items = false;
- while (menu_stack != NULL) {
- MenuType *mt = BLI_linklist_pop(&menu_stack);
+ while (menu_stack != nullptr) {
+ MenuType *mt = (MenuType *)BLI_linklist_pop(&menu_stack);
if (!WM_menutype_poll(C, mt)) {
continue;
}
@@ -687,7 +689,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
UI_block_end(C, block);
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- MenuType *mt_from_but = NULL;
+ MenuType *mt_from_but = nullptr;
/* Support menu titles with dynamic from initial labels
* (used by edit-mesh context menu). */
if (but->type == UI_BTYPE_LABEL) {
@@ -698,13 +700,13 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
but_test = but_test->prev;
}
- if (but_test == NULL) {
+ if (but_test == nullptr) {
BLI_ghash_insert(
menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr));
}
}
else if (menu_items_from_ui_create_item_from_button(
- data, memarena, mt, NULL, but, wm_context)) {
+ data, memarena, mt, nullptr, but, wm_context)) {
/* pass */
}
else if ((mt_from_but = UI_but_menutype_get(but))) {
@@ -714,8 +716,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) {
- struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena,
- sizeof(*menu_parent));
+ MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_memarena_calloc(
+ memarena, sizeof(*menu_parent));
/* Use brackets for menu key shortcuts,
* converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
* This is needed so we don't right align sub-menu contents
@@ -723,9 +725,9 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
*/
const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
+ nullptr;
bool drawstr_is_empty = false;
- if (drawstr_sep != NULL) {
+ if (drawstr_sep != nullptr) {
BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
/* Detect empty string, fallback to menu name. */
const char *drawstr = but->drawstr;
@@ -760,7 +762,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
}
}
- else if (but->menu_create_func != NULL) {
+ else if (but->menu_create_func != nullptr) {
/* A non 'MenuType' menu button. */
/* Only expand one level deep, this is mainly for expanding operator menus. */
@@ -785,19 +787,21 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
if (region) {
+ BLI_ghash_remove(region->runtime.block_name_map, sub_block->name, nullptr, nullptr);
BLI_remlink(&region->uiblocks, sub_block);
}
- UI_block_free(NULL, sub_block);
+ UI_block_free(nullptr, sub_block);
}
}
if (region) {
+ BLI_ghash_remove(region->runtime.block_name_map, block->name, nullptr, nullptr);
BLI_remlink(&region->uiblocks, block);
}
- UI_block_free(NULL, block);
+ UI_block_free(nullptr, block);
/* Add key-map items as a second pass,
* so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
- if ((menu_stack == NULL) && (has_keymap_menu_items == false)) {
+ if ((menu_stack == nullptr) && (has_keymap_menu_items == false)) {
has_keymap_menu_items = true;
menu_types_add_from_keymap_items(
C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged);
@@ -805,33 +809,34 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
}
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt);
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
+ item->menu_parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, item->mt);
}
GHASH_ITER (iter, menu_parent_map) {
- struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter);
- menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt);
+ MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_ghashIterator_getValue(&iter);
+ menu_parent->parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map,
+ menu_parent->parent_mt);
}
/* NOTE: currently this builds the full path for each menu item,
* that could be moved into the parent menu. */
/* Set names as full paths. */
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
if (include_all_areas) {
BLI_dynstr_appendf(dyn_str,
"%s: ",
- (item->wm_context != NULL) ?
+ (item->wm_context != nullptr) ?
space_type_ui_items[item->wm_context->space_type_ui_index].name :
global_menu_prefix);
}
- if (item->menu_parent != NULL) {
- struct MenuSearch_Parent *menu_parent = item->menu_parent;
- menu_parent->temp_child = NULL;
+ if (item->menu_parent != nullptr) {
+ MenuSearch_Parent *menu_parent = item->menu_parent;
+ menu_parent->temp_child = nullptr;
while (menu_parent && menu_parent->parent) {
menu_parent->parent->temp_child = menu_parent;
menu_parent = menu_parent->parent;
@@ -843,14 +848,14 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
}
else {
- const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt);
- if (drawstr == NULL) {
+ const char *drawstr = (const char *)BLI_ghash_lookup(menu_display_name_map, item->mt);
+ if (drawstr == nullptr) {
drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
}
BLI_dynstr_append(dyn_str, drawstr);
- wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt);
- if (kmi != NULL) {
+ wmKeyMapItem *kmi = (wmKeyMapItem *)BLI_ghash_lookup(menu_to_kmi, item->mt);
+ if (kmi != nullptr) {
char kmi_str[128];
WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str);
@@ -860,7 +865,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
}
/* Optional nested menu. */
- if (item->drawstr_submenu != NULL) {
+ if (item->drawstr_submenu != nullptr) {
BLI_dynstr_append(dyn_str, item->drawstr_submenu);
BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " ");
}
@@ -877,12 +882,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
* NOTE: we might want to keep the in-menu order, for now sort all. */
BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full);
- BLI_ghash_free(menu_parent_map, NULL, NULL);
- BLI_ghash_free(menu_display_name_map, NULL, NULL);
+ BLI_ghash_free(menu_parent_map, nullptr, nullptr);
+ BLI_ghash_free(menu_display_name_map, nullptr, nullptr);
- BLI_ghash_free(menu_to_kmi, NULL, NULL);
+ BLI_ghash_free(menu_to_kmi, nullptr, nullptr);
- BLI_gset_free(menu_tagged, NULL);
+ BLI_gset_free(menu_tagged, nullptr);
data->memarena = memarena;
@@ -915,16 +920,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
static void menu_search_arg_free_fn(void *data_v)
{
- struct MenuSearch_Data *data = data_v;
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ MenuSearch_Data *data = (MenuSearch_Data *)data_v;
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
- if (item->op.opptr != NULL) {
+ case MenuSearch_Item::Type::Operator: {
+ if (item->op.opptr != nullptr) {
WM_operator_properties_free(item->op.opptr);
MEM_freeN(item->op.opptr);
}
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
break;
}
}
@@ -937,8 +942,8 @@ static void menu_search_arg_free_fn(void *data_v)
static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
{
- struct MenuSearch_Item *item = arg2;
- if (item == NULL) {
+ MenuSearch_Item *item = (MenuSearch_Item *)arg2;
+ if (item == nullptr) {
return;
}
if (item->state & UI_BUT_DISABLED) {
@@ -948,20 +953,20 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
+ case MenuSearch_Item::Type::Operator: {
CTX_store_set(C, item->op.context);
WM_operator_name_call_ptr_with_depends_on_cursor(
C, item->op.type, item->op.opcontext, item->op.opptr, item->drawstr);
- CTX_store_set(C, NULL);
+ CTX_store_set(C, nullptr);
break;
}
- case MENU_SEARCH_TYPE_RNA: {
+ case MenuSearch_Item::Type::RNA: {
PointerRNA *ptr = &item->rna.ptr;
PropertyRNA *prop = item->rna.prop;
const int index = item->rna.index;
@@ -992,7 +997,7 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
}
}
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
@@ -1004,19 +1009,19 @@ static void menu_search_update_fn(const bContext *UNUSED(C),
uiSearchItems *items,
const bool UNUSED(is_first))
{
- struct MenuSearch_Data *data = arg;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
StringSearch *search = BLI_string_search_new();
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- BLI_string_search_add(search, item->drawwstr_full, item);
+ LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) {
+ BLI_string_search_add(search, item->drawwstr_full, item, 0);
}
- struct MenuSearch_Item **filtered_items;
+ MenuSearch_Item **filtered_items;
const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items);
for (int i = 0; i < filtered_amount; i++) {
- struct MenuSearch_Item *item = filtered_items[i];
+ MenuSearch_Item *item = filtered_items[i];
if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) {
break;
}
@@ -1041,8 +1046,8 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
void *active,
const struct wmEvent *event)
{
- struct MenuSearch_Data *data = arg;
- struct MenuSearch_Item *item = active;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
+ MenuSearch_Item *item = (MenuSearch_Item *)active;
bool has_menu = false;
memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
@@ -1055,7 +1060,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
@@ -1064,7 +1069,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
has_menu = true;
}
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
@@ -1085,8 +1090,8 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
void *arg,
void *active)
{
- struct MenuSearch_Data *data = arg;
- struct MenuSearch_Item *item = active;
+ MenuSearch_Data *data = (MenuSearch_Data *)arg;
+ MenuSearch_Item *item = (MenuSearch_Item *)active;
memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
uiBut *but = &data->context_menu_data.but;
@@ -1112,21 +1117,21 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, item->wm_context->area);
CTX_wm_region_set(C, item->wm_context->region);
}
ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false);
- if (item->wm_context != NULL) {
+ if (item->wm_context != nullptr) {
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
return region_tip;
}
- return NULL;
+ return nullptr;
}
/** \} */
@@ -1137,14 +1142,13 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
void UI_but_func_menu_search(uiBut *but)
{
- bContext *C = but->block->evil_C;
+ bContext *C = (bContext *)but->block->evil_C;
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
/* When run from top-bar scan all areas in the current window. */
const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR));
- struct MenuSearch_Data *data = menu_items_from_ui_create(
- C, win, area, region, include_all_areas);
+ MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region, include_all_areas);
UI_but_func_search_set(but,
/* Generic callback. */
ui_searchbox_create_menu,
@@ -1153,7 +1157,7 @@ void UI_but_func_menu_search(uiBut *but)
false,
menu_search_arg_free_fn,
menu_search_exec_fn,
- NULL);
+ nullptr);
UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu);
UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index b30a86c5fcf..b8026cbb40c 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -435,7 +435,7 @@ static void id_search_cb(const bContext *C,
/* ID listbase */
LISTBASE_FOREACH (ID *, id, lb) {
if (id_search_allows_id(template_ui, flag, id, str)) {
- BLI_string_search_add(search, id->name + 2, id);
+ BLI_string_search_add(search, id->name + 2, id, 0);
}
}
@@ -470,7 +470,7 @@ static void id_search_cb_tagged(const bContext *C,
LISTBASE_FOREACH (ID *, id, lb) {
if (id->tag & LIB_TAG_DOIT) {
if (id_search_allows_id(template_ui, flag, id, str)) {
- BLI_string_search_add(search, id->name + 2, id);
+ BLI_string_search_add(search, id->name + 2, id, 0);
}
id->tag &= ~LIB_TAG_DOIT;
}
@@ -585,7 +585,6 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
/* This is for browsing and editing the ID-blocks used */
-/* for new/open operators */
void UI_context_active_but_prop_get_templateID(bContext *C,
PointerRNA *r_ptr,
PropertyRNA **r_prop)
@@ -1556,9 +1555,6 @@ void uiTemplateGpencilColorPreview(uiLayout *layout,
false);
}
-/**
- * Version of #uiTemplateID using tabs.
- */
void uiTemplateIDTabs(uiLayout *layout,
bContext *C,
PointerRNA *ptr,
@@ -1592,14 +1588,6 @@ void uiTemplateIDTabs(uiLayout *layout,
/** \name ID Chooser Template
* \{ */
-/**
- * This is for selecting the type of ID-block to use,
- * and then from the relevant type choosing the block to use.
- *
- * \param propname: property identifier for property that ID-pointer gets stored to.
- * \param proptypename: property identifier for property
- * used to determine the type of ID-pointer that can be used.
- */
void uiTemplateAnyID(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -1855,10 +1843,6 @@ static TemplateSearch *template_search_setup(PointerRNA *ptr,
return template_search;
}
-/**
- * Search menu to pick an item from a collection.
- * A version of uiTemplateID that works for non-ID types.
- */
void uiTemplateSearch(uiLayout *layout,
bContext *C,
PointerRNA *ptr,
@@ -1909,13 +1893,6 @@ void uiTemplateSearchPreview(uiLayout *layout,
/* ---------- */
-/**
- * This is creating/editing RNA-Paths
- *
- * - ptr: struct which holds the path property
- * - propname: property identifier for property that path gets stored to
- * - root_ptr: struct that path gets built from
- */
void uiTemplatePathBuilder(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -2102,9 +2079,6 @@ static void bone_constraint_panel_id(void *md_link, char *r_name)
strcat(r_name, cti->structName);
}
-/**
- * Check if the constraint panels don't match the data and rebuild the panels if so.
- */
void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_constraints)
{
ARegion *region = CTX_wm_region(C);
@@ -2260,8 +2234,6 @@ void uiTemplateGpencilModifiers(uiLayout *UNUSED(layout), bContext *C)
/** \} */
-/** \} */
-
#define ERROR_LIBDATA_MESSAGE TIP_("Can't edit external library data")
/* -------------------------------------------------------------------- */
@@ -2280,9 +2252,6 @@ static void shaderfx_panel_id(void *fx_v, char *r_idname)
BKE_shaderfxType_panel_id(fx->type, r_idname);
}
-/**
- * Check if the shader effect panels don't match the data and rebuild the panels if so.
- */
void uiTemplateShaderFx(uiLayout *UNUSED(layout), bContext *C)
{
ARegion *region = CTX_wm_region(C);
@@ -2564,11 +2533,6 @@ static bool ui_layout_operator_properties_only_booleans(const bContext *C,
return true;
}
-/**
- * Draw Operator property buttons for redoing execution with different settings.
- * This function does not initialize the layout,
- * functions can be called on the layout before and after.
- */
void uiTemplateOperatorPropertyButs(
const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag)
{
@@ -2727,7 +2691,12 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co
PointerRNA ptr;
RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
- uiLayoutSetContextPointer(layout, "constraint", &ptr);
+ if (block->panel) {
+ UI_panel_context_pointer_set(block->panel, "constraint", &ptr);
+ }
+ else {
+ uiLayoutSetContextPointer(layout, "constraint", &ptr);
+ }
/* Constraint type icon. */
uiLayout *sub = uiLayoutRow(layout, false);
@@ -3532,9 +3501,6 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
/** \name Icon Template
* \{ */
-/**
- * \param icon_scale: Scale of the icon, 1x == button height.
- */
void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale)
{
uiBlock *block = uiLayoutAbsoluteBlock(layout);
@@ -3643,9 +3609,6 @@ static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *region, void *arg_lit
return block;
}
-/**
- * \param icon_scale: Scale of the icon, 1x == button height.
- */
void uiTemplateIconView(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -4152,51 +4115,6 @@ static uiBlock *curvemap_tools_func(
0,
UICURVE_FUNC_RESET_VIEW,
"");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Vector Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_VECTOR,
- "");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Auto Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_AUTO,
- "");
- uiDefIconTextBut(block,
- UI_BTYPE_BUT_MENU,
- 1,
- ICON_BLANK1,
- IFACE_("Auto Clamped Handle"),
- 0,
- yco -= UI_UNIT_Y,
- menuwidth,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0,
- UICURVE_FUNC_HANDLE_AUTO_ANIM,
- "");
}
if (show_extend) {
@@ -4276,6 +4194,21 @@ static uiBlock *curvemap_brush_tools_negslope_func(bContext *C, ARegion *region,
return curvemap_tools_func(C, region, cumap_v, false, UICURVE_FUNC_RESET_POS);
}
+static void curvemap_tools_handle_vector(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_VECTOR);
+}
+
+static void curvemap_tools_handle_auto(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_AUTO);
+}
+
+static void curvemap_tools_handle_auto_clamped(bContext *C, void *cumap_v, void *UNUSED(arg))
+{
+ curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_AUTO_ANIM);
+}
+
static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
{
ED_region_tag_redraw(CTX_wm_region(C));
@@ -4327,6 +4260,8 @@ static void curvemap_buttons_layout(uiLayout *layout,
uiBlock *block = uiLayoutGetBlock(layout);
+ UI_block_emboss_set(block, UI_EMBOSS);
+
if (tone) {
uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
uiItemR(uiLayoutRow(split, false), ptr, "tone", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
@@ -4412,10 +4347,11 @@ static void curvemap_buttons_layout(uiLayout *layout,
}
/* operation buttons */
- uiLayoutRow(row, true);
-
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* (Right aligned) */
+ uiLayout *sub = uiLayoutRow(row, true);
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
+ /* Zoom in */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
@@ -4432,6 +4368,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
TIP_("Zoom in"));
UI_but_func_set(bt, curvemap_buttons_zoom_in, cumap, NULL);
+ /* Zoom out */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
@@ -4448,97 +4385,53 @@ static void curvemap_buttons_layout(uiLayout *layout,
TIP_("Zoom out"));
UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, NULL);
+ /* Clippoing button. */
+ const int icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
+ bt = uiDefIconBlockBut(
+ block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
+ bt->drawflag &= ~UI_BUT_ICON_LEFT;
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+
if (brush && neg_slope) {
- bt = uiDefIconBlockBut(block,
- curvemap_brush_tools_negslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_brush_tools_negslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else if (brush) {
- bt = uiDefIconBlockBut(block,
- curvemap_brush_tools_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_brush_tools_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else if (neg_slope) {
- bt = uiDefIconBlockBut(block,
- curvemap_tools_negslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_tools_negslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
else {
- bt = uiDefIconBlockBut(block,
- curvemap_tools_posslope_func,
- cumap,
- 0,
- ICON_DOWNARROW_HLT,
- 0,
- 0,
- dx,
- dx,
- TIP_("Tools"));
+ bt = uiDefIconBlockBut(
+ block, curvemap_tools_posslope_func, cumap, 0, 0, 0, 0, dx, dx, TIP_("Tools"));
}
-
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
- const int icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
- bt = uiDefIconBlockBut(
- block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
- UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
-
- bt = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_X,
- 0,
- 0,
- dx,
- dx,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Delete points"));
- UI_but_funcN_set(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
-
- UI_block_emboss_set(block, UI_EMBOSS);
-
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
- /* curve itself */
+ /* Curve itself. */
const int size = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
row = uiLayoutRow(layout, false);
uiButCurveMapping *curve_but = (uiButCurveMapping *)uiDefBut(
- block, UI_BTYPE_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, 0, 0, "");
+ block, UI_BTYPE_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, -1, 0, "");
curve_but->gradient_type = bg;
- /* sliders for selected point */
+ /* Sliders for selected curve point. */
+ int i;
CurveMapPoint *cmp = NULL;
- for (int i = 0; i < cm->totpoint; i++) {
+ bool point_last_or_first = false;
+ for (i = 0; i < cm->totpoint; i++) {
if (cm->curve[i].flag & CUMA_SELECT) {
cmp = &cm->curve[i];
break;
}
}
+ if (ELEM(i, 0, cm->totpoint - 1)) {
+ point_last_or_first = true;
+ }
if (cmp) {
rctf bounds;
@@ -4550,12 +4443,75 @@ static void curvemap_buttons_layout(uiLayout *layout,
bounds.xmax = bounds.ymax = 1000.0;
}
+ UI_block_emboss_set(block, UI_EMBOSS);
+
uiLayoutRow(layout, true);
+
+ /* Curve handle buttons. */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_AUTO,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Auto Handle"));
+ UI_but_func_set(bt, curvemap_tools_handle_auto, cumap, NULL);
+ if (((cmp->flag & CUMA_HANDLE_AUTO_ANIM) == false) &&
+ ((cmp->flag & CUMA_HANDLE_VECTOR) == false)) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_VECTOR,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Vector Handle"));
+ UI_but_func_set(bt, curvemap_tools_handle_vector, cumap, NULL);
+ if (cmp->flag & CUMA_HANDLE_VECTOR) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 1,
+ ICON_HANDLE_AUTOCLAMPED,
+ 0,
+ UI_UNIT_Y,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Auto Clamped"));
+ UI_but_func_set(bt, curvemap_tools_handle_auto_clamped, cumap, NULL);
+ if (cmp->flag & CUMA_HANDLE_AUTO_ANIM) {
+ bt->flag |= UI_SELECT_DRAW;
+ }
+
+ /* Curve handle position */
UI_block_funcN_set(block, curvemap_buttons_update, MEM_dupallocN(cb), cumap);
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
- "X",
+ "X:",
0,
2 * UI_UNIT_Y,
UI_UNIT_X * 10,
@@ -4571,7 +4527,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
- "Y",
+ "Y:",
0,
1 * UI_UNIT_Y,
UI_UNIT_X * 10,
@@ -4584,6 +4540,26 @@ static void curvemap_buttons_layout(uiLayout *layout,
"");
UI_but_number_step_size_set(bt, 1);
UI_but_number_precision_set(bt, 5);
+
+ /* Curve handle delete point */
+ bt = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_X,
+ 0,
+ 0,
+ dx,
+ dx,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Delete points"));
+ UI_but_funcN_set(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
+ if (point_last_or_first) {
+ UI_but_flag_enable(bt, UI_BUT_DISABLED);
+ }
}
/* black/white levels */
@@ -5030,11 +5006,6 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
sub = uiLayoutRow(row, true);
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
- /* Reset view, reset curve */
- bt = uiDefIconBlockBut(
- block, CurveProfile_buttons_tools, profile, 0, 0, 0, 0, UI_UNIT_X, UI_UNIT_X, TIP_("Tools"));
- UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
-
/* Flip path */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
@@ -5070,6 +5041,11 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
TIP_("Toggle Profile Clipping"));
UI_but_funcN_set(bt, CurveProfile_clipping_toggle, MEM_dupallocN(cb), profile);
+ /* Reset view, reset curve */
+ bt = uiDefIconBlockBut(
+ block, CurveProfile_buttons_tools, profile, 0, 0, 0, 0, UI_UNIT_X, UI_UNIT_X, TIP_("Tools"));
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
+
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
/* The path itself */
@@ -5213,10 +5189,6 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
UI_block_funcN_set(block, NULL, NULL, NULL);
}
-/**
- * Template for a path creation widget intended for custom bevel profiles.
- * This section is quite similar to #uiTemplateCurveMapping, but with reduced complexity.
- */
void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -5263,7 +5235,6 @@ void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propn
#define WHEEL_SIZE (5 * U.widget_unit)
-/* This template now follows User Preference for type - name is not correct anymore... */
void uiTemplateColorPicker(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -5654,10 +5625,6 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
/* see view3d_header.c */
}
-/**
- * \todo for now, grouping of layers is determined by dividing up the length of
- * the array of layer bitflags
- */
void uiTemplateLayers(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.c
index 40f196d9b45..6916e1080b6 100644
--- a/source/blender/editors/interface/interface_undo.c
+++ b/source/blender/editors/interface/interface_undo.c
@@ -91,11 +91,6 @@ const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_curs
return ui_textedit_redo_impl(stack, r_cursor_index);
}
-/**
- * Push the information in the arguments to a new state in the undo stack.
- *
- * \note Currently the total length of the undo stack is not limited.
- */
void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor_index)
{
/* Clear all redo actions from the current state. */
@@ -114,11 +109,7 @@ void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor
memcpy(stack->current->text, text, text_size);
BLI_addtail(&stack->states, stack->current);
}
-/**
- * Start the undo stack.
- *
- * \note The current state should be pushed immediately after calling this.
- */
+
uiUndoStack_Text *ui_textedit_undo_stack_create(void)
{
uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__);
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 1a41dc8e9fb..84ec5f939d2 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -354,12 +354,6 @@ uiBut *uiDefAutoButR(uiBlock *block,
return but;
}
-/**
- * \a check_prop callback filters functions to avoid drawing certain properties,
- * in cases where PROP_HIDDEN flag can't be used for a property.
- *
- * \param prop_activate_init: Property to activate on initial popup (#UI_BUT_ACTIVATE_ON_INIT).
- */
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
PointerRNA *ptr,
bool (*check_prop)(PointerRNA *ptr,
@@ -552,7 +546,7 @@ void ui_rna_collection_search_update_fn(const struct bContext *C,
cis->name_prefix_offset = name_prefix_offset;
cis->has_sep_char = has_sep_char;
if (!skip_filter) {
- BLI_string_search_add(search, name, cis);
+ BLI_string_search_add(search, name, cis, 0);
}
BLI_addtail(items_list, cis);
if (name != name_buf) {
@@ -593,7 +587,6 @@ void ui_rna_collection_search_update_fn(const struct bContext *C,
MEM_freeN(items_list);
}
-/***************************** ID Utilities *******************************/
int UI_icon_from_id(const ID *id)
{
if (id == NULL) {
@@ -618,7 +611,6 @@ int UI_icon_from_id(const ID *id)
return (ptr.type) ? RNA_struct_ui_icon(ptr.type) : ICON_NONE;
}
-/* see: report_type_str */
int UI_icon_from_report_type(int type)
{
if (type & RPT_ERROR_ALL) {
@@ -690,10 +682,6 @@ int UI_text_colorid_from_report_type(int type)
/********************************** Misc **************************************/
-/**
- * Returns the best "UI" precision for given floating value,
- * so that e.g. 10.000001 rather gets drawn as '10'...
- */
int UI_calc_float_precision(int prec, double value)
{
static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {
@@ -839,16 +827,6 @@ static bool ui_view2d_cur_ensure_rect_in_view(View2D *v2d, const rctf *rect)
return changed;
}
-/**
- * Adjust the view so the rectangle of \a but is in view, with some extra margin.
- *
- * It's important that this is only executed after buttons received their final #uiBut.rect. E.g.
- * #UI_panels_end() modifies them, so if that is executed, this function must not be called before
- * it.
- *
- * \param region: The region the button is placed in. Make sure this is actually the one the button
- * is placed in, not just the context region.
- */
void UI_but_ensure_in_view(const bContext *C, ARegion *region, const uiBut *but)
{
View2D *v2d = &region->v2d;
@@ -892,9 +870,6 @@ struct uiButStoreElem {
uiBut **but_p;
};
-/**
- * Create a new button store, the caller must manage and run #UI_butstore_free
- */
uiButStore *UI_butstore_create(uiBlock *block)
{
uiButStore *bs_handle = MEM_callocN(sizeof(uiButStore), __func__);
@@ -966,9 +941,6 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p)
BLI_assert(0);
}
-/**
- * Update the pointer for a registered button.
- */
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src)
{
bool found = false;
@@ -985,9 +957,6 @@ bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *bu
return found;
}
-/**
- * NULL all pointers, don't free since the owner needs to be able to inspect.
- */
void UI_butstore_clear(uiBlock *block)
{
LISTBASE_FOREACH (uiButStore *, bs_handle, &block->butstore) {
@@ -998,9 +967,6 @@ void UI_butstore_clear(uiBlock *block)
}
}
-/**
- * Map freed buttons from the old block and update pointers.
- */
void UI_butstore_update(uiBlock *block)
{
/* move this list to the new block */
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 4e38f245155..500834f4434 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -46,7 +46,7 @@ struct ViewLink : public Link {
using TreeViewPtr = std::unique_ptr<AbstractTreeView>;
std::string idname;
- /* Note: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
+ /* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
std::variant<TreeViewPtr> view;
};
@@ -56,9 +56,6 @@ template<class T> T *get_view_from_link(ViewLink &link)
return t_uptr ? t_uptr->get() : nullptr;
}
-/**
- * Override this for all available tree types.
- */
AbstractTreeView *UI_block_add_view(uiBlock &block,
StringRef idname,
std::unique_ptr<AbstractTreeView> tree_view)
@@ -79,9 +76,6 @@ void ui_block_free_views(uiBlock *block)
}
}
-/**
- * \param x, y: Coordinate to find a tree-row item at, in window space.
- */
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2])
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy);
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 7d1b7b80ccd..ad8c0842657 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "DNA_brush_types.h"
+#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BLI_listbase.h"
@@ -45,6 +46,7 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
+#include "UI_view2d.h"
#include "interface_intern.h"
@@ -99,6 +101,10 @@ typedef enum {
UI_WTYPE_PULLDOWN,
UI_WTYPE_MENU_ITEM,
+ /* Same as #UI_WTYPE_MENU_ITEM, but doesn't add padding to sides for text & icon inside the
+ * widget. To be used when multiple menu items should be displayed close to each other
+ * horizontally. */
+ UI_WTYPE_MENU_ITEM_UNPADDED,
UI_WTYPE_MENU_ITEM_RADIAL,
UI_WTYPE_MENU_BACK,
@@ -114,7 +120,6 @@ typedef enum {
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
- UI_WTYPE_DATASETROW,
UI_WTYPE_TREEROW,
} uiWidgetTypeEnum;
@@ -268,8 +273,9 @@ typedef struct uiWidgetType {
uiWidgetColors wcol;
void (*state)(struct uiWidgetType *, int state, int drawflag, eUIEmbossType emboss);
- void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign);
- void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign);
+ void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
+ void (*custom)(
+ uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign, const float zoom);
void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
} uiWidgetType;
@@ -551,7 +557,6 @@ static void draw_anti_tria(
GPU_blend(GPU_BLEND_NONE);
}
-/* Triangle 'icon' for panel header and other cases. */
void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
{
const float f3 = 0.05 * U.widget_unit;
@@ -1514,17 +1519,6 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle,
}
}
-/**
- * Cut off the middle of the text to fit into the given width.
- *
- * \note in case this middle clipping would just remove a few chars,
- * it rather clips right, which is more readable.
- *
- * If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep
- * is preserved at all cost.
- * Useful for strings with shortcuts
- * (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
- */
float UI_text_clip_middle_ex(const uiFontStyle *fstyle,
char *str,
float okwidth,
@@ -2596,6 +2590,27 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossTyp
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Widget Corner Radius Calculation
+ *
+ * A lot of places of the UI like the Node Editor or panels are zoomable. In most cases we can
+ * get the zoom factor from the aspect, but in some cases like popups we need to fall back to
+ * using the the size of the element. The latter method relies on the element always being the same
+ * size.
+ * \{ */
+
+static float widget_radius_from_zoom(const float zoom, const uiWidgetColors *wcol)
+{
+ return wcol->roundness * U.widget_unit * zoom;
+}
+
+static float widget_radius_from_rcti(const rcti *rect, const uiWidgetColors *wcol)
+{
+ return wcol->roundness * BLI_rcti_size_y(rect);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Widget Types
* \{ */
@@ -2786,7 +2801,8 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
immUnbindProgram();
}
-static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
+static void widget_menu_back(
+ uiWidgetColors *wcol, rcti *rect, int flag, int direction, const float zoom)
{
uiWidgetBase wtb;
int roundboxalign = UI_CNR_ALL;
@@ -2808,29 +2824,31 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
}
GPU_blend(GPU_BLEND_ALPHA);
- widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
+ const float radius = widget_radius_from_zoom(zoom, wcol);
+ widget_softshadow(rect, roundboxalign, radius);
- round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
+ round_box_edges(&wtb, roundboxalign, rect, radius);
wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
GPU_blend(GPU_BLEND_NONE);
}
-static void ui_hsv_cursor(float x, float y)
+static void ui_hsv_cursor(const float x, const float y, const float zoom)
{
+ const float radius = zoom * 3.0f * U.pixelsize;
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
- imm_draw_circle_fill_2d(pos, x, y, 3.0f * U.pixelsize, 8);
+ imm_draw_circle_fill_2d(pos, x, y, radius, 8);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
immUniformColor3f(0.0f, 0.0f, 0.0f);
- imm_draw_circle_wire_2d(pos, x, y, 3.0f * U.pixelsize, 12);
+ imm_draw_circle_wire_2d(pos, x, y, radius, 12);
GPU_blend(GPU_BLEND_NONE);
GPU_line_smooth(false);
@@ -2851,7 +2869,6 @@ void ui_hsvcircle_vals_from_pos(
*r_val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
}
-/* cursor in hsv circle, in float units -1 to 1, to map on radius */
void ui_hsvcircle_pos_from_vals(
const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *r_xpos, float *r_ypos)
{
@@ -2978,7 +2995,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
float xpos, ypos;
ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos);
- ui_hsv_cursor(xpos, ypos);
+ const float zoom = 1.0f / but->block->aspect;
+ ui_hsv_cursor(xpos, ypos, zoom);
}
/** \} */
@@ -2987,7 +3005,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const
/** \name Draw Custom Buttons
* \{ */
-/* draws in resolution of 48x4 colors */
void ui_draw_gradient(const rcti *rect,
const float hsv[3],
const eButGradientType type,
@@ -3212,7 +3229,9 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
- ui_hsv_cursor(x, y);
+ const float zoom = 1.0f / but->block->aspect;
+
+ ui_hsv_cursor(x, y, zoom);
/* outline */
const uint pos = GPU_vertformat_attr_add(
@@ -3275,8 +3294,9 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
y = rect->ymin + v * BLI_rcti_size_y(rect);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
+ const float zoom = 1.0f / but->block->aspect;
- ui_hsv_cursor(x, y);
+ ui_hsv_cursor(x, y, zoom);
}
/** Separator for menus. */
@@ -3315,9 +3335,9 @@ static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
* \{ */
static void widget_numbut_draw(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss)
+ uiWidgetColors *wcol, rcti *rect, const float zoom, int state, int roundboxalign, bool emboss)
{
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
if (state & UI_SELECT) {
@@ -3416,17 +3436,19 @@ static void widget_numbut_draw(
}
}
-static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_numbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- widget_numbut_draw(wcol, rect, state, roundboxalign, false);
+ widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, false);
}
-static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_menubut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
@@ -3465,13 +3487,16 @@ static void widget_menubut_embossn(const uiBut *UNUSED(but),
/**
* Draw number buttons still with triangles when field is not embossed
*/
-static void widget_numbut_embossn(
- const uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_numbut_embossn(const uiBut *UNUSED(but),
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int roundboxalign,
+ const float zoom)
{
- widget_numbut_draw(wcol, rect, state, roundboxalign, true);
+ widget_numbut_draw(wcol, rect, zoom, state, roundboxalign, true);
}
-/* function in use for buttons and for view2d sliders */
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
{
uiWidgetBase wtb;
@@ -3559,8 +3584,12 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
}
}
-static void widget_scroll(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
+static void widget_scroll(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
/* calculate slider part */
const float value = (float)ui_but_value_get(but);
@@ -3617,8 +3646,12 @@ static void widget_scroll(
UI_draw_widget_scroll(wcol, rect, &rect1, state);
}
-static void widget_progressbar(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_progressbar(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiButProgressbar *but_progressbar = (uiButProgressbar *)but;
rcti rect_prog = *rect, rect_bar = *rect;
@@ -3629,7 +3662,7 @@ static void widget_progressbar(
/* round corners */
const float value = but_progressbar->progress;
- const float ofs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
+ const float ofs = widget_radius_from_zoom(zoom, wcol);
float w = value * BLI_rcti_size_x(&rect_prog);
/* Ensure minimum size. */
@@ -3648,15 +3681,19 @@ static void widget_progressbar(
widgetbase_draw(&wtb_bar, wcol);
}
-static void widget_treerow_exec(
- uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign), int indentation)
+static void widget_treerow_exec(uiWidgetColors *wcol,
+ rcti *rect,
+ int state,
+ int UNUSED(roundboxalign),
+ int indentation,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
/* no outline */
wtb.draw_outline = false;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
if ((state & UI_ACTIVE) || (state & UI_SELECT)) {
@@ -3668,23 +3705,19 @@ static void widget_treerow_exec(
}
static void widget_treerow(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
uiButTreeRow *tree_row = (uiButTreeRow *)but;
BLI_assert(but->type == UI_BTYPE_TREEROW);
- widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation);
+ widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation, zoom);
}
-static void widget_datasetrow(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
-{
- uiButDatasetRow *dataset_row = (uiButDatasetRow *)but;
- BLI_assert(but->type == UI_BTYPE_DATASETROW);
- widget_treerow_exec(wcol, rect, state, roundboxalign, dataset_row->indentation);
-}
-
-static void widget_nodesocket(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_nodesocket(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
const int radi = 0.25f * BLI_rcti_size_y(rect);
@@ -3719,14 +3752,14 @@ static void widget_nodesocket(
}
static void widget_numslider(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
uiWidgetBase wtb, wtb1;
widget_init(&wtb);
widget_init(&wtb1);
/* Backdrop first. */
- const float ofs = wcol->roundness * BLI_rcti_size_y(rect);
+ const float ofs = widget_radius_from_zoom(zoom, wcol);
const float toffs = ofs * 0.75f;
round_box_edges(&wtb, roundboxalign, rect, ofs);
@@ -3829,7 +3862,7 @@ static void widget_numslider(
#define SWATCH_KEYED_BORDER 3
static void widget_swatch(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
BLI_assert(but->type == UI_BTYPE_COLOR);
uiButColor *color_but = (uiButColor *)but;
@@ -3848,7 +3881,7 @@ static void widget_swatch(
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
ui_but_v3_get(but, col);
@@ -3913,14 +3946,19 @@ static void widget_swatch(
}
}
-static void widget_unitvec(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_unitvec(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
{
- ui_draw_but_UNITVEC(but, wcol, rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+ ui_draw_but_UNITVEC(but, wcol, rect, rad);
}
static void widget_icon_has_anim(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+ uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
but->emboss != UI_EMBOSS_NONE) {
@@ -3928,14 +3966,14 @@ static void widget_icon_has_anim(
widget_init(&wtb);
wtb.draw_outline = false;
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
else if (but->type == UI_BTYPE_NUM) {
/* Draw number buttons still with left/right
* triangles when field is not embossed */
- widget_numbut_embossn(but, wcol, rect, state, roundboxalign);
+ widget_numbut_embossn(but, wcol, rect, state, roundboxalign, zoom);
}
else if (but->type == UI_BTYPE_MENU) {
/* Draw menu buttons still with down arrow. */
@@ -3943,7 +3981,8 @@ static void widget_icon_has_anim(
}
}
-static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_textbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
if (state & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
@@ -3952,43 +3991,46 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_preview_tile(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_preview_tile(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
const uiStyle *style = UI_style_get();
ui_draw_preview_item_stateless(
&style->widget, rect, but->drawstr, but->icon, wcol->text, UI_STYLE_TEXT_CENTER);
}
-static void widget_menuiconbut(uiWidgetColors *wcol,
- rcti *rect,
- int UNUSED(state),
- int roundboxalign)
+static void widget_menuiconbut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
widgetbase_draw(&wtb, wcol);
}
-static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_pulldownbut(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
float back[4];
UI_GetThemeColor4fv(TH_BACK, back);
if ((state & UI_ACTIVE) || (back[3] < 1.0f)) {
uiWidgetBase wtb;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
if (state & UI_ACTIVE) {
copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
@@ -4012,26 +4054,54 @@ static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int
static void widget_menu_itembut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
/* Padding on the sides. */
- const float padding = 0.125f * BLI_rcti_size_y(rect);
+ const float padding = zoom * 0.125f * U.widget_unit;
rect->xmin += padding;
rect->xmax -= padding;
/* No outline. */
wtb.draw_outline = false;
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_menu_radial_itembut(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_menu_itembut_unpadded(uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
+{
+ /* This function is used for menu items placed close to each other horizontally, e.g. the matcap
+ * preview popup or the row of collection color icons in the Outliner context menu. Don't use
+ * padding on the sides like the normal menu item. */
+
+ uiWidgetBase wtb;
+ widget_init(&wtb);
+
+ /* No outline. */
+ wtb.draw_outline = false;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+ round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
+
+ widgetbase_draw(&wtb, wcol);
+}
+
+static void widget_menu_radial_itembut(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int UNUSED(roundboxalign),
+ const float zoom)
{
const float fac = but->block->pie_data.alphafac;
@@ -4040,7 +4110,7 @@ static void widget_menu_radial_itembut(
wtb.draw_emboss = false;
- const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
wcol->inner[3] *= fac;
@@ -4056,14 +4126,15 @@ static void widget_menu_radial_itembut(
static void widget_list_itembut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
/* no outline */
wtb.draw_outline = false;
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4072,7 +4143,8 @@ static void widget_list_itembut(uiWidgetColors *wcol,
static void widget_optionbut(uiWidgetColors *wcol,
rcti *rect,
int state,
- int UNUSED(roundboxalign))
+ int UNUSED(roundboxalign),
+ const float UNUSED(zoom))
{
const bool text_before_widget = (state & UI_STATE_TEXT_BEFORE_WIDGET);
rcti recttemp = *rect;
@@ -4095,7 +4167,7 @@ static void widget_optionbut(uiWidgetColors *wcol,
/* Keep one edge in place. */
BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
- const float rad = wcol->roundness * BLI_rcti_size_y(&recttemp);
+ const float rad = widget_radius_from_rcti(&recttemp, wcol);
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
/* decoration */
@@ -4142,19 +4214,24 @@ static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmb
}
}
-static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_radiobut(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_box(
- uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_box(uiBut *but,
+ uiWidgetColors *wcol,
+ rcti *rect,
+ int UNUSED(state),
+ int roundboxalign,
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4170,7 +4247,7 @@ static void widget_box(
wcol->inner[3] = but->col[3];
}
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4178,12 +4255,13 @@ static void widget_box(
copy_v3_v3_uchar(wcol->inner, old_col);
}
-static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+static void widget_but(
+ uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign, const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -4204,10 +4282,9 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
}
#endif
-static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_roundbut_exec(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- const float rad = wcol->roundness * U.widget_unit;
-
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4216,15 +4293,18 @@ static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, in
shape_preset_init_hold_action(&wtb.tria1, rect, 0.75f, 'r');
}
+ const float rad = widget_radius_from_zoom(zoom, wcol);
+
/* half rounded */
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
-static void widget_tab(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+static void widget_tab(
+ uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
{
- const float rad = wcol->roundness * U.widget_unit;
+ const float rad = widget_radius_from_zoom(zoom, wcol);
const bool is_active = (state & UI_SELECT);
/* Draw shaded outline - Disabled for now,
@@ -4421,6 +4501,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.state = widget_state_menu_item;
break;
+ case UI_WTYPE_MENU_ITEM_UNPADDED:
+ wt.wcol_theme = &btheme->tui.wcol_menu_item;
+ wt.draw = widget_menu_itembut_unpadded;
+ wt.state = widget_state_menu_item;
+ break;
+
case UI_WTYPE_MENU_BACK:
wt.wcol_theme = &btheme->tui.wcol_menu_back;
wt.draw = widget_menu_back;
@@ -4476,10 +4562,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.custom = widget_progressbar;
break;
- case UI_WTYPE_DATASETROW:
- wt.custom = widget_datasetrow;
- break;
-
case UI_WTYPE_TREEROW:
wt.custom = widget_treerow;
break;
@@ -4565,11 +4647,12 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
return roundbox;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Public API
* \{ */
-/* conversion from old to new buttons, so still messy */
void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
{
bTheme *btheme = UI_GetTheme();
@@ -4586,9 +4669,12 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
case UI_BTYPE_SEPR_LINE:
ui_draw_separator(rect, &tui->wcol_menu_item);
break;
- default:
- wt = widget_type(UI_WTYPE_MENU_ITEM);
+ default: {
+ const bool use_unpadded = (but->flag & UI_BUT_ICON_PREVIEW) ||
+ ((but->flag & UI_HAS_ICON) && !but->drawstr[0]);
+ wt = widget_type(use_unpadded ? UI_WTYPE_MENU_ITEM_UNPADDED : UI_WTYPE_MENU_ITEM);
break;
+ }
}
}
else if (ELEM(but->emboss, UI_EMBOSS_NONE, UI_EMBOSS_NONE_OR_STATUS)) {
@@ -4811,11 +4897,6 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
fstyle = &style->widgetlabel;
break;
- case UI_BTYPE_DATASETROW:
- wt = widget_type(UI_WTYPE_DATASETROW);
- fstyle = &style->widgetlabel;
- break;
-
case UI_BTYPE_TREEROW:
wt = widget_type(UI_WTYPE_TREEROW);
fstyle = &style->widgetlabel;
@@ -4897,12 +4978,13 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
}
#endif
+ const float zoom = 1.0f / but->block->aspect;
wt->state(wt, state, drawflag, but->emboss);
if (wt->custom) {
- wt->custom(but, &wt->wcol, rect, state, roundboxalign);
+ wt->custom(but, &wt->wcol, rect, state, roundboxalign, zoom);
}
else if (wt->draw) {
- wt->draw(&wt->wcol, rect, state, roundboxalign);
+ wt->draw(&wt->wcol, rect, state, roundboxalign, zoom);
}
if (wt->text) {
@@ -4945,10 +5027,11 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
if (block) {
- wt->draw(&wt->wcol, rect, block->flag, block->direction);
+ const float zoom = 1.0f / block->aspect;
+ wt->draw(&wt->wcol, rect, block->flag, block->direction, zoom);
}
else {
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5042,8 +5125,9 @@ void ui_draw_popover_back(struct ARegion *region,
wt->wcol_theme, rect, block->direction, U.widget_unit / block->aspect, mval_origin);
}
else {
+ const float zoom = 1.0f / block->aspect;
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, zoom);
}
ui_draw_clip_tri(block, rect, wt);
@@ -5235,7 +5319,7 @@ static void ui_draw_widget_back_color(uiWidgetTypeEnum type,
if (color) {
rgba_float_to_uchar(wt->wcol.inner, color);
}
- wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL);
+ wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL, 1.0f);
}
void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
{
@@ -5252,18 +5336,9 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
/* wt->draw ends up using same function to draw the tooltip as menu_back */
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
}
-/**
- * Helper call to draw a menu item without a button.
- *
- * \param state: The state of the button,
- * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
- * \param separator_type: The kind of separator which controls if and how the string is clipped.
- * \param r_xmax: The right hand position of the text, this takes into the icon,
- * padding and text clipping when there is not enough room to display the full text.
- */
void ui_draw_menu_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -5280,7 +5355,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
char *cpoin = NULL;
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
UI_fontstyle_set(fstyle);
@@ -5402,10 +5477,6 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
}
}
-/**
- * Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
- * state. It just draws the preview and text directly.
- */
void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
@@ -5466,11 +5537,11 @@ void ui_draw_preview_item(const uiFontStyle *fstyle,
int state,
eFontStyle_Align text_align)
{
- uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
+ uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM_UNPADDED);
/* drawing button background */
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
- wt->draw(&wt->wcol, rect, 0, 0);
+ wt->draw(&wt->wcol, rect, 0, 0, 1.0f);
ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
}
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index d960f5e6b1d..3b511e23384 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1035,12 +1035,6 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
return (const uchar *)cp;
}
-/**
- * Initialize default theme.
- *
- * \note When you add new colors, created & saved themes need initialized
- * use function below, #init_userdef_do_versions.
- */
void UI_theme_init_default(void)
{
/* we search for the theme with name Default */
@@ -1091,9 +1085,6 @@ bTheme *UI_GetTheme(void)
return U.themes.first;
}
-/**
- * For the rare case we need to temp swap in a different theme (off-screen render).
- */
void UI_Theme_Store(struct bThemeState *theme_state)
{
*theme_state = g_theme_state;
@@ -1163,21 +1154,18 @@ void UI_FontThemeColor(int fontid, int colorid)
BLF_color4ubv(fontid, color);
}
-/* get individual values, not scaled */
float UI_GetThemeValuef(int colorid)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
return ((float)cp[0]);
}
-/* get individual values, not scaled */
int UI_GetThemeValue(int colorid)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
return ((int)cp[0]);
}
-/* versions of the function above, which take a space-type */
float UI_GetThemeValueTypef(int colorid, int spacetype)
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
@@ -1190,7 +1178,6 @@ int UI_GetThemeValueType(int colorid, int spacetype)
return ((int)cp[0]);
}
-/* get the color, range 0.0-1.0 */
void UI_GetThemeColor3fv(int colorid, float col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1217,7 +1204,6 @@ void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4])
col[3] = ((float)cp[3]) / 255.0f;
}
-/* get the color, range 0.0-1.0, complete with shading offset */
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1350,7 +1336,6 @@ void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int of
col[3] = ((float)a) / 255.0f;
}
-/* get the color, in char pointer */
void UI_GetThemeColor3ubv(int colorid, uchar col[3])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1359,7 +1344,6 @@ void UI_GetThemeColor3ubv(int colorid, uchar col[3])
col[2] = cp[2];
}
-/* get the color, range 0.0-1.0, complete with shading offset */
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1381,7 +1365,6 @@ void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
col[3] = ((float)a) / 255.0f;
}
-/* get the color, in char pointer */
void UI_GetThemeColor4ubv(int colorid, uchar col[4])
{
const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
@@ -1459,7 +1442,6 @@ void UI_GetColorPtrShade3ubv(const uchar cp[3], uchar col[3], int offset)
col[2] = b;
}
-/* get a 3 byte color, blended and shaded between two other char color pointers */
void UI_GetColorPtrBlendShade3ubv(
const uchar cp1[3], const uchar cp2[3], uchar col[3], float fac, int offset)
{
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index fcc878c440c..3010aaba5a3 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -39,8 +39,8 @@ namespace blender::ui {
/* ---------------------------------------------------------------------- */
/**
- * Add a tree-item to the container. This is the only place where items should be added, it handles
- * important invariants!
+ * Add a tree-item to the container. This is the only place where items should be added, it
+ * handles important invariants!
*/
AbstractTreeViewItem &TreeViewItemContainer::add_tree_item(
std::unique_ptr<AbstractTreeViewItem> item)
@@ -87,19 +87,6 @@ bool AbstractTreeView::is_renaming() const
return rename_buffer_ != nullptr;
}
-void AbstractTreeView::build_layout_from_tree(const TreeViewLayoutBuilder &builder)
-{
- uiLayout *prev_layout = builder.current_layout();
-
- uiLayout *box = uiLayoutBox(prev_layout);
- uiLayoutColumn(box, false);
-
- foreach_item([&builder](AbstractTreeViewItem &item) { builder.build_row(item); },
- IterOptions::SkipCollapsed);
-
- UI_block_layout_set_current(&builder.block(), prev_layout);
-}
-
void AbstractTreeView::update_from_old(uiBlock &new_block)
{
uiBlock *old_block = new_block.oldblock;
@@ -111,7 +98,10 @@ void AbstractTreeView::update_from_old(uiBlock &new_block)
uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
&new_block, reinterpret_cast<uiTreeViewHandle *>(this));
- BLI_assert(old_view_handle);
+ if (old_view_handle == nullptr) {
+ is_reconstructed_ = true;
+ return;
+ }
AbstractTreeView &old_view = reinterpret_cast<AbstractTreeView &>(*old_view_handle);
@@ -127,8 +117,8 @@ void AbstractTreeView::update_from_old(uiBlock &new_block)
is_reconstructed_ = true;
}
-void AbstractTreeView::update_children_from_old_recursive(const TreeViewItemContainer &new_items,
- const TreeViewItemContainer &old_items)
+void AbstractTreeView::update_children_from_old_recursive(const TreeViewOrItem &new_items,
+ const TreeViewOrItem &old_items)
{
for (const auto &new_item : new_items.children_) {
AbstractTreeViewItem *matching_old_item = find_matching_child(*new_item, old_items);
@@ -144,7 +134,7 @@ void AbstractTreeView::update_children_from_old_recursive(const TreeViewItemCont
}
AbstractTreeViewItem *AbstractTreeView::find_matching_child(
- const AbstractTreeViewItem &lookup_item, const TreeViewItemContainer &items)
+ const AbstractTreeViewItem &lookup_item, const TreeViewOrItem &items)
{
for (const auto &iter_item : items.children_) {
if (lookup_item.matches(*iter_item)) {
@@ -180,6 +170,9 @@ void AbstractTreeViewItem::tree_row_click_fn(struct bContext * /*C*/,
*tree_row_but->tree_item);
tree_item.activate();
+ /* Not only activate the item, also show its children. Maybe this should be optional, or
+ * controlled by the specific tree-view. */
+ tree_item.set_collapsed(false);
}
void AbstractTreeViewItem::add_treerow_button(uiBlock &block)
@@ -350,9 +343,14 @@ void AbstractTreeViewItem::on_activate()
/* Do nothing by default. */
}
-void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn)
+std::optional<bool> AbstractTreeViewItem::should_be_active() const
{
- is_active_fn_ = is_active_fn;
+ return std::nullopt;
+}
+
+bool AbstractTreeViewItem::supports_collapsing() const
+{
+ return true;
}
std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
@@ -369,7 +367,7 @@ std::unique_ptr<AbstractTreeViewItemDropController> AbstractTreeViewItem::create
return nullptr;
}
-bool AbstractTreeViewItem::can_rename() const
+bool AbstractTreeViewItem::supports_renaming() const
{
/* No renaming by default. */
return false;
@@ -403,7 +401,7 @@ bool AbstractTreeViewItem::matches(const AbstractTreeViewItem &other) const
void AbstractTreeViewItem::begin_renaming()
{
AbstractTreeView &tree_view = get_tree_view();
- if (tree_view.is_renaming() || !can_rename()) {
+ if (tree_view.is_renaming() || !supports_renaming()) {
return;
}
@@ -433,7 +431,7 @@ AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
int AbstractTreeViewItem::count_parents() const
{
int i = 0;
- for (TreeViewItemContainer *parent = parent_; parent; parent = parent->parent_) {
+ for (AbstractTreeViewItem *parent = parent_; parent; parent = parent->parent_) {
i++;
}
return i;
@@ -504,7 +502,10 @@ void AbstractTreeViewItem::set_collapsed(bool collapsed)
bool AbstractTreeViewItem::is_collapsible() const
{
- return !children_.is_empty();
+ if (children_.is_empty()) {
+ return false;
+ }
+ return this->supports_collapsing();
}
bool AbstractTreeViewItem::is_renaming() const
@@ -546,43 +547,69 @@ uiButTreeRow *AbstractTreeViewItem::tree_row_button()
void AbstractTreeViewItem::change_state_delayed()
{
- if (is_active_fn_()) {
+ const std::optional<bool> should_be_active = this->should_be_active();
+ if (should_be_active.has_value() && *should_be_active) {
activate();
}
}
+
/* ---------------------------------------------------------------------- */
-AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
+AbstractTreeViewItemDragController::AbstractTreeViewItemDragController(AbstractTreeView &tree_view)
: tree_view_(tree_view)
{
}
-/* ---------------------------------------------------------------------- */
-
-TreeViewBuilder::TreeViewBuilder(uiBlock &block) : block_(block)
+void AbstractTreeViewItemDragController::on_drag_start()
{
+ /* Do nothing by default. */
}
-void TreeViewBuilder::build_tree_view(AbstractTreeView &tree_view)
+/* ---------------------------------------------------------------------- */
+
+AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
+ : tree_view_(tree_view)
{
- tree_view.build_tree();
- tree_view.update_from_old(block_);
- tree_view.change_state_delayed();
- tree_view.build_layout_from_tree(TreeViewLayoutBuilder(block_));
}
/* ---------------------------------------------------------------------- */
+class TreeViewLayoutBuilder {
+ uiBlock &block_;
+
+ friend TreeViewBuilder;
+
+ public:
+ void build_from_tree(const AbstractTreeView &tree_view);
+ void build_row(AbstractTreeViewItem &item) const;
+
+ uiBlock &block() const;
+ uiLayout *current_layout() const;
+
+ private:
+ /* Created through #TreeViewBuilder. */
+ TreeViewLayoutBuilder(uiBlock &block);
+
+ static void polish_layout(const uiBlock &block);
+};
+
TreeViewLayoutBuilder::TreeViewLayoutBuilder(uiBlock &block) : block_(block)
{
}
-/**
- * Moves the button following the last added chevron closer to the list item.
- *
- * Iterates backwards over buttons until finding the tree-row button, which is assumed to be the
- * first button added for the row, and can act as a delimiter that way.
- */
+void TreeViewLayoutBuilder::build_from_tree(const AbstractTreeView &tree_view)
+{
+ uiLayout *prev_layout = current_layout();
+
+ uiLayout *box = uiLayoutBox(prev_layout);
+ uiLayoutColumn(box, false);
+
+ tree_view.foreach_item([this](AbstractTreeViewItem &item) { build_row(item); },
+ AbstractTreeView::IterOptions::SkipCollapsed);
+
+ UI_block_layout_set_current(&block(), prev_layout);
+}
+
void TreeViewLayoutBuilder::polish_layout(const uiBlock &block)
{
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block.buttons) {
@@ -642,6 +669,22 @@ uiLayout *TreeViewLayoutBuilder::current_layout() const
/* ---------------------------------------------------------------------- */
+TreeViewBuilder::TreeViewBuilder(uiBlock &block) : block_(block)
+{
+}
+
+void TreeViewBuilder::build_tree_view(AbstractTreeView &tree_view)
+{
+ tree_view.build_tree();
+ tree_view.update_from_old(block_);
+ tree_view.change_state_delayed();
+
+ TreeViewLayoutBuilder builder(block_);
+ builder.build_from_tree(tree_view);
+}
+
+/* ---------------------------------------------------------------------- */
+
BasicTreeViewItem::BasicTreeViewItem(StringRef label, BIFIconID icon_) : icon(icon_)
{
label_ = label;
@@ -670,13 +713,110 @@ void BasicTreeViewItem::on_activate()
}
}
-void BasicTreeViewItem::on_activate(ActivateFn fn)
+void BasicTreeViewItem::set_on_activate_fn(ActivateFn fn)
{
activate_fn_ = fn;
}
+void BasicTreeViewItem::set_is_active_fn(IsActiveFn is_active_fn)
+{
+ is_active_fn_ = is_active_fn;
+}
+
+std::optional<bool> BasicTreeViewItem::should_be_active() const
+{
+ if (is_active_fn_) {
+ return is_active_fn_();
+ }
+ return std::nullopt;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Helper for a public (C-)API, presenting higher level functionality. Has access to internal
+ * data/functionality (friend of #AbstractTreeViewItem), which is sometimes needed when
+ * functionality of the API needs to be constructed from multiple internal conditions and/or
+ * functions that on their own shouldn't be part of the API.
+ */
+class TreeViewItemAPIWrapper {
+ public:
+ static bool matches(const AbstractTreeViewItem &a, const AbstractTreeViewItem &b)
+ {
+ /* TODO should match the tree-view as well. */
+ return a.matches_including_parents(b);
+ }
+
+ static bool drag_start(bContext &C, const AbstractTreeViewItem &item)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
+ item.create_drag_controller();
+ if (!drag_controller) {
+ return false;
+ }
+
+ WM_event_start_drag(&C,
+ ICON_NONE,
+ drag_controller->get_drag_type(),
+ drag_controller->create_drag_data(),
+ 0,
+ WM_DRAG_FREE_DATA);
+ drag_controller->on_drag_start();
+
+ return true;
+ }
+
+ static bool can_drop(const AbstractTreeViewItem &item,
+ const wmDrag &drag,
+ const char **r_disabled_hint)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return false;
+ }
+
+ return drop_controller->can_drop(drag, r_disabled_hint);
+ }
+
+ static std::string drop_tooltip(const AbstractTreeViewItem &item, const wmDrag &drag)
+ {
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return {};
+ }
+
+ return drop_controller->drop_tooltip(drag);
+ }
+
+ static bool drop_handle(bContext &C, const AbstractTreeViewItem &item, const ListBase &drags)
+ {
+ std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+
+ const char *disabled_hint_dummy = nullptr;
+ LISTBASE_FOREACH (const wmDrag *, drag, &drags) {
+ if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
+ return drop_controller->on_drop(&C, *drag);
+ }
+ }
+
+ return false;
+ }
+
+ static bool can_rename(const AbstractTreeViewItem &item)
+ {
+ const AbstractTreeView &tree_view = item.get_tree_view();
+ return !tree_view.is_renaming() && item.supports_renaming();
+ }
+};
+
} // namespace blender::ui
+/* ---------------------------------------------------------------------- */
+/* C-API */
+
using namespace blender::ui;
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
@@ -690,31 +830,13 @@ bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
{
const AbstractTreeViewItem &a = reinterpret_cast<const AbstractTreeViewItem &>(*a_handle);
const AbstractTreeViewItem &b = reinterpret_cast<const AbstractTreeViewItem &>(*b_handle);
- /* TODO should match the tree-view as well. */
- return a.matches_including_parents(b);
+ return TreeViewItemAPIWrapper::matches(a, b);
}
-/**
- * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
- * support dragging, i.e. it won't create a drag-controller upon request.
- * \return True if dragging started successfully, otherwise false.
- */
bool UI_tree_view_item_drag_start(bContext *C, uiTreeViewItemHandle *item_)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
- item.create_drag_controller();
- if (!drag_controller) {
- return false;
- }
-
- WM_event_start_drag(C,
- ICON_NONE,
- drag_controller->get_drag_type(),
- drag_controller->create_drag_data(),
- 0,
- WM_DRAG_FREE_DATA);
- return true;
+ return TreeViewItemAPIWrapper::drag_start(*C, item);
}
bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
@@ -722,57 +844,29 @@ bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
const char **r_disabled_hint)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
- if (!drop_controller) {
- return false;
- }
-
- return drop_controller->can_drop(*drag, r_disabled_hint);
+ return TreeViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint);
}
char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_, const wmDrag *drag)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
- if (!drop_controller) {
- return nullptr;
- }
- return BLI_strdup(drop_controller->drop_tooltip(*drag).c_str());
+ const std::string tooltip = TreeViewItemAPIWrapper::drop_tooltip(item, *drag);
+ return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
}
-/**
- * Let a tree-view item handle a drop event.
- * \return True if the drop was handled by the tree-view item.
- */
-bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const ListBase *drags)
+bool UI_tree_view_item_drop_handle(bContext *C,
+ const uiTreeViewItemHandle *item_,
+ const ListBase *drags)
{
- AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_);
- std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
- item.create_drop_controller();
-
- const char *disabled_hint_dummy = nullptr;
- LISTBASE_FOREACH (const wmDrag *, drag, drags) {
- if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
- return drop_controller->on_drop(*drag);
- }
- }
-
- return false;
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+ return TreeViewItemAPIWrapper::drop_handle(*C, item, *drags);
}
-/**
- * Can \a item_handle be renamed right now? Not that this isn't just a mere wrapper around
- * #AbstractTreeViewItem::can_rename(). This also checks if there is another item being renamed,
- * and returns false if so.
- */
bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
- const AbstractTreeView &tree_view = item.get_tree_view();
- return !tree_view.is_renaming() && item.can_rename();
+ return TreeViewItemAPIWrapper::can_rename(item);
}
void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle)
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 9a6fbbf4016..b530693a7e5 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -228,16 +228,6 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
/** \name View2D Refresh and Validation (Spatial)
* \{ */
-/**
- * Initialize all relevant View2D data (including view rects if first time)
- * and/or refresh mask sizes after view resize.
- *
- * - For some of these presets, it is expected that the region will have defined some
- * additional settings necessary for the customization of the 2D viewport to its requirements
- * - This function should only be called from region init() callbacks, where it is expected that
- * this is called before #UI_view2d_size_update(),
- * as this one checks that the rects are properly initialized.
- */
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
{
bool tot_changed = false, do_init;
@@ -872,8 +862,6 @@ bool UI_view2d_area_supports_sync(ScrArea *area)
return ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP, SPACE_GRAPH);
}
-/* Called by menus to activate it, or by view2d operators
- * to make sure 'related' views stay in synchrony */
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
{
/* don't continue if no view syncing to be done */
@@ -937,11 +925,6 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
}
}
-/**
- * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot).
- * This does not take into account if zooming the view on an axis
- * will improve the view (if allowed).
- */
void UI_view2d_curRect_reset(View2D *v2d)
{
float width, height;
@@ -991,7 +974,6 @@ void UI_view2d_curRect_reset(View2D *v2d)
/* ------------------ */
-/* Change the size of the maximum viewable area (i.e. 'tot' rect) */
void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize)
{
/* don't do anything if either value is 0 */
@@ -1110,7 +1092,6 @@ static void view2d_map_cur_using_mask(const View2D *v2d, rctf *r_curmasked)
}
}
-/* Set view matrices to use 'cur' rect as viewing frame for View2D drawing */
void UI_view2d_view_ortho(const View2D *v2d)
{
rctf curmasked;
@@ -1152,12 +1133,6 @@ void UI_view2d_view_ortho(const View2D *v2d)
wmOrtho2(curmasked.xmin, curmasked.xmax, curmasked.ymin, curmasked.ymax);
}
-/**
- * Set view matrices to only use one axis of 'cur' only
- *
- * \param xaxis: if non-zero, only use cur x-axis,
- * otherwise use cur-yaxis (mostly this will be used for x).
- */
void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, const bool xaxis)
{
rctf curmasked;
@@ -1184,7 +1159,6 @@ void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, const bool xaxis)
}
}
-/* Restore view matrices after drawing */
void UI_view2d_view_restore(const bContext *C)
{
ARegion *region = CTX_wm_region(C);
@@ -1203,7 +1177,6 @@ void UI_view2d_view_restore(const bContext *C)
/** \name Grid-Line Drawing
* \{ */
-/* Draw a multi-level grid in given 2d-region */
void UI_view2d_multi_grid_draw(
const View2D *v2d, int colorid, float step, int level_size, int totlevels)
{
@@ -1335,14 +1308,6 @@ static const DotGridLevelInfo level_info[9] = {
{0.025f, 0.6f, 0.9f},
};
-/**
- * Draw a multi-level grid of dots, with a dynamic number of levels based on the fading.
- *
- * \param grid_color_id: The theme color used for the points. Faded dynamically based on zoom.
- * \param min_step: The base size of the grid. At different zoom levels, the visible grid may have
- * a larger step size.
- * \param grid_levels: The maximum grid depth. Larger grid levels will subdivide the grid more.
- */
void UI_view2d_dot_grid_draw(const View2D *v2d,
const int grid_color_id,
const float min_step,
@@ -1400,6 +1365,7 @@ void UI_view2d_dot_grid_draw(const View2D *v2d,
immUnbindProgram();
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1414,6 +1380,8 @@ void UI_view2d_dot_grid_draw(const View2D *v2d,
*/
struct View2DScrollers {
/* focus bubbles */
+ /* focus bubbles */
+ /* focus bubbles */
int vert_min, vert_max; /* vertical scrollbar */
int hor_min, hor_max; /* horizontal scrollbar */
@@ -1423,7 +1391,6 @@ struct View2DScrollers {
/* int horfull, vertfull; */ /* UNUSED */
};
-/* Calculate relevant scroller properties */
void UI_view2d_scrollers_calc(View2D *v2d,
const rcti *mask_custom,
struct View2DScrollers *r_scrollers)
@@ -1550,7 +1517,6 @@ void UI_view2d_scrollers_calc(View2D *v2d,
}
}
-/* Draw scrollbars in the given 2d-region */
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
{
View2DScrollers scrollers;
@@ -1646,18 +1612,6 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
/** \name List View Utilities
* \{ */
-/**
- * Get the 'cell' (row, column) that the given 2D-view coordinates
- * (i.e. in 'tot' rect space) lie in.
- *
- * \param columnwidth, rowheight: size of each 'cell'
- * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
- * \param r_column, r_row: the 'coordinates' of the relevant 'cell'
- */
void UI_view2d_listview_view_to_cell(float columnwidth,
float rowheight,
float startx,
@@ -1705,12 +1659,6 @@ float UI_view2d_region_to_view_y(const struct View2D *v2d, float y)
(BLI_rctf_size_y(&v2d->cur) * (y - v2d->mask.ymin) / BLI_rcti_size_y(&v2d->mask)));
}
-/**
- * Convert from screen/region space to 2d-View space
- *
- * \param x, y: coordinates to convert
- * \param r_view_x, r_view_y: resultant coordinates
- */
void UI_view2d_region_to_view(
const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y)
{
@@ -1744,13 +1692,6 @@ float UI_view2d_view_to_region_y(const View2D *v2d, float y)
(((y - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur)) * BLI_rcti_size_y(&v2d->mask)));
}
-/**
- * Convert from 2d-View space to screen/region space
- * \note Coordinates are clamped to lie within bounds of region
- *
- * \param x, y: Coordinates to convert.
- * \param r_region_x, r_region_y: Resultant coordinates.
- */
bool UI_view2d_view_to_region_clip(
const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -1772,14 +1713,6 @@ bool UI_view2d_view_to_region_clip(
return false;
}
-/**
- * Convert from 2d-view space to screen/region space
- *
- * \note Coordinates are NOT clamped to lie within bounds of region.
- *
- * \param x, y: Coordinates to convert.
- * \param r_region_x, r_region_y: Resultant coordinates.
- */
void UI_view2d_view_to_region(
const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -1874,7 +1807,6 @@ bool UI_view2d_view_to_region_rcti_clip(const View2D *v2d, const rctf *rect_src,
/** \name Utilities
* \{ */
-/* View2D data by default resides in region, so get from region stored in context */
View2D *UI_view2d_fromcontext(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1889,7 +1821,6 @@ View2D *UI_view2d_fromcontext(const bContext *C)
return &(region->v2d);
}
-/* Same as above, but it returns region-window. Utility for pull-downs or buttons. */
View2D *UI_view2d_fromcontext_rwin(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1908,8 +1839,6 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
return &(region->v2d);
}
-/* Get scrollbar sizes of the current 2D view. The size will be zero if the view has its scrollbars
- * disabled. */
void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
{
const int scroll = view2d_scroll_mapped(v2d->scroll);
@@ -1933,14 +1862,6 @@ void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
}
}
-/**
- * Calculate the scale per-axis of the drawing-area
- *
- * Is used to inverse correct drawing of icons, etc. that need to follow view
- * but not be affected by scale
- *
- * \param r_x, r_y: scale on each axis
- */
void UI_view2d_scale_get(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
@@ -1958,9 +1879,6 @@ float UI_view2d_scale_get_y(const View2D *v2d)
{
return BLI_rcti_size_y(&v2d->mask) / BLI_rctf_size_y(&v2d->cur);
}
-/**
- * Same as `UI_view2d_scale_get() - 1.0f / x, y`.
- */
void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
@@ -1971,10 +1889,6 @@ void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
}
}
-/**
- * Simple functions for consistent center offset access.
- * Used by node editor to shift view center for each individual node tree.
- */
void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y)
{
/* get center */
@@ -1993,12 +1907,6 @@ void UI_view2d_center_set(struct View2D *v2d, float x, float y)
UI_view2d_curRect_validate(v2d);
}
-/**
- * Simple pan function
- * (0.0, 0.0) bottom left
- * (0.5, 0.5) center
- * (1.0, 1.0) top right.
- */
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
{
if (xfac != -1.0f) {
@@ -2022,17 +1930,6 @@ void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
UI_view2d_curRect_validate(v2d);
}
-/**
- * Check if mouse is within scrollers
- *
- * \param x, y: Mouse coordinates in screen (not region) space.
- * \param r_scroll: Mapped view2d scroll flag.
- *
- * \return appropriate code for match.
- * - 'h' = in horizontal scroller.
- * - 'v' = in vertical scroller.
- * - 0 = not in scroller.
- */
char UI_view2d_mouse_in_scrollers_ex(const ARegion *region,
const View2D *v2d,
const int xy[2],
@@ -2154,7 +2051,6 @@ void UI_view2d_text_cache_add(
}
}
-/* no clip (yet) */
void UI_view2d_text_cache_add_rectf(
View2D *v2d, const rctf *rect_view, const char *str, size_t str_len, const uchar col[4])
{
diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.c b/source/blender/editors/interface/view2d_gizmo_navigate.c
index 3ff5b471731..2497081b412 100644
--- a/source/blender/editors/interface/view2d_gizmo_navigate.c
+++ b/source/blender/editors/interface/view2d_gizmo_navigate.c
@@ -251,7 +251,6 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
-/* Caller defines the name for gizmo group. */
void VIEW2D_GGT_navigate_impl(wmGizmoGroupType *gzgt, const char *idname)
{
gzgt->name = "View2D Navigate";
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 0bca4e327cc..0d3c427bf39 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1570,8 +1570,6 @@ static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b)
return min_ff(fac_max, 1.0f);
}
-/* will start timer if appropriate */
-/* the arguments are the desired situation */
void UI_view2d_smooth_view(bContext *C, ARegion *region, const rctf *cur, const int smooth_viewtx)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1761,7 +1759,6 @@ typedef struct v2dScrollerMove {
* For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
- /* focus bubbles */
int vert_min, vert_max; /* vertical scrollbar */
int hor_min, hor_max; /* horizontal scrollbar */
diff --git a/source/blender/editors/lattice/editlattice_tools.c b/source/blender/editors/lattice/editlattice_tools.c
index d503cbc87b8..15325c7648c 100644
--- a/source/blender/editors/lattice/editlattice_tools.c
+++ b/source/blender/editors/lattice/editlattice_tools.c
@@ -47,8 +47,6 @@
#include "lattice_intern.h"
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Make Regular Operator
* \{ */
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index 23eaf991fd3..6d79d063a2f 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -278,7 +278,6 @@ static void lattice_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_lattice_undosys_type(UndoType *ut)
{
ut->name = "Edit Lattice";
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 22232e9c87e..9504a8783a0 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -587,6 +587,35 @@ static void draw_spline_curve(const bContext *C,
}
}
+static void draw_layer_splines(const bContext *C,
+ MaskLayer *layer,
+ const char draw_flag,
+ const char draw_type,
+ const int width,
+ const int height,
+ const bool is_active)
+{
+ LISTBASE_FOREACH (MaskSpline *, spline, &layer->splines) {
+ /* draw curve itself first... */
+ draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
+
+ if (!(layer->visibility_flag & MASK_HIDE_SELECT)) {
+ /* ...and then handles over the curve so they're nicely visible */
+ draw_spline_points(C, layer, spline, draw_flag, draw_type);
+ }
+
+ /* show undeform for testing */
+ if (0) {
+ void *back = spline->points_deform;
+
+ spline->points_deform = NULL;
+ draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
+ draw_spline_points(C, layer, spline, draw_flag, draw_type);
+ spline->points_deform = back;
+ }
+ }
+}
+
static void draw_mask_layers(const bContext *C,
Mask *mask,
const char draw_flag,
@@ -600,6 +629,7 @@ static void draw_mask_layers(const bContext *C,
MaskLayer *mask_layer;
int i;
+ MaskLayer *active = NULL;
for (mask_layer = mask->masklayers.first, i = 0; mask_layer != NULL;
mask_layer = mask_layer->next, i++) {
const bool is_active = (i == mask->masklay_act);
@@ -608,26 +638,16 @@ static void draw_mask_layers(const bContext *C,
continue;
}
- LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
-
- /* draw curve itself first... */
- draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
-
- if (!(mask_layer->visibility_flag & MASK_HIDE_SELECT)) {
- /* ...and then handles over the curve so they're nicely visible */
- draw_spline_points(C, mask_layer, spline, draw_flag, draw_type);
- }
+ if (is_active) {
+ active = mask_layer;
+ continue;
+ }
- /* show undeform for testing */
- if (0) {
- void *back = spline->points_deform;
+ draw_layer_splines(C, mask_layer, draw_flag, draw_type, width, height, is_active);
+ }
- spline->points_deform = NULL;
- draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
- draw_spline_points(C, mask_layer, spline, draw_flag, draw_type);
- spline->points_deform = back;
- }
- }
+ if (active != NULL) {
+ draw_layer_splines(C, active, draw_flag, draw_type, width, height, true);
}
GPU_program_point_size(false);
@@ -666,8 +686,6 @@ static float *mask_rasterize(Mask *mask, const int width, const int height)
return buffer;
}
-/* sets up the opengl context.
- * width, height are to match the values from ED_mask_get_size() */
void ED_mask_draw_region(
Depsgraph *depsgraph,
Mask *mask_,
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index d9efbef4b42..3668f3bb34e 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -52,7 +52,6 @@
/* ***************************************** */
/* Generics - Loopers */
-/* Loops over the mask-frames for a mask-layer, and applies the given callback */
bool ED_masklayer_frames_looper(MaskLayer *mask_layer,
Scene *scene,
bool (*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
@@ -80,7 +79,6 @@ bool ED_masklayer_frames_looper(MaskLayer *mask_layer,
/* ****************************************** */
/* Data Conversion Tools */
-/* make a listing all the mask-frames in a layer as cfraelems */
void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool onlysel)
{
MaskLayerShape *mask_layer_shape;
@@ -108,7 +106,6 @@ void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool on
/* ***************************************** */
/* Selection Tools */
-/* check if one of the frames in this layer is selected */
bool ED_masklayer_frame_select_check(const MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape;
@@ -150,7 +147,6 @@ static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short sele
}
}
-/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -167,7 +163,6 @@ void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
}
}
-/* set all/none/invert select */
void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
{
/* error checking */
@@ -179,7 +174,6 @@ void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
ED_mask_select_frames(mask_layer, mode);
}
-/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -195,7 +189,6 @@ void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
}
}
-/* select the frames in this layer that occur within the bounds specified */
void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
{
MaskLayerShape *mask_layer_shape;
@@ -213,7 +206,6 @@ void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max,
}
}
-/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_masklayer_frames_select_region(KeyframeEditData *ked,
MaskLayer *mask_layer,
short tool,
@@ -253,7 +245,6 @@ void ED_masklayer_frames_select_region(KeyframeEditData *ked,
/* ***************************************** */
/* Frame Editing Tools */
-/* Delete selected frames */
bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape, *mask_layer_shape_next;
@@ -278,7 +269,6 @@ bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
return changed;
}
-/* Duplicate selected frames from given mask-layer */
void ED_masklayer_frames_duplicate(MaskLayer *mask_layer)
{
MaskLayerShape *mask_layer_shape, *gpfn;
@@ -344,7 +334,6 @@ static bool snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *
return false;
}
-/* snap selected frames to ... */
void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
{
switch (mode) {
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index ee1784011ea..41ff14dcd5f 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -32,13 +32,18 @@ struct wmOperatorType;
/* internal exports only */
/* mask_add.c */
+
void MASK_OT_add_vertex(struct wmOperatorType *ot);
void MASK_OT_add_feather_vertex(struct wmOperatorType *ot);
void MASK_OT_primitive_circle_add(struct wmOperatorType *ot);
void MASK_OT_primitive_square_add(struct wmOperatorType *ot);
/* mask_ops.c */
+
struct Mask *ED_mask_new(struct bContext *C, const char *name);
+/**
+ * Get active layer. Will create mask/layer to be sure there's an active layer.
+ */
struct MaskLayer *ED_mask_layer_ensure(struct bContext *C, bool *r_added_mask);
void MASK_OT_new(struct wmOperatorType *ot);
@@ -55,6 +60,7 @@ void MASK_OT_hide_view_clear(struct wmOperatorType *ot);
void MASK_OT_hide_view_set(struct wmOperatorType *ot);
void MASK_OT_feather_weight_clear(struct wmOperatorType *ot);
void MASK_OT_switch_direction(struct wmOperatorType *ot);
+/* Named to match mesh recalculate normals. */
void MASK_OT_normals_make_consistent(struct wmOperatorType *ot);
void MASK_OT_handle_type_set(struct wmOperatorType *ot);
@@ -66,10 +72,13 @@ void MASK_OT_copy_splines(struct wmOperatorType *ot);
void MASK_OT_paste_splines(struct wmOperatorType *ot);
/* mask_relationships.c */
+
+/** based on #OBJECT_OT_parent_set */
void MASK_OT_parent_set(struct wmOperatorType *ot);
void MASK_OT_parent_clear(struct wmOperatorType *ot);
/* mask_select.c */
+
void MASK_OT_select(struct wmOperatorType *ot);
void MASK_OT_select_all(struct wmOperatorType *ot);
@@ -81,6 +90,7 @@ void MASK_OT_select_linked(struct wmOperatorType *ot);
void MASK_OT_select_more(struct wmOperatorType *ot);
void MASK_OT_select_less(struct wmOperatorType *ot);
+/* 'check' select */
bool ED_mask_spline_select_check(const struct MaskSpline *spline);
bool ED_mask_layer_select_check(const struct MaskLayer *mask_layer);
bool ED_mask_select_check(const struct Mask *mask);
@@ -91,6 +101,7 @@ void ED_mask_select_toggle_all(struct Mask *mask, int action);
void ED_mask_select_flush_all(struct Mask *mask);
/* mask_editor.c */
+
bool ED_maskedit_poll(struct bContext *C);
bool ED_maskedit_mask_poll(struct bContext *C);
@@ -108,6 +119,7 @@ void ED_mask_view_lock_state_restore_no_jump(const struct bContext *C,
const MaskViewLockState *state);
/* mask_query.c */
+
bool ED_mask_find_nearest_diff_point(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index fd5925bbd0c..8feb526c8d5 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -83,9 +83,6 @@ Mask *ED_mask_new(bContext *C, const char *name)
return mask;
}
-/**
- * Get active layer. Will create mask/layer to be sure there's an active layer.
- */
MaskLayer *ED_mask_layer_ensure(bContext *C, bool *r_added_mask)
{
Mask *mask = CTX_data_edit_mask(C);
@@ -1616,7 +1613,6 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
return OPERATOR_CANCELLED;
}
-/* Named to match mesh recalculate normals. */
void MASK_OT_normals_make_consistent(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index e66c4e45e27..de80d9f04bd 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -489,7 +489,6 @@ bool ED_mask_feather_find_nearest(const bContext *C,
return false;
}
-/* takes event->mval */
void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float co[2])
{
if (area) {
@@ -523,8 +522,6 @@ void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float
}
}
-/* input: x/y - mval space
- * output: xr/yr - mask point space */
void ED_mask_point_pos(ScrArea *area, ARegion *region, float x, float y, float *xr, float *yr)
{
float co[2];
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 9c4740b3087..259402efbf1 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -168,7 +168,6 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/** based on #OBJECT_OT_parent_set */
void MASK_OT_parent_set(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index fe6acac7d29..dd4a557f449 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -52,7 +52,6 @@
/** \name Public Mask Selection API
* \{ */
-/* 'check' select */
bool ED_mask_spline_select_check(const MaskSpline *spline)
{
for (int i = 0; i < spline->tot_point; i++) {
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 648008a4779..06547c94992 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -50,8 +50,6 @@
/* own include */
-/* copy the face flags, most importantly selection from the mesh to the final derived mesh,
- * use in object mode when selecting faces (while painting) */
void paintface_flush_flags(struct bContext *C, Object *ob, short flag)
{
Mesh *me = BKE_mesh_from_object(ob);
@@ -369,7 +367,7 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
continue;
}
- ml = me->mloop + mp->totloop;
+ ml = me->mloop + mp->loopstart;
for (b = 0; b < mp->totloop; b++, ml++) {
mul_v3_m3v3(vec, bmat, mvert[ml->v].co);
add_v3_v3v3(vec, vec, ob->obmat[3]);
@@ -437,9 +435,6 @@ bool paintface_mouse_select(
return true;
}
-/* (similar to void paintface_flush_flags(Object *ob))
- * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
- * use in object mode when selecting vertices (while painting) */
void paintvert_flush_flags(Object *ob)
{
Mesh *me = BKE_mesh_from_object(ob);
@@ -492,10 +487,6 @@ void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
-/**
- * \note if the caller passes false to flush_flags,
- * then they will need to run #paintvert_flush_flags(ob) themselves.
- */
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
Mesh *me;
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 912399c25b3..913be7d69bb 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -144,7 +144,6 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch
return true;
}
-/* extrudes individual edges */
bool edbm_extrude_edges_indiv(BMEditMesh *em,
wmOperator *op,
const char hflag,
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index ee227c58fe7..18fe9cf7ad3 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -114,6 +114,7 @@ static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_selec
}
}
}
+ EDBM_select_flush(em);
}
EDBM_update(me,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index cd04f40dedf..3772a37ac44 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -210,7 +210,7 @@ typedef struct KnifeBVH {
typedef struct KnifeTool_OpData {
ARegion *region; /* Region that knifetool was activated in. */
void *draw_handle; /* For drawing preview loop. */
- ViewContext vc; /* Note: _don't_ use 'mval', instead use the one we define below. */
+ ViewContext vc; /* NOTE: _don't_ use 'mval', instead use the one we define below. */
float mval[2]; /* Mouse value with snapping applied. */
Scene *scene;
@@ -4143,7 +4143,7 @@ static void knifetool_exit_ex(KnifeTool_OpData *kcd)
for (int i = 0; i < kcd->objects_len; i++) {
knifetool_free_cagecos(kcd, i);
}
- MEM_freeN(kcd->cagecos);
+ MEM_freeN((void *)kcd->cagecos);
knife_bvh_free(kcd);
/* Line-hits cleanup. */
@@ -4866,9 +4866,6 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
return false;
}
-/**
- * \param use_tag: When set, tag all faces inside the polylines.
- */
void EDBM_mesh_knife(bContext *C, ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_through)
{
KnifeTool_OpData *kcd;
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
index dfd646c767f..ab268251061 100644
--- a/source/blender/editors/mesh/editmesh_preselect_elem.c
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -411,4 +411,5 @@ void EDBM_preselect_elem_update_preview(struct EditMesh_PreSelElem *psel,
BLI_assert(0);
}
}
+
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index e0768bcff24..7e05209f79e 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -267,17 +267,6 @@ static void findnearestvert__doClosest(void *userData,
}
}
-/**
- * Nearest vertex under the cursor.
- *
- * \param dist_px_manhattan_p: (in/out), minimal distance to the nearest and at the end,
- * actual distance.
- * \param use_select_bias:
- * - When true, selected vertices are given a 5 pixel bias
- * to make them further than unselect verts.
- * - When false, unselected vertices are given the bias.
- * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
- */
BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc,
float *dist_px_manhattan_p,
const bool use_select_bias,
@@ -713,13 +702,6 @@ static void findnearestface__doClosest(void *userData,
}
}
-/**
- * \param use_zbuf_single_px: Special case, when using the back-buffer selection,
- * only use the pixel at `vc->mval` instead of using `dist_px_manhattan_p` to search over a larger
- * region. This is needed because historically selection worked this way for a long time, however
- * it's reasonable that some callers might want to expand the region too. So add an argument to do
- * this,
- */
BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
float *dist_px_manhattan_p,
float *r_dist_center,
@@ -2217,8 +2199,6 @@ static void edbm_strip_selections(BMEditMesh *em)
}
}
-/* when switching select mode, makes sure selection is consistent for editing */
-/* also for paranoia checks to make sure edge or face mode works */
void EDBM_selectmode_set(BMEditMesh *em)
{
BMVert *eve;
@@ -2273,20 +2253,6 @@ void EDBM_selectmode_set(BMEditMesh *em)
}
}
-/**
- * Expand & Contract the Selection
- * (used when changing modes and Ctrl key held)
- *
- * Flush the selection up:
- * - vert -> edge
- * - vert -> face
- * - edge -> face
- *
- * Flush the selection down:
- * - face -> edge
- * - face -> vert
- * - edge -> vert
- */
void EDBM_selectmode_convert(BMEditMesh *em,
const short selectmode_old,
const short selectmode_new)
@@ -2393,7 +2359,6 @@ void EDBM_selectmode_convert(BMEditMesh *em,
}
}
-/* user facing function, does notification */
bool EDBM_selectmode_toggle_multi(bContext *C,
const short selectmode_new,
const int action,
@@ -2569,12 +2534,6 @@ bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
return changed;
}
-/**
- * Use to disable a selectmode if its enabled, Using another mode as a fallback
- * if the disabled mode is the only mode set.
- *
- * \return true if the mode is changed.
- */
bool EDBM_selectmode_disable(Scene *scene,
BMEditMesh *em,
const short selectmode_disable,
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index c452f7a7487..f2311eb926d 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -974,6 +974,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1255,6 +1256,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 6cd7d912820..633e8183eb3 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -8226,7 +8226,6 @@ enum {
EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED = 114,
};
-/* Called in transform_ops.c, on each regeneration of key-maps. */
wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index f52cd94b8dc..f22d4bbe580 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -915,7 +915,6 @@ static void mesh_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_mesh_undosys_type(UndoType *ut)
{
ut->name = "Edit Mesh";
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 3ba8f601937..013d5e5a661 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -68,9 +68,6 @@
* just as the undo stack would.
* So leaving this as an interface for further work */
-/**
- * Save a copy of the #BMesh for restoring later.
- */
BMBackup EDBM_redo_state_store(BMEditMesh *em)
{
BMBackup backup;
@@ -93,9 +90,6 @@ void EDBM_redo_state_restore(BMBackup *backup, BMEditMesh *em, bool recalc_loopt
}
}
-/**
- * Delete the backup, flushing it to an edit-mesh.
- */
void EDBM_redo_state_restore_and_free(BMBackup *backup, BMEditMesh *em, bool recalc_looptri)
{
BM_mesh_data_free(em->bm);
@@ -139,11 +133,6 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
return true;
}
-/**
- * The return value:
- * - False on error (the mesh must not be changed).
- * - True on success, executes and finishes a #BMesh operator.
- */
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
{
const char *errmsg;
@@ -320,11 +309,6 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
EDBM_selectmode_flush(me->edit_mesh);
}
-/**
- * \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
- * Most callers should run #DEG_id_tag_update on `ob->data`, see: T46738, T46913.
- * This ensures #BKE_object_free_derived_caches runs on all objects that use this mesh.
- */
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
{
Mesh *me = ob->data;
@@ -363,9 +347,6 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
EDBM_mesh_load_ex(bmain, ob, true);
}
-/**
- * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
- */
void EDBM_mesh_free_data(BMEditMesh *em)
{
/* These tables aren't used yet, so it's not strictly necessary
@@ -486,9 +467,6 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
/** \name UV Vertex Map API
* \{ */
-/**
- * Return a new #UvVertMap from the edit-mesh.
- */
UvVertMap *BM_uv_vert_map_create(BMesh *bm, const bool use_select, const bool use_winding)
{
BMVert *ev;
@@ -632,7 +610,6 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
return vmap->vert[v];
}
-/* A specialized vert map used by stitch operator */
UvElementMap *BM_uv_element_map_create(BMesh *bm,
const Scene *scene,
const bool face_selected,
@@ -953,10 +930,6 @@ UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
/** \name Data Layer Checks
* \{ */
-/**
- * last_sel, use em->act_face otherwise get the last selected face in the editselections
- * at the moment, last_sel is mainly useful for making sure the space image doesn't flicker.
- */
BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
{
BMFace *efa = NULL;
@@ -974,7 +947,6 @@ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool se
return NULL;
}
-/* Can we edit UV's for this mesh? */
bool EDBM_uv_check(BMEditMesh *em)
{
/* some of these checks could be a touch overkill */
@@ -1015,20 +987,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int ind
* \endcode
*/
-/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
- * preference */
+/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a preference. */
#define BM_SEARCH_MAXDIST_MIRR 0.00002f
#define BM_CD_LAYER_ID "__mirror_index"
-/**
- * \param em: Editmesh.
- * \param use_self: Allow a vertex to point to its self (middle verts).
- * \param use_select: Restrict to selected verts.
- * \param respecthide: Skip hidden vertices.
- * \param use_topology: Use topology mirror.
- * \param maxdist: Distance for close point test.
- * \param r_index: Optional array to write into, as an alternative to a customdata layer
- * (length of total verts).
- */
+
void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
const int axis,
const bool use_self,
@@ -1255,7 +1217,6 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t
/** \name Hide/Reveal API
* \{ */
-/* swap is 0 or 1, if 1 it hides not selected */
bool EDBM_mesh_hide(BMEditMesh *em, bool swap)
{
BMIter iter;
@@ -1410,9 +1371,6 @@ void EDBM_stats_update(BMEditMesh *em)
}
}
-/**
- * So many tools call these that we better make it a generic function.
- */
void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
{
BMEditMesh *em = mesh->edit_mesh;
@@ -1459,7 +1417,6 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
#endif
}
-/* Bad level call from Python API. */
void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
{
EDBM_update(me,
@@ -1476,7 +1433,6 @@ void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool
/** \name Operator Helpers
* \{ */
-/* poll call for mesh operators requiring a view3d context */
bool EDBM_view3d_poll(bContext *C)
{
if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) {
@@ -1509,11 +1465,6 @@ BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFa
return ele;
}
-/**
- * Used when we want to store a single index for any vert/edge/face.
- *
- * Intended for use with operators.
- */
int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
{
BMesh *bm = em->bm;
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 7391451b694..d7d1dc7dcae 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -208,7 +208,6 @@ static void mesh_uv_reset_mface(MPoly *mp, MLoopUV *mloopuv)
mesh_uv_reset_array(fuv, mp->totloop);
}
-/* without bContext, called in uvedit */
void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum)
{
BMEditMesh *em = me->edit_mesh;
@@ -253,10 +252,11 @@ void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
-/* NOTE: keep in sync with #ED_mesh_color_add. */
int ED_mesh_uv_texture_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_color_add. */
+
BMEditMesh *em;
int layernum_dst;
@@ -267,7 +267,7 @@ int ED_mesh_uv_texture_add(
layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV);
if (layernum_dst >= MAX_MTFACE) {
- BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i UV maps", MAX_MTFACE);
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i UV maps", MAX_MTFACE);
return -1;
}
@@ -287,7 +287,7 @@ int ED_mesh_uv_texture_add(
else {
layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum_dst >= MAX_MTFACE) {
- BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i UV maps", MAX_MTFACE);
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i UV maps", MAX_MTFACE);
return -1;
}
@@ -381,10 +381,11 @@ bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name)
return false;
}
-/* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
int ED_mesh_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+
BMEditMesh *em;
int layernum;
@@ -393,7 +394,7 @@ int ED_mesh_color_add(
layernum = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
if (layernum >= MAX_MCOL) {
- BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i vertex color layers", MAX_MCOL);
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
return -1;
}
@@ -411,7 +412,7 @@ int ED_mesh_color_add(
else {
layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
if (layernum >= MAX_MCOL) {
- BKE_reportf(reports, RPT_ERROR, "Cannot add more than %i vertex color layers", MAX_MCOL);
+ BKE_reportf(reports, RPT_WARNING, "Cannot add more than %i vertex color layers", MAX_MCOL);
return -1;
}
@@ -516,10 +517,11 @@ static bool sculpt_vertex_color_remove_poll(bContext *C)
return false;
}
-/* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
int ED_mesh_sculpt_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
+ /* NOTE: keep in sync with #ED_mesh_uv_texture_add. */
+
BMEditMesh *em;
int layernum;
@@ -529,7 +531,7 @@ int ED_mesh_sculpt_color_add(
layernum = CustomData_number_of_layers(&em->bm->vdata, CD_PROP_COLOR);
if (layernum >= MAX_MCOL) {
BKE_reportf(
- reports, RPT_ERROR, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
+ reports, RPT_WARNING, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
return -1;
}
@@ -548,7 +550,7 @@ int ED_mesh_sculpt_color_add(
layernum = CustomData_number_of_layers(&me->vdata, CD_PROP_COLOR);
if (layernum >= MAX_MCOL) {
BKE_reportf(
- reports, RPT_ERROR, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
+ reports, RPT_WARNING, "Cannot add more than %i sculpt vertex color layers", MAX_MCOL);
return -1;
}
@@ -905,6 +907,7 @@ static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator *UNUSED(op))
void MESH_OT_customdata_mask_clear(wmOperatorType *ot)
{
+ /* NOTE: no create_mask yet */
/* identifiers */
ot->name = "Clear Sculpt Mask Data";
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index abff3c70e67..bba142133a6 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -43,7 +43,7 @@ struct wmOperatorType;
* BMEdit module is for code shared with blenkernel that concerns
* the BMEditMesh structure. */
-/* Calls a bmesh op, reporting errors to the user, etc */
+/** Calls a bmesh op, reporting errors to the user, etc. */
bool EDBM_op_callf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt, ...);
bool EDBM_op_call_and_selectf(struct BMEditMesh *em,
struct wmOperator *op,
@@ -51,17 +51,26 @@ bool EDBM_op_call_and_selectf(struct BMEditMesh *em,
const bool select_replace,
const char *fmt,
...);
-/* Same as above, but doesn't report errors. */
+/**
+ * Same as above, but doesn't report errors.
+ */
bool EDBM_op_call_silentf(struct BMEditMesh *em, const char *fmt, ...);
-/* these next two functions are the split version of EDBM_op_callf, so you can
- * do stuff with a bmesh operator, after initializing it but before executing
- * it.
+/**
+ * These next two functions are the split version of EDBM_op_callf, so you can
+ * do stuff with a bmesh operator, after initializing it but before executing it.
*
* execute the operator with BM_Exec_Op */
bool EDBM_op_init(
struct BMEditMesh *em, struct BMOperator *bmop, struct wmOperator *op, const char *fmt, ...);
-/* Cleans up after a bmesh operator */
+
+/**
+ * Cleans up after a bmesh operator.
+ *
+ * The return value:
+ * - False on error (the mesh must not be changed).
+ * - True on success, executes and finishes a #BMesh operator.
+ */
bool EDBM_op_finish(struct BMEditMesh *em,
struct BMOperator *bmop,
struct wmOperator *op,
@@ -69,6 +78,9 @@ bool EDBM_op_finish(struct BMEditMesh *em,
void EDBM_stats_update(struct BMEditMesh *em);
+/**
+ * Poll call for mesh operators requiring a view3d context.
+ */
bool EDBM_view3d_poll(struct bContext *C);
struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
@@ -76,6 +88,11 @@ struct BMElem *EDBM_elem_from_selectmode(struct BMEditMesh *em,
struct BMEdge *eed,
struct BMFace *efa);
+/**
+ * Used when we want to store a single index for any vert/edge/face.
+ *
+ * Intended for use with operators.
+ */
int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele);
struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, uint index);
@@ -88,12 +105,16 @@ struct BMElem *EDBM_elem_from_index_any_multi(struct ViewLayer *view_layer,
uint elem_index,
struct Object **r_obedit);
+/**
+ * Extrudes individual edges.
+ */
bool edbm_extrude_edges_indiv(struct BMEditMesh *em,
struct wmOperator *op,
const char hflag,
const bool use_normal_flip);
/* *** editmesh_add.c *** */
+
void MESH_OT_primitive_plane_add(struct wmOperatorType *ot);
void MESH_OT_primitive_cube_add(struct wmOperatorType *ot);
void MESH_OT_primitive_circle_add(struct wmOperatorType *ot);
@@ -105,16 +126,20 @@ void MESH_OT_primitive_uv_sphere_add(struct wmOperatorType *ot);
void MESH_OT_primitive_ico_sphere_add(struct wmOperatorType *ot);
/* *** editmesh_add_gizmo.c *** */
+
void MESH_OT_primitive_cube_add_gizmo(struct wmOperatorType *ot);
/* *** editmesh_bevel.c *** */
+
void MESH_OT_bevel(struct wmOperatorType *ot);
struct wmKeyMap *bevel_modal_keymap(struct wmKeyConfig *keyconf);
/* *** editmesh_bisect.c *** */
+
void MESH_OT_bisect(struct wmOperatorType *ot);
/* *** editmesh_extrude.c *** */
+
void MESH_OT_extrude_repeat(struct wmOperatorType *ot);
void MESH_OT_extrude_region(struct wmOperatorType *ot);
void MESH_OT_extrude_context(struct wmOperatorType *ot);
@@ -124,15 +149,20 @@ void MESH_OT_extrude_faces_indiv(struct wmOperatorType *ot);
void MESH_OT_dupli_extrude_cursor(struct wmOperatorType *ot);
/* *** editmesh_extrude_screw.c *** */
+
void MESH_OT_screw(struct wmOperatorType *ot);
/* *** editmesh_extrude_spin.c *** */
+
void MESH_OT_spin(struct wmOperatorType *ot);
+
/* *** editmesh_extrude_spin_gizmo.c *** */
+
void MESH_GGT_spin(struct wmGizmoGroupType *gzgt);
void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt);
/* *** editmesh_polybuild.c *** */
+
void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot);
@@ -140,16 +170,22 @@ void MESH_OT_polybuild_transform_at_cursor(struct wmOperatorType *ot);
void MESH_OT_polybuild_delete_at_cursor(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
+
void MESH_OT_inset(struct wmOperatorType *ot);
/* *** editmesh_intersect.c *** */
+
void MESH_OT_intersect(struct wmOperatorType *ot);
void MESH_OT_intersect_boolean(struct wmOperatorType *ot);
void MESH_OT_face_split_by_edges(struct wmOperatorType *ot);
/* *** editmesh_knife.c *** */
+
void MESH_OT_knife_tool(struct wmOperatorType *ot);
void MESH_OT_knife_project(struct wmOperatorType *ot);
+/**
+ * \param use_tag: When set, tag all faces inside the polylines.
+ */
void EDBM_mesh_knife(struct bContext *C,
struct ViewContext *vc,
struct LinkNode *polys,
@@ -159,13 +195,16 @@ void EDBM_mesh_knife(struct bContext *C,
struct wmKeyMap *knifetool_modal_keymap(struct wmKeyConfig *keyconf);
/* *** editmesh_loopcut.c *** */
+
void MESH_OT_loopcut(struct wmOperatorType *ot);
/* *** editmesh_rip.c *** */
+
void MESH_OT_rip(struct wmOperatorType *ot);
void MESH_OT_rip_edge(struct wmOperatorType *ot);
/* *** editmesh_select.c *** */
+
void MESH_OT_select_similar(struct wmOperatorType *ot);
void MESH_OT_select_similar_region(struct wmOperatorType *ot);
void MESH_OT_select_mode(struct wmOperatorType *ot);
@@ -265,10 +304,12 @@ void MESH_OT_smooth_normals(struct wmOperatorType *ot);
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
/* *** editmesh_mask_extract.c *** */
+
void MESH_OT_paint_mask_extract(struct wmOperatorType *ot);
void MESH_OT_face_set_extract(struct wmOperatorType *ot);
void MESH_OT_paint_mask_slice(struct wmOperatorType *ot);
+/** Called in transform_ops.c, on each regeneration of key-maps. */
struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
#if defined(WITH_FREESTYLE)
@@ -277,13 +318,13 @@ void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
#endif
/* *** mesh_data.c *** */
+
void MESH_OT_uv_texture_add(struct wmOperatorType *ot);
void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
void MESH_OT_sculpt_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_sculpt_vertex_color_remove(struct wmOperatorType *ot);
-/* no create_mask yet */
void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 94823b92c44..d616dd3bb63 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -372,7 +372,6 @@ void ED_operatormacros_mesh(void)
RNA_boolean_set(otmacro->ptr, "mirror", false);
}
-/* note mesh keymap also for other space? */
void ED_keymap_mesh(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Mesh", 0, 0);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 1b720f2c14d..ebe8b758aa2 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -755,11 +755,10 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
/* -------------------------------------------------------------------- */
/** \name Join as Shapes
+ *
+ * Append selected meshes vertex locations as shapes of the active mesh.
* \{ */
-/* Append selected meshes vertex locations as shapes of the active mesh,
- * return 0 if no join is made (error) and 1 of the join is done */
-
int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -876,12 +875,6 @@ BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob,
*r_em_mirror = em_mirror;
}
-/**
- * Mode is 's' start, or 'e' end, or 'u' use
- * if end, ob can be NULL.
- * \note This is supposed return -1 on error,
- * which callers are currently checking for, but is not used so far.
- */
void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *me_eval)
{
Mesh *me_mirror;
@@ -1012,11 +1005,6 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob,
return editbmesh_get_x_mirror_vert_spatial(ob, em, co);
}
-/**
- * Wrapper for object-mode/edit-mode.
- *
- * call #BM_mesh_elem_table_ensure first for editmesh.
- */
int ED_mesh_mirror_get_vert(Object *ob, int index)
{
Mesh *me = ob->data;
@@ -1146,7 +1134,6 @@ static bool mirror_facecmp(const void *a, const void *b)
return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
}
-/* This is a Mesh-based copy of mesh_get_x_mirror_faces() */
int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
{
Mesh *me = ob->data;
@@ -1209,15 +1196,8 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
return mirrorfaces;
}
-/* selection, vertex and face */
-/* returns 0 if not found, otherwise 1 */
+/* Selection (vertex and face). */
-/**
- * Face selection in object mode,
- * currently only weight-paint and vertex-paint use this.
- *
- * \return boolean true == Found
- */
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
ViewContext vc;
@@ -1280,10 +1260,6 @@ static void ed_mesh_pick_face_vert__mpoly_find(
}
}
}
-/**
- * Use when the back buffer stores face index values. but we want a vert.
- * This gets the face then finds the closest vertex to mval.
- */
bool ED_mesh_pick_face_vert(
bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index f7b53b5513f..5c724ac2d01 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -253,7 +253,6 @@ static void mball_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_mball_undosys_type(UndoType *ut)
{
ut->name = "Edit MBall";
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 292052b778a..bedb9d4f4f4 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -62,7 +62,6 @@
/** \name Edit Mode Functions
* \{ */
-/* This function is used to free all MetaElems from MetaBall */
void ED_mball_editmball_free(Object *obedit)
{
MetaBall *mb = (MetaBall *)obedit->data;
@@ -71,8 +70,6 @@ void ED_mball_editmball_free(Object *obedit)
mb->lastelem = NULL;
}
-/* This function is called, when MetaBall Object is
- * switched from object mode to edit mode */
void ED_mball_editmball_make(Object *obedit)
{
MetaBall *mb = (MetaBall *)obedit->data;
@@ -90,9 +87,6 @@ void ED_mball_editmball_make(Object *obedit)
mb->editelems = &mb->elems;
}
-/* This function is called, when MetaBall Object switched from
- * edit mode to object mode. List of MetaElements is copied
- * from object->data->edit_elems to object->data->elems. */
void ED_mball_editmball_load(Object *UNUSED(obedit))
{
}
@@ -122,9 +116,6 @@ bool ED_mball_deselect_all_multi(bContext *C)
/** \name Add Meta Primitive Utility
* \{ */
-/**
- * Add meta-element primitive to meta-ball object (which is in edit mode).
- */
MetaElem *ED_mball_add_primitive(
bContext *UNUSED(C), Object *obedit, bool obedit_is_new, float mat[4][4], float dia, int type)
{
@@ -759,8 +750,6 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
/** \name Select Pick Utility
* \{ */
-/* Select MetaElement with mouse click (user can select radius circle or
- * stiffness circle) */
bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index c77db10d74b..9354171a1e4 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -130,7 +130,7 @@
/** \name Local Enum Declarations
* \{ */
-/* this is an exact copy of the define in rna_light.c
+/* This is an exact copy of the define in `rna_light.c`
* kept here because of linking order.
* Icons are only defined here */
const EnumPropertyItem rna_enum_light_type_items[] = {
@@ -331,8 +331,6 @@ void ED_object_base_init_transform_on_add(Object *object, const float loc[3], co
BKE_object_to_mat4(object, object->obmat);
}
-/* Uses context to figure out transform for primitive.
- * Returns standard diameter. */
float ED_object_new_primitive_matrix(bContext *C,
Object *obedit,
const float loc[3],
@@ -603,12 +601,6 @@ bool ED_object_add_generic_get_opts(bContext *C,
return true;
}
-/**
- * For object add primitive operators, or for object creation when `obdata != NULL`.
- * \param obdata: Assigned to #Object.data, with increased user count.
- *
- * \note Do not call undo push in this function (users of this function have to).
- */
Object *ED_object_add_type_with_obdata(bContext *C,
const int type,
const char *name,
@@ -1724,7 +1716,6 @@ static int object_instance_add_invoke(bContext *C, wmOperator *op, const wmEvent
return op->type->exec(C, op);
}
-/* only used as menu */
void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1994,8 +1985,7 @@ void OBJECT_OT_pointcloud_add(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
/** \name Delete Object Operator
* \{ */
-/* remove base from a specific scene */
-/* NOTE: now unlinks constraints as well. */
+
void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
{
if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 &&
@@ -2013,10 +2003,6 @@ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
BKE_scene_collections_object_remove(bmain, scene, ob, true);
}
-/**
- * Remove base from a specific scene.
- * `ob` must not be indirectly used.
- */
void ED_object_base_free_and_unlink_no_indirect_check(Main *bmain, Scene *scene, Object *ob)
{
BLI_assert(!BKE_library_ID_is_indirectly_used(bmain, ob));
@@ -3115,11 +3101,11 @@ static int object_convert_exec(bContext *C, wmOperator *op)
basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, NULL);
newob = basen->object;
- /* Decrement original point-cloud's usage count. */
+ /* Decrement original point cloud's usage count. */
PointCloud *pointcloud = newob->data;
id_us_min(&pointcloud->id);
- /* Make a new copy of the point-cloud. */
+ /* Make a new copy of the point cloud. */
newob->data = BKE_id_copy(bmain, &pointcloud->id);
}
else {
@@ -3371,11 +3357,6 @@ static Base *object_add_duplicate_internal(Main *bmain,
return basen;
}
-/* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */
-/* leaves selection of base/object unaltered.
- * NOTE: don't call this within a loop since clear_* funcs loop over the entire database.
- * NOTE: caller must do DAG_relations_tag_update(bmain);
- * this is not done automatic since we may duplicate many objects in a batch */
Base *ED_object_add_duplicate(
Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, const eDupli_ID_Flags dupflag)
{
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 47c2998ed3d..5c3a8fc2277 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -80,10 +80,6 @@
/** \name Constraint Data Accessors
* \{ */
-/**
- * If object is in pose-mode, return active bone constraints, else object constraints.
- * No constraints are returned for a bone on an inactive bone-layer.
- */
ListBase *ED_object_constraint_active_list(Object *ob)
{
if (ob == NULL) {
@@ -105,10 +101,6 @@ ListBase *ED_object_constraint_active_list(Object *ob)
return NULL;
}
-/**
- * Get the constraints for the active pose bone. Bone may be on an inactive bone-layer
- * (unlike #ED_object_constraint_active_list, such constraints are not excluded here).
- */
ListBase *ED_object_pose_constraint_list(const bContext *C)
{
bPoseChannel *pose_bone = CTX_data_pointer_get(C, "pose_bone").data;
@@ -122,8 +114,6 @@ ListBase *ED_object_pose_constraint_list(const bContext *C)
return &pose_bone->constraints;
}
-/* Find the list that a given constraint belongs to,
- * and/or also get the posechannel this is from (if applicable) */
ListBase *ED_object_constraint_list_from_constraint(Object *ob,
bConstraint *con,
bPoseChannel **r_pchan)
@@ -164,7 +154,6 @@ ListBase *ED_object_constraint_list_from_constraint(Object *ob,
return NULL;
}
-/* single constraint */
bConstraint *ED_object_constraint_active_get(Object *ob)
{
return BKE_constraints_active_get(ED_object_constraint_active_list(ob));
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 6251fb799c5..49149a5152f 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -603,7 +603,6 @@ static bool data_transfer_poll_property(const bContext *UNUSED(C),
return true;
}
-/* Transfer mesh data from active to selected objects. */
void OBJECT_OT_data_transfer(wmOperatorType *ot)
{
PropertyRNA *prop;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 78440f52160..38d0a044cb4 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -134,8 +134,6 @@ Object *ED_object_context(const bContext *C)
return CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
}
-/* Find the correct active object per context.
- * NOTE: context can be NULL when called from a enum with #PROP_ENUM_NO_CONTEXT. */
Object *ED_object_active_context(const bContext *C)
{
Object *ob = NULL;
@@ -148,14 +146,6 @@ Object *ED_object_active_context(const bContext *C)
return ob;
}
-/**
- * Return an array of objects:
- * - When in the property space, return the pinned or active object.
- * - When in edit-mode/pose-mode, return an array of objects in the mode.
- * - Otherwise return selected objects,
- * the callers \a filter_fn needs to check of they are editable
- * (assuming they need to be modified).
- */
Object **ED_object_array_in_mode_or_selected(bContext *C,
bool (*filter_fn)(const Object *ob, void *user_data),
void *filter_user_data,
@@ -669,10 +659,6 @@ bool ED_object_editmode_load(Main *bmain, Object *obedit)
return ED_object_editmode_load_free_ex(bmain, obedit, true, false);
}
-/**
- * \param flag:
- * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly.
- */
bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag)
{
const bool free_data = (flag & EM_FREEDATA) != 0;
@@ -723,11 +709,6 @@ bool ED_object_editmode_exit(bContext *C, int flag)
return ED_object_editmode_exit_ex(bmain, scene, obedit, flag);
}
-/**
- * Support freeing edit-mode data without flushing it back to the object.
- *
- * \return true if data was freed.
- */
bool ED_object_editmode_free_ex(Main *bmain, Object *obedit)
{
return ED_object_editmode_load_free_ex(bmain, obedit, false, true);
@@ -1161,11 +1142,6 @@ static bool has_pose_motion_paths(Object *ob)
return ob->pose && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
}
-/* For the objects with animation: update paths for those that have got them
- * This should selectively update paths that exist...
- *
- * To be called from various tools that do incremental updates
- */
void ED_objects_recalculate_paths(bContext *C,
Scene *scene,
eObjectPathCalcRange range,
@@ -1428,7 +1404,6 @@ static void object_clear_mpath(Object *ob)
}
}
-/* Clear motion paths for all objects */
void ED_objects_clear_paths(bContext *C, bool only_selected)
{
if (only_selected) {
@@ -1663,10 +1638,10 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/** \name Object Mode Set Operator
* \{ */
-static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
+static const EnumPropertyItem *object_mode_set_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
const EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
@@ -1815,7 +1790,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
- RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
+ RNA_def_enum_funcs(ot->prop, object_mode_set_itemf);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c
index 92f3d28878c..f5127bd5228 100644
--- a/source/blender/editors/object/object_facemap_ops.c
+++ b/source/blender/editors/object/object_facemap_ops.c
@@ -53,7 +53,6 @@
#include "object_intern.h"
-/* called while not in editmode */
void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
{
int fmap_nr;
@@ -77,7 +76,6 @@ void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
}
}
-/* called while not in editmode */
void ED_object_facemap_face_remove(Object *ob, bFaceMap *fmap, int facenum)
{
int fmap_nr;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index fe07ecef438..9a1b4b48464 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -45,6 +45,7 @@ enum eObject_Hook_Add_Mode {
/* internal exports only */
/* object_transform.c */
+
void OBJECT_OT_location_clear(struct wmOperatorType *ot);
void OBJECT_OT_rotation_clear(struct wmOperatorType *ot);
void OBJECT_OT_scale_clear(struct wmOperatorType *ot);
@@ -55,6 +56,7 @@ void OBJECT_OT_transform_axis_target(struct wmOperatorType *ot);
void OBJECT_OT_origin_set(struct wmOperatorType *ot);
/* object_relations.c */
+
void OBJECT_OT_parent_set(struct wmOperatorType *ot);
void OBJECT_OT_parent_no_inverse_set(struct wmOperatorType *ot);
void OBJECT_OT_parent_clear(struct wmOperatorType *ot);
@@ -67,10 +69,18 @@ void OBJECT_OT_convert_proxy_to_override(struct wmOperatorType *ot);
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
+/**
+ * Used for drop-box.
+ * Assigns to object under cursor, only first material slot.
+ */
void OBJECT_OT_drop_named_material(struct wmOperatorType *ot);
+/**
+ * \note Only for empty-image objects, this operator is needed
+ */
void OBJECT_OT_unlink_data(struct wmOperatorType *ot);
/* object_edit.c */
+
void OBJECT_OT_hide_view_set(struct wmOperatorType *ot);
void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot);
void OBJECT_OT_hide_collection(struct wmOperatorType *ot);
@@ -93,6 +103,7 @@ void OBJECT_OT_link_to_collection(struct wmOperatorType *ot);
void OBJECT_OT_transfer_mode(struct wmOperatorType *ot);
/* object_select.c */
+
void OBJECT_OT_select_all(struct wmOperatorType *ot);
void OBJECT_OT_select_random(struct wmOperatorType *ot);
void OBJECT_OT_select_by_type(struct wmOperatorType *ot);
@@ -104,6 +115,7 @@ void OBJECT_OT_select_less(struct wmOperatorType *ot);
void OBJECT_OT_select_same_collection(struct wmOperatorType *ot);
/* object_add.c */
+
void OBJECT_OT_add(struct wmOperatorType *ot);
void OBJECT_OT_add_named(struct wmOperatorType *ot);
void OBJECT_OT_transform_to_mouse(struct wmOperatorType *ot);
@@ -120,6 +132,9 @@ void OBJECT_OT_camera_add(struct wmOperatorType *ot);
void OBJECT_OT_speaker_add(struct wmOperatorType *ot);
void OBJECT_OT_hair_add(struct wmOperatorType *ot);
void OBJECT_OT_pointcloud_add(struct wmOperatorType *ot);
+/**
+ * Only used as menu.
+ */
void OBJECT_OT_collection_instance_add(struct wmOperatorType *ot);
void OBJECT_OT_data_instance_add(struct wmOperatorType *ot);
@@ -131,10 +146,15 @@ void OBJECT_OT_join_shapes(struct wmOperatorType *ot);
void OBJECT_OT_convert(struct wmOperatorType *ot);
/* object_volume.c */
+
void OBJECT_OT_volume_add(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void OBJECT_OT_volume_import(struct wmOperatorType *ot);
/* object_hook.c */
+
void OBJECT_OT_hook_add_selob(struct wmOperatorType *ot);
void OBJECT_OT_hook_add_newob(struct wmOperatorType *ot);
void OBJECT_OT_hook_remove(struct wmOperatorType *ot);
@@ -144,6 +164,7 @@ void OBJECT_OT_hook_reset(struct wmOperatorType *ot);
void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
/* object_collection.c */
+
void COLLECTION_OT_create(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove(struct wmOperatorType *ot);
@@ -151,6 +172,7 @@ void COLLECTION_OT_objects_add_active(struct wmOperatorType *ot);
void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot);
/* object_modifier.c */
+
bool edit_modifier_poll_generic(struct bContext *C,
struct StructRNA *rna_type,
int obtype_flag,
@@ -249,6 +271,7 @@ void CONSTRAINT_OT_objectsolver_clear_inverse(struct wmOperatorType *ot);
void CONSTRAINT_OT_followpath_path_animate(struct wmOperatorType *ot);
/* object_vgroup.c */
+
void OBJECT_OT_vertex_group_add(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_remove(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_assign(struct wmOperatorType *ot);
@@ -279,6 +302,7 @@ void OBJECT_OT_vertex_weight_normalize_active_vertex(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_copy(struct wmOperatorType *ot);
/* object_facemap_ops.c */
+
void OBJECT_OT_face_map_add(struct wmOperatorType *ot);
void OBJECT_OT_face_map_remove(struct wmOperatorType *ot);
void OBJECT_OT_face_map_assign(struct wmOperatorType *ot);
@@ -288,9 +312,11 @@ void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot);
void OBJECT_OT_face_map_move(struct wmOperatorType *ot);
/* object_warp.c */
+
void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot);
/* object_shapekey.c */
+
void OBJECT_OT_shape_key_add(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_remove(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_clear(struct wmOperatorType *ot);
@@ -299,6 +325,7 @@ void OBJECT_OT_shape_key_mirror(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_move(struct wmOperatorType *ot);
/* object_collection.c */
+
void OBJECT_OT_collection_add(struct wmOperatorType *ot);
void OBJECT_OT_collection_link(struct wmOperatorType *ot);
void OBJECT_OT_collection_remove(struct wmOperatorType *ot);
@@ -306,18 +333,25 @@ void OBJECT_OT_collection_unlink(struct wmOperatorType *ot);
void OBJECT_OT_collection_objects_select(struct wmOperatorType *ot);
/* object_bake.c */
+
void OBJECT_OT_bake_image(wmOperatorType *ot);
void OBJECT_OT_bake(wmOperatorType *ot);
/* object_random.c */
+
void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_remesh.cc */
+
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
void OBJECT_OT_voxel_size_edit(struct wmOperatorType *ot);
void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
+
+/**
+ * Transfer mesh data from active to selected objects.
+ */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
void OBJECT_OT_datalayout_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 0c1b394a916..d3f72b91366 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -111,10 +111,6 @@ static const char *object_mode_op_string(eObjectMode mode)
return NULL;
}
-/**
- * Checks the mode to be set is compatible with the object
- * should be made into a generic function
- */
bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
{
if (mode == OB_MODE_OBJECT) {
@@ -162,11 +158,6 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
return false;
}
-/**
- * Sets the mode to a compatible state (use before entering the mode).
- *
- * This is so each mode's exec function can call
- */
bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports)
{
bool ok;
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 21b978268d9..71ad54383a6 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -152,12 +152,6 @@ static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
md_eval->mode = mode;
}
-/**
- * Add a modifier to given object, including relevant extra processing needed by some physics types
- * (particles, simulations...).
- *
- * \param scene: is only used to set current frame in some cases, and may be NULL.
- */
ModifierData *ED_object_modifier_add(
ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
@@ -264,14 +258,6 @@ static bool object_has_modifier(const Object *ob, const ModifierData *exclude, M
return false;
}
-/* If the object data of 'orig_ob' has other users, run 'callback' on
- * each of them.
- *
- * If include_orig is true, the callback will run on 'orig_ob' too.
- *
- * If the callback ever returns true, iteration will stop and the
- * function value will be true. Otherwise the function returns false.
- */
bool ED_object_iter_other(Main *bmain,
Object *orig_ob,
const bool include_orig,
@@ -314,9 +300,6 @@ static bool object_has_modifier_cb(Object *ob, void *data)
return object_has_modifier(ob, NULL, type);
}
-/* Use with ED_object_iter_other(). Sets the total number of levels
- * for any multires modifiers on the object to the int pointed to by
- * callback_data. */
bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
{
int totlevel = *((char *)totlevel_v);
@@ -731,7 +714,7 @@ static bool modifier_apply_shape(Main *bmain,
BKE_id_free(NULL, mesh_applied);
}
else {
- /* TODO: implement for hair, point-clouds and volumes. */
+ /* TODO: implement for hair, point clouds and volumes. */
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return false;
}
@@ -830,7 +813,7 @@ static bool modifier_apply_obdata(
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
else {
- /* TODO: implement for hair, point-clouds and volumes. */
+ /* TODO: implement for hair, point clouds and volumes. */
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
return false;
}
@@ -1696,6 +1679,8 @@ void OBJECT_OT_modifier_set_active(wmOperatorType *ot)
}
/** \} */
+
+/* ------------------------------------------------------------------- */
/** \name Copy Modifier To Selected Operator
* \{ */
@@ -2695,6 +2680,7 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+
/** \} */
/* ------------------------------------------------------------------- */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index b51644eebf3..811f20e82be 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1783,8 +1783,6 @@ static void single_object_users(
BKE_main_collection_sync_remap(bmain);
}
-/* not an especially efficient function, only added so the single user
- * button can be functional. */
void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
{
FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) {
@@ -2644,10 +2642,6 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_FINISHED;
}
-/**
- * Used for drop-box.
- * Assigns to object under cursor, only first material slot.
- */
void OBJECT_OT_drop_named_material(wmOperatorType *ot)
{
/* identifiers */
@@ -2706,9 +2700,6 @@ static int object_unlink_data_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/**
- * \note Only for empty-image objects, this operator is needed
- */
void OBJECT_OT_unlink_data(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 3bdf7e0d34d..719ffd36f03 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -821,7 +821,8 @@ static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmet
mmd.flag = 0;
mmd.flag &= MOD_MIR_AXIS_X << i;
mesh_mirror_temp = mesh_mirror;
- mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(&mmd, ob, mesh_mirror, axis);
+ mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ &mmd, ob, mesh_mirror, axis, true);
if (mesh_mirror_temp != mesh_mirror) {
BKE_id_free(nullptr, mesh_mirror_temp);
}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index eb37aebcff2..a86dba15469 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -89,14 +89,6 @@
/** \name Public Object Selection API
* \{ */
-/**
- * Simple API for object selection, rather than just using the flag
- * this takes into account the 'restrict selection in 3d view' flag.
- * deselect works always, the restriction just prevents selection
- *
- * \note Caller must send a `NC_SCENE | ND_OB_SELECT` notifier
- * (or a `NC_SCENE | ND_OB_VISIBLE` in case of visibility toggling).
- */
void ED_object_base_select(Base *base, eObjectSelect_Mode mode)
{
if (mode == BA_INVERT) {
@@ -121,9 +113,6 @@ void ED_object_base_select(Base *base, eObjectSelect_Mode mode)
}
}
-/**
- * Call when the active base has changed.
- */
void ED_object_base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
@@ -134,9 +123,6 @@ void ED_object_base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_la
}
}
-/**
- * Change active base, it includes the notifier
- */
void ED_object_base_activate(bContext *C, Base *base)
{
Scene *scene = CTX_data_scene(C);
@@ -242,10 +228,6 @@ static int get_base_select_priority(Base *base)
return 1;
}
-/**
- * If id is not already an Object, try to find an object that uses it as data.
- * Prefers active, then selected, then visible/selectable.
- */
Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
{
BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
@@ -279,12 +261,6 @@ Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
return base_best;
}
-/**
- * Select and make the target object active in the view layer.
- * If already selected, selection isn't changed.
- *
- * \returns false if not found in current view layer
- */
bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_hidden))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -316,13 +292,6 @@ bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_
return true;
}
-/**
- * Select and make the target object and bone active.
- * Switches to Pose mode if in Object mode so the selection is visible.
- * Un-hides the target bone and bone layer if necessary.
- *
- * \returns false if object not in layer, bone not found, or other error
- */
bool ED_object_jump_to_bone(bContext *C,
Object *ob,
const char *bone_name,
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index 2723d7ad1e3..043a679a0c0 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -402,6 +402,8 @@ void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ID);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Generic Functions for Operators Using Names and Data Context
* \{ */
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index c7dfe911ce7..5f85f6ea0eb 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -369,10 +369,6 @@ void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container
}
}
-/**
- * This may be called multiple times with the same data.
- * Each time, the original transformations are re-applied, instead of accumulating the changes.
- */
void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
struct Main *bmain,
Depsgraph *depsgraph)
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index f0ab082cd9c..3e74aaeeb10 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -140,9 +140,6 @@ bool ED_vgroup_sync_from_pose(Object *ob)
return false;
}
-/**
- * Removes out of range MDeformWeights
- */
void ED_vgroup_data_clamp_range(ID *id, const int total)
{
MDeformVert **dvert_arr;
@@ -264,13 +261,6 @@ bool ED_vgroup_parray_alloc(ID *id,
return false;
}
-/**
- * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true.
- * This finds the unselected mirror deform verts and copies the weights to them from the selected.
- *
- * \note \a dvert_array has mirrored weights filled in,
- * in case cleanup operations are needed on both.
- */
void ED_vgroup_parray_mirror_sync(Object *ob,
MDeformVert **dvert_array,
const int dvert_tot,
@@ -314,11 +304,6 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
MEM_freeN(dvert_array_all);
}
-/**
- * Fill in the pointers for mirror verts (as if all mirror verts were selected too).
- *
- * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points.
- */
void ED_vgroup_parray_mirror_assign(Object *ob, MDeformVert **dvert_array, const int dvert_tot)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -383,7 +368,6 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array,
}
}
-/* matching index only */
bool ED_vgroup_array_copy(Object *ob, Object *ob_from)
{
MDeformVert **dvert_array_from = NULL, **dvf;
@@ -575,9 +559,6 @@ static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
}
}
-/**
- * Use when adjusting the active vertex weight and apply to mirror vertices.
- */
void ED_vgroup_vert_active_mirror(Object *ob, int def_nr)
{
Mesh *me = ob->data;
@@ -883,7 +864,6 @@ static void ED_vgroup_nr_vert_add(
}
}
-/* called while not in editmode */
void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
{
/* add the vert to the deform group with the
@@ -912,7 +892,6 @@ void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight,
}
}
-/* mesh object mode, lattice can be in editmode */
void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
{
/* This routine removes the vertex from the specified
@@ -2369,8 +2348,6 @@ static void dvert_mirror_op(MDeformVert *dvert,
}
}
-/* TODO: vgroup locking. */
-/* TODO: face masking. */
void ED_vgroup_mirror(Object *ob,
const bool mirror_weights,
const bool flip_vgroups,
@@ -2379,6 +2356,8 @@ void ED_vgroup_mirror(Object *ob,
int *r_totmirr,
int *r_totfail)
{
+ /* TODO: vgroup locking.
+ * TODO: face masking. */
#define VGROUP_MIRR_OP \
dvert_mirror_op(dvert, \
diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c
index fbdee00c29c..6c92814abc0 100644
--- a/source/blender/editors/object/object_volume.c
+++ b/source/blender/editors/object/object_volume.c
@@ -158,7 +158,6 @@ static int volume_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
return OPERATOR_RUNNING_MODAL;
}
-/* called by other space types too */
void OBJECT_OT_volume_import(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index be6b44f87bf..80e3f934c80 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -92,7 +92,6 @@ static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* add surface slot */
void DPAINT_OT_surface_slot_add(wmOperatorType *ot)
{
/* identifiers */
@@ -141,7 +140,6 @@ static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* remove surface slot */
void DPAINT_OT_surface_slot_remove(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index fc80767be9e..f1e6f02cb39 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1419,7 +1419,6 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
-/* set current distances to be kept between neighboring keys */
void recalc_lengths(PTCacheEdit *edit)
{
POINT_P;
@@ -1437,7 +1436,6 @@ void recalc_lengths(PTCacheEdit *edit)
}
}
-/* calculate a tree for finding nearest emitter's vertice */
void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), ParticleSystem *psys)
{
PTCacheEdit *edit = psys->edit;
@@ -5261,7 +5259,6 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
/** \name Particle Edit Toggle Operator
* \{ */
-/* initialize needed data for bake edit */
void PE_create_particle_edit(
Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 601a8385a24..804ab614c09 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -298,7 +298,6 @@ static void particle_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref));
}
-/* Export for ED_undo_sys. */
void ED_particle_undosys_type(UndoType *ut)
{
ut->name = "Edit Particle";
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index ef07d73826a..e8270c7a4aa 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -32,6 +32,7 @@ struct Scene;
struct wmOperatorType;
/* particle_edit.c */
+
void PARTICLE_OT_select_all(struct wmOperatorType *ot);
void PARTICLE_OT_select_roots(struct wmOperatorType *ot);
void PARTICLE_OT_select_tips(struct wmOperatorType *ot);
@@ -60,18 +61,28 @@ void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
+/**
+ * Initialize needed data for bake edit.
+ */
void PE_create_particle_edit(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct PointCache *cache,
struct ParticleSystem *psys);
+/**
+ * Set current distances to be kept between neighboring keys.
+ */
void recalc_lengths(struct PTCacheEdit *edit);
+/**
+ * Calculate a tree for finding nearest emitter's vertice.
+ */
void recalc_emitter_field(struct Depsgraph *depsgraph,
struct Object *ob,
struct ParticleSystem *psys);
void update_world_cos(struct Object *ob, struct PTCacheEdit *edit);
/* particle_object.c */
+
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);
@@ -92,6 +103,7 @@ void PARTICLE_OT_dupliob_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_refresh(struct wmOperatorType *ot);
/* particle_boids.c */
+
void BOID_OT_rule_add(struct wmOperatorType *ot);
void BOID_OT_rule_del(struct wmOperatorType *ot);
void BOID_OT_rule_move_up(struct wmOperatorType *ot);
@@ -103,6 +115,7 @@ void BOID_OT_state_move_up(struct wmOperatorType *ot);
void BOID_OT_state_move_down(struct wmOperatorType *ot);
/* physics_fluid.c */
+
void FLUID_OT_bake_all(struct wmOperatorType *ot);
void FLUID_OT_free_all(struct wmOperatorType *ot);
void FLUID_OT_bake_data(struct wmOperatorType *ot);
@@ -118,13 +131,21 @@ void FLUID_OT_free_guides(struct wmOperatorType *ot);
void FLUID_OT_pause_bake(struct wmOperatorType *ot);
/* dynamicpaint.c */
+
void DPAINT_OT_bake(struct wmOperatorType *ot);
+/**
+ * Add surface slot.
+ */
void DPAINT_OT_surface_slot_add(struct wmOperatorType *ot);
+/**
+ * Remove surface slot.
+ */
void DPAINT_OT_surface_slot_remove(struct wmOperatorType *ot);
void DPAINT_OT_type_toggle(struct wmOperatorType *ot);
void DPAINT_OT_output_toggle(struct wmOperatorType *ot);
/* physics_pointcache.c */
+
void PTCACHE_OT_bake_all(struct wmOperatorType *ot);
void PTCACHE_OT_free_bake_all(struct wmOperatorType *ot);
void PTCACHE_OT_bake(struct wmOperatorType *ot);
@@ -134,6 +155,7 @@ void PTCACHE_OT_add(struct wmOperatorType *ot);
void PTCACHE_OT_remove(struct wmOperatorType *ot);
/* rigidbody_object.c */
+
void RIGIDBODY_OT_object_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_object_remove(struct wmOperatorType *ot);
@@ -144,10 +166,12 @@ void RIGIDBODY_OT_shape_change(struct wmOperatorType *ot);
void RIGIDBODY_OT_mass_calculate(struct wmOperatorType *ot);
/* rigidbody_constraint.c */
+
void RIGIDBODY_OT_constraint_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_constraint_remove(struct wmOperatorType *ot);
/* rigidbody_world.c */
+
void RIGIDBODY_OT_world_add(struct wmOperatorType *ot);
void RIGIDBODY_OT_world_remove(struct wmOperatorType *ot);
void RIGIDBODY_OT_world_export(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index e1d03e6f3be..d374717664b 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -28,6 +28,7 @@ struct bContext;
struct wmOperatorType;
/* render_shading.c */
+
void OBJECT_OT_material_slot_add(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_remove(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_assign(struct wmOperatorType *ot);
@@ -80,10 +81,18 @@ void TEXTURE_OT_slot_paste(struct wmOperatorType *ot);
void TEXTURE_OT_slot_move(struct wmOperatorType *ot);
/* render_internal.c */
+
+/**
+ * Contextual render, using current scene, view3d?
+ */
void RENDER_OT_render(struct wmOperatorType *ot);
void RENDER_OT_shutter_curve_preset(struct wmOperatorType *ot);
/* render_view.c */
+
+/**
+ * New window uses x,y to set position.
+ */
struct ScrArea *render_view_open(struct bContext *C, int mx, int my, struct ReportList *reports);
void RENDER_OT_view_show(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 49e7ebf6340..29d829dc131 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -1076,7 +1076,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
return OPERATOR_RUNNING_MODAL;
}
-/* contextual render, using current scene, view3d? */
void RENDER_OT_render(wmOperatorType *ot)
{
PropertyRNA *prop;
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 4bf250b9d4f..409430d28f1 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -103,6 +103,8 @@
#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
+#include "UI_interface_icons.h"
+
#ifndef NDEBUG
/* Used for database init assert(). */
# include "BLI_threads.h"
@@ -212,7 +214,7 @@ static bool check_engine_supports_preview(Scene *scene)
static bool preview_method_is_render(int pr_method)
{
- return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER, PR_NODE_RENDER);
+ return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
}
void ED_preview_free_dbase(void)
@@ -459,7 +461,7 @@ static Scene *preview_prepare_scene(
Scene *sce;
Main *pr_main = sp->pr_main;
- memcpy(pr_main->name, BKE_main_blendfile_path(bmain), sizeof(pr_main->name));
+ memcpy(pr_main->filepath, BKE_main_blendfile_path(bmain), sizeof(pr_main->filepath));
sce = preview_get_scene(pr_main);
if (sce) {
@@ -526,15 +528,6 @@ static Scene *preview_prepare_scene(
MA_SPHERE_A :
mat->pr_type;
set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
-
- if (sp->pr_method != PR_ICON_RENDER) {
- if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(mat->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origmat is not safe! */
- BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, true);
- }
- }
}
else {
sce->display.render_aa = SCE_DISPLAY_AA_OFF;
@@ -570,13 +563,6 @@ static Scene *preview_prepare_scene(
sp->id_copy = NULL;
BLI_addtail(&pr_main->textures, tex);
}
-
- if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origtex is not safe! */
- BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true);
- }
}
else if (id_type == ID_LA) {
Light *la = NULL, *origla = (Light *)id;
@@ -606,13 +592,6 @@ static Scene *preview_prepare_scene(
}
}
}
-
- if (la && la->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(la->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origla is not safe! */
- BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true);
- }
}
else if (id_type == ID_WO) {
World *wrld = NULL, *origwrld = (World *)id;
@@ -626,13 +605,6 @@ static Scene *preview_prepare_scene(
set_preview_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method);
sce->world = wrld;
-
- if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) {
- /* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(wrld->nodetree, sp->sizex, sp->sizey, true);
- /* WATCH: Accessing origwrld is not safe! */
- BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true);
- }
}
return sce;
@@ -786,6 +758,11 @@ struct ObjectPreviewData {
int sizey;
};
+static bool object_preview_is_type_supported(const Object *ob)
+{
+ return OB_TYPE_IS_GEOMETRY(ob->type);
+}
+
static Object *object_preview_camera_create(Main *preview_main,
ViewLayer *view_layer,
Object *preview_object)
@@ -989,7 +966,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
preview_sized->sizey,
IB_rect,
V3D_OFSDRAW_NONE,
- R_ALPHAPREMUL,
+ R_ADDSKY,
NULL,
NULL,
err_out);
@@ -1030,41 +1007,8 @@ static int shader_preview_break(void *spv)
return *(sp->stop);
}
-/* outside thread, called before redraw notifiers, it moves finished preview over */
-static void shader_preview_updatejob(void *spv)
+static void shader_preview_updatejob(void *UNUSED(spv))
{
- ShaderPreview *sp = spv;
-
- if (sp->pr_method == PR_NODE_RENDER) {
- if (GS(sp->id->name) == ID_MA) {
- Material *mat = (Material *)sp->id;
-
- if (sp->matcopy && mat->nodetree && sp->matcopy->nodetree) {
- ntreeLocalSync(sp->matcopy->nodetree, mat->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_TE) {
- Tex *tex = (Tex *)sp->id;
-
- if (sp->texcopy && tex->nodetree && sp->texcopy->nodetree) {
- ntreeLocalSync(sp->texcopy->nodetree, tex->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_WO) {
- World *wrld = (World *)sp->id;
-
- if (sp->worldcopy && wrld->nodetree && sp->worldcopy->nodetree) {
- ntreeLocalSync(sp->worldcopy->nodetree, wrld->nodetree);
- }
- }
- else if (GS(sp->id->name) == ID_LA) {
- Light *la = (Light *)sp->id;
-
- if (sp->lampcopy && la->nodetree && sp->lampcopy->nodetree) {
- ntreeLocalSync(sp->lampcopy->nodetree, la->nodetree);
- }
- }
- }
}
/* Renders texture directly to render buffer. */
@@ -1180,21 +1124,12 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
sce->r.scemode |= R_NO_IMAGE_LOAD;
sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
}
- else if (sp->pr_method == PR_NODE_RENDER) {
- if (idtype == ID_MA) {
- sce->r.scemode |= R_MATNODE_PREVIEW;
- }
- else if (idtype == ID_TE) {
- sce->r.scemode |= R_TEXNODE_PREVIEW;
- }
- sce->display.render_aa = SCE_DISPLAY_AA_OFF;
- }
else { /* PR_BUTS_RENDER */
sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8;
}
/* Callbacks are cleared on GetRender(). */
- if (ELEM(sp->pr_method, PR_BUTS_RENDER, PR_NODE_RENDER)) {
+ if (sp->pr_method == PR_BUTS_RENDER) {
RE_display_update_cb(re, sp, shader_preview_update);
}
/* set this for all previews, default is react to G.is_break still */
@@ -1302,10 +1237,6 @@ static void shader_preview_free(void *customdata)
main_id_copy = (ID *)sp->lampcopy;
BLI_remlink(&pr_main->lights, sp->lampcopy);
}
- if (main_id_copy || sp->id_copy) {
- /* node previews */
- shader_preview_updatejob(sp);
- }
if (sp->own_id_copy) {
if (sp->id_copy) {
preview_id_copy_free(sp->id_copy);
@@ -1658,9 +1589,12 @@ static void icon_preview_startjob_all_sizes(void *customdata,
if (ip->id != NULL) {
switch (GS(ip->id->name)) {
case ID_OB:
- /* Much simpler than the ShaderPreview mess used for other ID types. */
- object_preview_render(ip, cur_size);
- continue;
+ if (object_preview_is_type_supported((Object *)ip->id)) {
+ /* Much simpler than the ShaderPreview mess used for other ID types. */
+ object_preview_render(ip, cur_size);
+ continue;
+ }
+ break;
case ID_AC:
action_preview_render(ip, cur_size);
continue;
@@ -1749,6 +1683,18 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
+bool ED_preview_id_is_supported(const ID *id)
+{
+ if (id == NULL) {
+ return false;
+ }
+
+ if (GS(id->name) == ID_OB) {
+ return object_preview_is_type_supported((const Object *)id);
+ }
+ return BKE_previewimg_id_get_p(id) != NULL;
+}
+
void ED_preview_icon_render(
const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
{
@@ -1849,7 +1795,7 @@ void ED_preview_shader_job(const bContext *C,
wmJob *wm_job;
ShaderPreview *sp;
Scene *scene = CTX_data_scene(C);
- short id_type = GS(id->name);
+ const ID_Type id_type = GS(id->name);
BLI_assert(BKE_previewimg_id_supports_jobs(id));
@@ -1860,11 +1806,6 @@ void ED_preview_shader_job(const bContext *C,
return;
}
- /* Only texture node preview is supported with Cycles. */
- if (method == PR_NODE_RENDER && id_type != ID_TE) {
- return;
- }
-
ED_preview_ensure_dbase();
wm_job = WM_jobs_get(CTX_wm_manager(C),
@@ -1893,7 +1834,7 @@ void ED_preview_shader_job(const bContext *C,
* once with custom preview .blend path for external engines */
/* grease pencil use its own preview file */
- if (GS(id->name) == ID_MA) {
+ if (id_type == ID_MA) {
ma = (Material *)id;
}
@@ -1929,4 +1870,45 @@ void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
}
}
+typedef struct PreviewRestartQueueEntry {
+ struct PreviewRestartQueueEntry *next, *prev;
+
+ enum eIconSizes size;
+ ID *id;
+} PreviewRestartQueueEntry;
+
+static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
+
+void ED_preview_restart_queue_free(void)
+{
+ BLI_freelistN(&G_restart_previews_queue);
+}
+
+void ED_preview_restart_queue_add(ID *id, enum eIconSizes size)
+{
+ PreviewRestartQueueEntry *queue_entry = MEM_mallocN(sizeof(*queue_entry), __func__);
+ queue_entry->size = size;
+ queue_entry->id = id;
+ BLI_addtail(&G_restart_previews_queue, queue_entry);
+}
+
+void ED_preview_restart_queue_work(const bContext *C)
+{
+ LISTBASE_FOREACH_MUTABLE (PreviewRestartQueueEntry *, queue_entry, &G_restart_previews_queue) {
+ PreviewImage *preview = BKE_previewimg_id_get(queue_entry->id);
+ if (!preview) {
+ continue;
+ }
+ if (preview->flag[queue_entry->size] & PRV_USER_EDITED) {
+ /* Don't touch custom previews. */
+ continue;
+ }
+
+ BKE_previewimg_clear_single(preview, queue_entry->size);
+ UI_icon_render_id(C, NULL, queue_entry->id, queue_entry->size, true);
+
+ BLI_freelinkN(&G_restart_previews_queue, queue_entry);
+ }
+}
+
/** \} */
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index b6e6869f4e2..54ff25ede28 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -2226,10 +2226,10 @@ void SCENE_OT_freestyle_stroke_material_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-#endif /* WITH_FREESTYLE */
-
/** \} */
+#endif /* WITH_FREESTYLE */
+
/* -------------------------------------------------------------------- */
/** \name Texture Slot Move Operator
* \{ */
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 8bc2281db73..e975eab4736 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -68,7 +68,6 @@
/** \name Render Engines
* \{ */
-/* Update 3D viewport render or draw engine on changes to the scene or view settings. */
void ED_render_view3d_update(Depsgraph *depsgraph,
wmWindow *window,
ScrArea *area,
@@ -126,8 +125,6 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
}
}
-/* Update all 3D viewport render and draw engines on changes to the scene.
- * This is called by the dependency graph when it detects changes. */
void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool updated)
{
Main *bmain = update_ctx->bmain;
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 7f27b6f585a..9163718ffad 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -132,7 +132,6 @@ static ScrArea *find_area_image_empty(bContext *C)
/********************** open image editor for render *************************/
-/* new window uses x,y to set position */
ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 5195bc8303a..555ffbfd5e7 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -77,10 +77,6 @@ Scene *ED_scene_add(Main *bmain, bContext *C, wmWindow *win, eSceneCopyMethod me
return scene_new;
}
-/**
- * \note Only call outside of area/region loops
- * \return true if successful
- */
bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
{
Scene *scene_new;
@@ -113,7 +109,6 @@ bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
return true;
}
-/* Depsgraph updates after scene becomes active in a window. */
void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
{
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, layer);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 8523496bdbd..5dc6fe88663 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -140,7 +140,6 @@ void ED_region_pixelspace(const ARegion *region)
GPU_matrix_identity_set();
}
-/* only exported for WM */
void ED_region_do_listen(wmRegionListenerParams *params)
{
ARegion *region = params->region;
@@ -169,7 +168,6 @@ void ED_region_do_listen(wmRegionListenerParams *params)
}
}
-/* only exported for WM */
void ED_area_do_listen(wmSpaceTypeListenerParams *params)
{
/* no generic notes? */
@@ -178,7 +176,6 @@ void ED_area_do_listen(wmSpaceTypeListenerParams *params)
}
}
-/* only exported for WM */
void ED_area_do_refresh(bContext *C, ScrArea *area)
{
/* no generic notes? */
@@ -443,7 +440,6 @@ void ED_area_do_msg_notify_tag_refresh(
ED_area_tag_refresh(area);
}
-/* Follow ARegionType.message_subscribe */
void ED_area_do_mgs_subscribe_for_tool_header(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
@@ -507,7 +503,6 @@ static bool area_is_pseudo_minimized(const ScrArea *area)
return (area->winx < 3) || (area->winy < 3);
}
-/* only exported for WM */
void ED_region_do_layout(bContext *C, ARegion *region)
{
/* This is optional, only needed for dynamically sized regions. */
@@ -531,7 +526,6 @@ void ED_region_do_layout(bContext *C, ARegion *region)
region->flag &= ~RGN_FLAG_SEARCH_FILTER_UPDATE;
}
-/* only exported for WM */
void ED_region_do_draw(bContext *C, ARegion *region)
{
wmWindow *win = CTX_wm_window(C);
@@ -594,7 +588,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
memset(&region->drawrct, 0, sizeof(region->drawrct));
- UI_blocklist_free_inactive(C, &region->uiblocks);
+ UI_blocklist_free_inactive(C, region);
if (area) {
const bScreen *screen = WM_window_get_active_screen(win);
@@ -705,10 +699,6 @@ void ED_region_tag_refresh_ui(ARegion *region)
}
}
-/**
- * Tag editor overlays to be redrawn. If in doubt about which parts need to be redrawn (partial
- * clipping rectangle set), redraw everything.
- */
void ED_region_tag_redraw_editor_overlays(struct ARegion *region)
{
if (region && !(region->do_draw & (RGN_DRAWING | RGN_DRAW))) {
@@ -786,9 +776,6 @@ void ED_area_tag_refresh(ScrArea *area)
/* *************************************************************** */
-/**
- * Returns the search string if the space type and region type support property search.
- */
const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion *region)
{
/* Only the properties editor has a search string for now. */
@@ -802,9 +789,6 @@ const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion
return NULL;
}
-/**
- * Set the temporary update flag for property search.
- */
void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
{
region->flag |= RGN_FLAG_SEARCH_FILTER_UPDATE;
@@ -817,7 +801,6 @@ void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
/* *************************************************************** */
-/* use NULL to disable it */
void ED_area_status_text(ScrArea *area, const char *str)
{
/* happens when running transform operators in background mode */
@@ -1271,7 +1254,6 @@ static void region_overlap_fix(ScrArea *area, ARegion *region)
}
}
-/* overlapping regions only in the following restricted cases */
bool ED_region_is_overlap(int spacetype, int regiontype)
{
if (regiontype == RGN_TYPE_HUD) {
@@ -1926,7 +1908,6 @@ bool ED_area_has_shared_border(struct ScrArea *a, struct ScrArea *b)
return area_getorientation(a, b) != -1;
}
-/* called in screen_refresh, or screens_init, also area size changes */
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
{
WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -1985,7 +1966,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
}
else {
/* prevent uiblocks to run */
- UI_blocklist_free(NULL, &region->uiblocks);
+ UI_blocklist_free(NULL, region);
}
/* Some AZones use View2D data which is only updated in region init, so call that first! */
@@ -2076,15 +2057,11 @@ static void region_update_rect(ARegion *region)
BLI_rcti_init(&region->v2d.mask, 0, region->winx - 1, 0, region->winy - 1);
}
-/**
- * Call to move a popup window (keep OpenGL context free!)
- */
void ED_region_update_rect(ARegion *region)
{
region_update_rect(region);
}
-/* externally called for floating regions like menus */
void ED_region_floating_init(ARegion *region)
{
BLI_assert(region->alignment == RGN_ALIGN_FLOAT);
@@ -2114,18 +2091,22 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *area, ARegion *region)
WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
-/* for use after changing visibility of regions */
void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
{
if (region->flag & RGN_FLAG_HIDDEN) {
WM_event_remove_handlers(C, &region->handlers);
+ /* Needed to close any open pop-overs which would otherwise remain open,
+ * crashing on attempting to refresh. See: T93410.
+ *
+ * When #ED_area_init frees buttons via #UI_blocklist_free a NULL context
+ * is passed, causing the free not to remove menus or their handlers. */
+ UI_region_free_active_but_all(C, region);
}
ED_area_init(CTX_wm_manager(C), CTX_wm_window(C), area);
ED_area_tag_redraw(area);
}
-/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
{
ScrArea *area = CTX_wm_area(C);
@@ -2141,15 +2122,11 @@ void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
}
}
-/* exported to all editors, uses fading default */
void ED_region_toggle_hidden(bContext *C, ARegion *region)
{
region_toggle_hidden(C, region, true);
}
-/**
- * we swap spaces for fullscreen to keep all allocated data area vertices were set
- */
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
{
const char spacetype = area_dst->spacetype;
@@ -2455,9 +2432,6 @@ void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
ED_area_tag_refresh(sa2);
}
-/**
- * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
- */
void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_region_exit)
{
wmWindow *win = CTX_wm_window(C);
@@ -2622,7 +2596,6 @@ void ED_area_prevspace(bContext *C, ScrArea *area)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, area);
}
-/* returns offset for next button in header */
int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
{
ScrArea *area = CTX_wm_area(C);
@@ -2934,11 +2907,16 @@ static const char *region_panels_collect_categories(ARegion *region,
return NULL;
}
-/**
- * \param contexts: A NULL terminated array of context strings to match against.
- * Matching against any of these strings will draw the panel.
- * Can be NULL to skip context checks.
- */
+static int panel_draw_width_from_max_width_get(const ARegion *region,
+ const PanelType *panel_type,
+ const int max_width)
+{
+ /* With a background, we want some extra padding. */
+ return UI_panel_should_show_background(region, panel_type) ?
+ max_width - UI_PANEL_MARGIN_X * 2.0f :
+ max_width;
+}
+
void ED_region_panels_layout_ex(const bContext *C,
ARegion *region,
ListBase *paneltypes,
@@ -2982,7 +2960,6 @@ void ED_region_panels_layout_ex(const bContext *C,
}
const int width_no_header = BLI_rctf_size_x(&v2d->cur) - margin_x;
- const int width = width_no_header - UI_PANEL_MARGIN_X * 2.0f;
/* Works out to 10 * UI_UNIT_X or 20 * UI_UNIT_X. */
const int em = (region->type->prefsizex) ? 10 : 20;
@@ -3010,6 +2987,7 @@ void ED_region_panels_layout_ex(const bContext *C,
continue;
}
}
+ const int width = panel_draw_width_from_max_width_get(region, pt, width_no_header);
if (panel && UI_panel_is_dragging(panel)) {
/* Prevent View2d.tot rectangle size changes while dragging panels. */
@@ -3040,6 +3018,7 @@ void ED_region_panels_layout_ex(const bContext *C,
!STREQ(category, panel->type->category)) {
continue;
}
+ const int width = panel_draw_width_from_max_width_get(region, panel->type, width_no_header);
if (panel && UI_panel_is_dragging(panel)) {
/* Prevent View2d.tot rectangle size changes while dragging panels. */
@@ -3249,10 +3228,6 @@ static bool panel_property_search(const bContext *C,
return false;
}
-/**
- * Build the same panel list as #ED_region_panels_layout_ex and checks whether any
- * of the panels contain a search result based on the area / region's search filter.
- */
bool ED_region_property_search(const bContext *C,
ARegion *region,
ListBase *paneltypes,
@@ -3323,7 +3298,7 @@ bool ED_region_property_search(const bContext *C,
}
/* Free the panels and blocks, as they are only used for search. */
- UI_blocklist_free(C, &region->uiblocks);
+ UI_blocklist_free(C, region);
UI_panels_free_instanced(C, region);
BKE_area_region_panels_free(&region->panels);
@@ -3458,9 +3433,6 @@ int ED_area_footersize(void)
return ED_area_headersize();
}
-/**
- * \return the final height of a global \a area, accounting for DPI.
- */
int ED_area_global_size_y(const ScrArea *area)
{
BLI_assert(ED_area_is_global(area));
@@ -3510,12 +3482,6 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area)
return screen->areabase.first;
}
-/**
- * For now we just assume all global areas are made up out of horizontal bars
- * with the same size. A fixed size could be stored in ARegion instead if needed.
- *
- * \return the DPI aware height of a single bar/region in global areas.
- */
int ED_region_global_size_y(void)
{
return ED_area_headersize(); /* same size as header */
@@ -3841,9 +3807,6 @@ void ED_region_cache_draw_cached_segments(
}
}
-/**
- * Generate subscriptions for this region.
- */
void ED_region_message_subscribe(wmRegionMessageSubscribeParams *params)
{
ARegion *region = params->region;
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 30e744ca174..022f8620b0b 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -140,10 +140,6 @@ bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
ED_region_overlap_isect_y_with_margin(region, event_xy[1], margin));
}
-/**
- * \note: This may return true for multiple overlapping regions. If it matters, check overlapped
- * regions first (#ARegion.overlap).
- */
bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
{
/* Only use the margin when inside the region. */
@@ -193,13 +189,6 @@ bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
return false;
}
-/**
- * Similar to #BKE_area_find_region_xy() but when \a event_xy intersects an overlapping region,
- * this returns the region that is visually under the cursor. E.g. when over the
- * transparent part of the region, it returns the region underneath.
- *
- * The overlapping region is determined using the #ED_region_contains_xy() query.
- */
ARegion *ED_area_find_region_xy_visual(const ScrArea *area,
const int regiontype,
const int event_xy[2])
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 30553bb7f07..9a688ac0b05 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -40,9 +40,6 @@
/** \name Generic Tool System Region Callbacks
* \{ */
-/**
- * Callback for #ARegionType.message_subscribe
- */
void ED_region_generic_tools_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
@@ -56,9 +53,6 @@ void ED_region_generic_tools_region_message_subscribe(const wmRegionMessageSubsc
WM_msg_subscribe_rna_anon_prop(mbus, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
}
-/**
- * Callback for #ARegionType.snap_size
- */
int ED_region_generic_tools_region_snap_size(const ARegion *region, int size, int axis)
{
if (axis == 0) {
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index f651fd4fb61..5f523df18d1 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -57,12 +57,6 @@ static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state)
vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
-/**
- * To be used before calling #immDrawPixelsTex
- * Default shader is #GPU_SHADER_2D_IMAGE_COLOR
- * You can still set uniforms with:
- * `GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);`
- */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
{
IMMDrawPixelsTexState state;
@@ -78,20 +72,6 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
return state;
}
-/**
- * Use the currently bound shader.
- *
- * Use #immDrawPixelsTexSetup to bind the shader you
- * want before calling #immDrawPixelsTex.
- *
- * If using a special shader double check it uses the same
- * attributes "pos" "texCoord" and uniform "image".
- *
- * If color is NULL then use white by default
- *
- * Be also aware that this function unbinds the shader when
- * it's finished.
- */
void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float x,
float y,
@@ -363,7 +343,6 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
/* **** Color management helper functions for GLSL display/transform ***** */
-/* Draw given image buffer on a screen using GLSL for display transform */
void ED_draw_imbuf_clipping(ImBuf *ibuf,
float x,
float y,
@@ -577,8 +556,6 @@ int ED_draw_imbuf_method(ImBuf *ibuf)
return U.image_draw_method;
}
-/* don't move to GPU_immediate_util.h because this uses user-prefs
- * and isn't very low level */
void immDrawBorderCorners(uint pos, const rcti *border, float zoomx, float zoomy)
{
float delta_x = 4.0f * UI_DPI_FAC / zoomx;
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index a8c63027254..304205d0cc4 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -113,6 +113,8 @@ const char *screen_context_dir[] = {
"active_gpencil_frame",
"active_annotation_layer",
"active_operator",
+ "selected_visible_actions",
+ "selected_editable_actions",
"visible_fcurves",
"editable_fcurves",
"selected_visible_fcurves",
@@ -975,6 +977,90 @@ static eContextResult screen_ctx_active_operator(const bContext *C, bContextData
}
return CTX_RESULT_NO_DATA;
}
+static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
+ bContextDataResult *result,
+ bool editable)
+{
+ bAnimContext ac;
+ if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_GRAPH)) {
+ /* In the Action and Shape Key editor always use the action field at the top. */
+ if (ac.spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)ac.sl;
+
+ if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY)) {
+ if (saction->action && !(editable && ID_IS_LINKED(saction->action))) {
+ CTX_data_id_list_add(result, &saction->action->id);
+ }
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+ }
+ }
+
+ /* Search for selected animation data items. */
+ ListBase anim_data = {NULL, NULL};
+
+ int filter = ANIMFILTER_DATA_VISIBLE;
+ bool check_selected = false;
+
+ switch (ac.spacetype) {
+ case SPACE_GRAPH:
+ filter |= ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL;
+ break;
+
+ case SPACE_ACTION:
+ filter |= ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
+ check_selected = true;
+ break;
+ }
+
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ GSet *seen_set = BLI_gset_ptr_new("seen actions");
+
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ /* In dopesheet check selection status of individual items, skipping
+ * if not selected or has no selection flag. This is needed so that
+ * selecting action or group rows without any channels works. */
+ if (check_selected && ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_SELECT) <= 0) {
+ continue;
+ }
+
+ bAction *action = ANIM_channel_action_get(ale);
+
+ if (action) {
+ if (editable && ID_IS_LINKED(action)) {
+ continue;
+ }
+
+ /* Add the action to the output list if not already added. */
+ if (!BLI_gset_haskey(seen_set, action)) {
+ CTX_data_id_list_add(result, &action->id);
+ BLI_gset_add(seen_set, action);
+ }
+ }
+ }
+
+ BLI_gset_free(seen_set, NULL);
+
+ ANIM_animdata_freelist(&anim_data);
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return CTX_RESULT_OK;
+ }
+ return CTX_RESULT_NO_DATA;
+}
+
+static eContextResult screen_ctx_selected_visible_actions(const bContext *C,
+ bContextDataResult *result)
+{
+ return screen_ctx_sel_actions_impl(C, result, false);
+}
+static eContextResult screen_ctx_selected_editable_actions(const bContext *C,
+ bContextDataResult *result)
+{
+ return screen_ctx_sel_actions_impl(C, result, true);
+}
static eContextResult screen_ctx_sel_edit_fcurves_(const bContext *C,
bContextDataResult *result,
const int extra_filter)
@@ -1185,6 +1271,8 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("editable_gpencil_layers", screen_ctx_editable_gpencil_layers);
register_context_function("editable_gpencil_strokes", screen_ctx_editable_gpencil_strokes);
register_context_function("active_operator", screen_ctx_active_operator);
+ register_context_function("selected_visible_actions", screen_ctx_selected_visible_actions);
+ register_context_function("selected_editable_actions", screen_ctx_selected_editable_actions);
register_context_function("editable_fcurves", screen_ctx_editable_fcurves);
register_context_function("visible_fcurves", screen_ctx_visible_fcurves);
register_context_function("selected_editable_fcurves", screen_ctx_selected_editable_fcurves);
@@ -1195,7 +1283,6 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("ui_list", screen_ctx_ui_list);
}
-/* Entry point for the screen context. */
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
{
if (CTX_data_dir(member)) {
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index ab50e327de3..e720ae4b9d8 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -162,9 +162,6 @@ static void drawscredge_area(ScrArea *area, int sizex, int sizey, float edge_thi
drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, edge_thickness);
}
-/**
- * Only for edge lines between areas.
- */
void ED_screen_draw_edges(wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -231,12 +228,6 @@ void ED_screen_draw_edges(wmWindow *win)
}
}
-/**
- * Visual indication of the two areas involved in a proposed join.
- *
- * \param sa1: Area from which the resultant originates.
- * \param sa2: Target area that will be replaced.
- */
void screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2)
{
const eScreenDir dir = area_getorientation(sa1, sa2);
@@ -445,9 +436,6 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
GPU_matrix_pop();
}
-/**
- * Render the preview for a screen layout in \a screen.
- */
void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uint *r_rect)
{
char err_out[256] = "unknown";
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index fa0cfd16817..5a2b53163b8 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -203,9 +203,6 @@ ScrArea *area_split(const wmWindow *win,
return newa;
}
-/**
- * Empty screen, with 1 dummy area without spacedata. Uses window size.
- */
bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
{
bScreen *screen = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
@@ -274,9 +271,6 @@ void screen_data_copy(bScreen *to, bScreen *from)
}
}
-/**
- * Prepare a newly created screen for initializing it as active screen.
- */
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
{
screen_new->winid = win->winid;
@@ -284,11 +278,6 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
screen_new->do_draw = true;
}
-/**
- * with `sa_a` as center, `sa_b` is located at: 0=W, 1=N, 2=E, 3=S
- * -1 = not valid check.
- * used with join operator.
- */
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
{
if (sa_a == NULL || sa_b == NULL || sa_a == sa_b) {
@@ -329,9 +318,6 @@ eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
return -1;
}
-/**
- * Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation().
- */
void area_getoffsets(
ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2)
{
@@ -536,13 +522,11 @@ static bool screen_area_join_ex(
return true;
}
-/* Join any two neighboring areas. Might involve complex changes. */
int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
{
return screen_area_join_ex(C, screen, sa1, sa2, false);
}
-/* Close a screen area, allowing most-aligned neighbor to take its place. */
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
{
if (area == NULL) {
@@ -640,8 +624,6 @@ void ED_screen_do_listen(bContext *C, wmNotifier *note)
}
}
-/* make this screen usable */
-/* for file read and first use, for scaling window, area moves */
void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -681,7 +663,6 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen->context = ed_screen_context;
}
-/* file read, set all screens, ... */
void ED_screens_init(Main *bmain, wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -709,10 +690,6 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree
}
}
-/**
- * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
- * slightly differently, see #ui_region_temp_remove().
- */
void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
{
ED_region_exit(C, region);
@@ -862,10 +839,6 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
}
}
-/**
- * Called in wm_event_system.c. sets state vars in screen, cursors.
- * event type is mouse move.
- */
void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -955,7 +928,7 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
* because it can undo setting the right button as active due
* to delayed notifier handling. */
if (C) {
- UI_screen_free_active_but(C, screen);
+ UI_screen_free_active_but_highlight(C, screen);
}
}
}
@@ -1126,10 +1099,6 @@ void ED_screen_global_areas_refresh(wmWindow *win)
/* -------------------------------------------------------------------- */
/* Screen changing */
-/**
- * \return the screen to activate.
- * \warning The returned screen may not always equal \a screen_new!
- */
void screen_change_prepare(
bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
{
@@ -1176,14 +1145,6 @@ void screen_change_update(bContext *C, wmWindow *win, bScreen *screen)
WM_event_add_mousemove(win);
}
-/**
- * \brief Change the active screen.
- *
- * Operator call, WM + Window + screen already existed before
- *
- * \warning Do NOT call in area/region queues!
- * \returns if screen changing was successful.
- */
bool ED_screen_change(bContext *C, bScreen *screen)
{
Main *bmain = CTX_data_main(C);
@@ -1324,9 +1285,6 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
return newsa;
}
-/**
- * \a was_prev_temp for the case previous space was a temporary fullscreen as well
- */
void ED_screen_full_prevspace(bContext *C, ScrArea *area)
{
BLI_assert(area->full);
@@ -1356,7 +1314,6 @@ void ED_screen_restore_temp_type(bContext *C, ScrArea *area)
}
}
-/* restore a screen / area back to default operation, after temp fullscreen modes */
void ED_screen_full_restore(bContext *C, ScrArea *area)
{
wmWindow *win = CTX_wm_window(C);
@@ -1463,28 +1420,11 @@ static bScreen *screen_state_to_nonnormal(bContext *C,
return screen;
}
-/**
- * Create a new temporary screen with a maximized, empty area.
- * This can be closed with #ED_screen_state_toggle().
- *
- * Use this to just create a new maximized screen/area, rather than maximizing an existing one.
- * Otherwise, maximize with #ED_screen_state_toggle().
- */
bScreen *ED_screen_state_maximized_create(bContext *C)
{
return screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED);
}
-/**
- * This function toggles: if area is maximized/full then the parent will be restored.
- *
- * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to
- * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a
- * specific area. In the former case, space data of the maximized and non-maximized area should be
- * independent, in the latter it should be the same.
- *
- * \warning \a area may be freed.
- */
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1495,8 +1435,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
* switching screens with tooltip open because region and tooltip
* are no longer in the same screen */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- UI_blocklist_free(C, &region->uiblocks);
-
+ UI_blocklist_free(C, region);
if (region->regiontimer) {
WM_event_remove_timer(wm, NULL, region->regiontimer);
region->regiontimer = NULL;
@@ -1593,14 +1532,6 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
return screen->areabase.first;
}
-/**
- * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
- * by \a display_type.
- *
- * \param title: Title to set for the window, if a window is spawned.
- * \param x, y: Position of the window, if a window is spawned.
- * \param sizex, sizey: Dimensions of the window, if a window is spawned.
- */
ScrArea *ED_screen_temp_space_open(bContext *C,
const char *title,
int x,
@@ -1649,7 +1580,6 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
return area;
}
-/* update frame rate info for viewport drawing */
void ED_refresh_viewport_fps(bContext *C)
{
wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
@@ -1675,9 +1605,6 @@ void ED_refresh_viewport_fps(bContext *C)
}
}
-/* redraws: uses defines from stime->redraws
- * enable: 1 - forward on, -1 - backwards on, 0 - off
- */
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1777,7 +1704,6 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws)
}
}
-/* results in fully updated anim system */
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
{
Scene *scene = DEG_get_input_scene(depsgraph);
@@ -1802,9 +1728,6 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
BKE_scene_graph_update_for_newframe(depsgraph);
}
-/*
- * return true if any active area requires to see in 3D
- */
bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
{
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
@@ -1880,11 +1803,6 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
return false;
}
-/**
- * Find the scene displayed in \a screen.
- * \note Assumes \a screen to be visible/active!
- */
-
Scene *ED_screen_scene_find_with_window(const bScreen *screen,
const wmWindowManager *wm,
struct wmWindow **r_window)
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index e67c933cb8e..394a7fd7350 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -83,10 +83,6 @@ bool screen_geom_edge_is_horizontal(ScrEdge *se)
return (se->v1->vec.y == se->v2->vec.y);
}
-/**
- * \param bounds_rect: Either window or screen bounds.
- * Used to exclude edges along window/screen edges.
- */
ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
const rcti *bounds_rect,
const int mx,
@@ -124,7 +120,6 @@ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
return NULL;
}
-/* need win size to make sure not to include edges along screen edge */
ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
const int mx,
@@ -249,13 +244,6 @@ static bool screen_geom_vertices_scale_pass(const wmWindow *win,
return needs_another_pass;
}
-/**
- * \brief Main screen-layout calculation function.
- *
- * * Scale areas nicely on window size and DPI changes.
- * * Ensure areas have a minimum height.
- * * Correctly set global areas to their fixed height.
- */
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
{
rcti window_rect, screen_rect;
@@ -303,9 +291,6 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
}
}
-/**
- * \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
- */
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
const eScreenAxis dir_axis,
@@ -374,9 +359,6 @@ short screen_geom_find_area_split_point(const ScrArea *area,
return x;
}
-/**
- * Select all edges that are directly or indirectly connected to \a edge.
- */
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
{
bScreen *screen = WM_window_get_active_screen(win);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 47229e5e2b5..bc06e46ba96 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -61,23 +61,48 @@ typedef enum eScreenAxis {
#define AREAJOINTOLERANCEX (AREAMINX * U.dpi_fac)
#define AREAJOINTOLERANCEY (HEADERY * U.dpi_fac)
-/* Expanded interaction influence of area borders. */
+/**
+ * Expanded interaction influence of area borders.
+ */
#define BORDERPADDING ((2.0f * U.dpi_fac) + U.pixelsize)
/* area.c */
+
+/**
+ * we swap spaces for fullscreen to keep all allocated data area vertices were set
+ */
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free);
void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src);
+/* for quick toggle, can skip fades */
void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade);
/* screen_draw.c */
+
+/**
+ * Visual indication of the two areas involved in a proposed join.
+ *
+ * \param sa1: Area from which the resultant originates.
+ * \param sa2: Target area that will be replaced.
+ */
void screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2);
void screen_draw_split_preview(struct ScrArea *area, const eScreenAxis dir_axis, const float fac);
/* screen_edit.c */
+
+/**
+ * Empty screen, with 1 dummy area without space-data. Uses window size.
+ */
bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
void screen_data_copy(bScreen *to, bScreen *from);
+/**
+ * Prepare a newly created screen for initializing it as active screen.
+ */
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
void screen_change_update(struct bContext *C, wmWindow *win, bScreen *screen);
+/**
+ * \return the screen to activate.
+ * \warning The returned screen may not always equal \a screen_new!
+ */
void screen_change_prepare(bScreen *screen_old,
bScreen *screen_new,
struct Main *bmain,
@@ -89,10 +114,24 @@ ScrArea *area_split(const wmWindow *win,
const eScreenAxis dir_axis,
const float fac,
const bool merge);
+/**
+ * Join any two neighboring areas. Might involve complex changes.
+ */
int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2);
+/**
+ * with `sa_a` as center, `sa_b` is located at: 0=W, 1=N, 2=E, 3=S
+ * -1 = not valid check.
+ * used with join operator.
+ */
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b);
+/**
+ * Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation().
+ */
void area_getoffsets(
ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2);
+/**
+ * Close a screen area, allowing most-aligned neighbor to take its place.
+ */
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area);
void screen_area_spacelink_add(struct Scene *scene, ScrArea *area, eSpace_Type space_type);
struct AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2]);
@@ -105,22 +144,46 @@ ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y);
ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2);
ScrEdge *screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2);
bool screen_geom_edge_is_horizontal(ScrEdge *se);
+/**
+ * \param bounds_rect: Either window or screen bounds.
+ * Used to exclude edges along window/screen edges.
+ */
ScrEdge *screen_geom_area_map_find_active_scredge(const struct ScrAreaMap *area_map,
const rcti *bounds_rect,
const int mx,
const int my);
+/**
+ * Need win size to make sure not to include edges along screen edge.
+ */
ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
const int mx,
const int my);
+/**
+ * \brief Main screen-layout calculation function.
+ *
+ * * Scale areas nicely on window size and DPI changes.
+ * * Ensure areas have a minimum height.
+ * * Correctly set global areas to their fixed height.
+ */
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen);
+/**
+ * \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
+ */
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
const eScreenAxis dir_axis,
float fac);
+/**
+ * Select all edges that are directly or indirectly connected to \a edge.
+ */
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge);
/* screen_context.c */
+
+/**
+ * Entry point for the screen context.
+ */
int ed_screen_context(const struct bContext *C,
const char *member,
struct bContextDataResult *result);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 66140cba9c6..d017345b523 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -165,7 +165,6 @@ static bool ED_operator_screenactive_norender(bContext *C)
return true;
}
-/* when mouse is over area-edge */
bool ED_operator_screen_mainwinactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
@@ -219,10 +218,6 @@ bool ED_operator_objectmode(bContext *C)
return true;
}
-/**
- * Same as #ED_operator_objectmode() but additionally sets a "disabled hint". That is, a message
- * to be displayed to the user explaining why the operator can't be used in current context.
- */
bool ED_operator_objectmode_poll_msg(bContext *C)
{
if (!ED_operator_objectmode(C)) {
@@ -257,7 +252,6 @@ bool ED_operator_region_view3d_active(bContext *C)
return false;
}
-/* generic for any view2d which uses anim_ops */
bool ED_operator_animview_active(bContext *C)
{
if (ED_operator_areaactive(C)) {
@@ -289,21 +283,11 @@ bool ED_operator_outliner_active_no_editobject(bContext *C)
return false;
}
-/**
- * \note Will return true for file spaces in either file or asset browsing mode! See
- * #ED_operator_file_browsing_active() (file browsing only) and
- * #ED_operator_asset_browsing_active() (asset browsing only).
- */
bool ED_operator_file_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_FILE);
}
-/**
- * \note Will only return true if the file space is in file browsing mode, not asset browsing! See
- * #ED_operator_file_active() (file or asset browsing) and
- * #ED_operator_asset_browsing_active() (asset browsing only).
- */
bool ED_operator_file_browsing_active(bContext *C)
{
if (ed_spacetype_test(C, SPACE_FILE)) {
@@ -430,7 +414,6 @@ bool ED_operator_object_active_editable(bContext *C)
return ED_operator_object_active_editable_ex(C, ob);
}
-/** Object must be editable and fully local (i.e. not an override). */
bool ED_operator_object_active_local_editable_ex(bContext *C, const Object *ob)
{
return ED_operator_object_active_editable_ex(C, ob) && !ID_IS_OVERRIDE_LIBRARY(ob);
@@ -530,7 +513,6 @@ bool ED_operator_posemode_exclusive(bContext *C)
return ed_operator_posemode_exclusive_ex(C, obact);
}
-/** Object must be editable, fully local (i.e. not an override), and exclusively in Pose mode. */
bool ED_operator_object_active_local_editable_posemode_exclusive(bContext *C)
{
Object *obact = ED_object_active_context(C);
@@ -547,8 +529,6 @@ bool ED_operator_object_active_local_editable_posemode_exclusive(bContext *C)
return true;
}
-/* allows for pinned pose objects to be used in the object buttons
- * and the non-active pose object to be used in the 3D view */
bool ED_operator_posemode_context(bContext *C)
{
Object *obpose = ED_pose_object_from_context(C);
@@ -588,7 +568,6 @@ bool ED_operator_posemode_local(bContext *C)
return false;
}
-/* wrapper for ED_space_image_show_uvedit */
bool ED_operator_uvedit(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -4426,6 +4405,7 @@ static void SCREEN_OT_region_context_menu(wmOperatorType *ot)
*
* Animation Step.
* \{ */
+
static bool screen_animation_region_supports_time_follow(eSpace_Type spacetype,
eRegion_Type regiontype)
{
@@ -4812,7 +4792,6 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
* Animation Playback with Timer.
* \{ */
-/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -4839,7 +4818,6 @@ bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
return NULL;
}
-/* toggle operator */
int ED_screen_animation_play(bContext *C, int sync, int mode)
{
bScreen *screen = CTX_wm_screen(C);
@@ -5391,9 +5369,6 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
WM_event_remove_timer(CTX_wm_manager(C), NULL, region->regiontimer); /* frees rgi */
region->regiontimer = NULL;
}
-/**
- * \note Assumes that \a region itself is not a split version from previous region.
- */
void ED_region_visibility_change_update_animated(bContext *C, ScrArea *area, ARegion *region)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -5701,7 +5676,6 @@ static void SCREEN_OT_workspace_cycle(wmOperatorType *ot)
/** \name Assigning Operator Types
* \{ */
-/* called in spacetypes.c */
void ED_operatortypes_screen(void)
{
/* Generic UI stuff. */
@@ -5778,7 +5752,7 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
static bool blend_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH) {
- if (drag->icon == ICON_FILE_BLEND) {
+ if (ELEM(drag->icon, ICON_FILE_BLEND, ICON_BLENDER)) {
return true;
}
}
@@ -5791,7 +5765,6 @@ static void blend_file_drop_copy(wmDrag *drag, wmDropBox *drop)
RNA_string_set(drop->ptr, "filepath", drag->path);
}
-/* called in spacetypes.c */
void ED_keymap_screen(wmKeyConfig *keyconf)
{
/* Screen Editing ------------------------------------------------ */
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 5c4ba67d72a..b26291c4d1b 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -180,8 +180,9 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* extension is added by 'screenshot_check' after */
char filepath[FILE_MAX] = "//screen";
- if (G.relbase_valid) {
- BLI_strncpy(filepath, BKE_main_blendfile_path_from_global(), sizeof(filepath));
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') {
+ BLI_strncpy(filepath, blendfile_path, sizeof(filepath));
BLI_path_extension_replace(filepath, sizeof(filepath), ""); /* strip '.blend' */
}
RNA_string_set(op->ptr, "filepath", filepath);
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 4b81e713080..125b345a1ed 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -112,15 +112,6 @@ static WorkSpaceLayout *workspace_change_get_new_layout(Main *bmain,
bmain, workspace_new, layout_new, layout_old, win);
}
-/**
- * \brief Change the active workspace.
- *
- * Operator call, WM + Window + screen already existed before
- * Pretty similar to #ED_screen_change since changing workspace also changes screen.
- *
- * \warning Do NOT call in area/region queues!
- * \returns if workspace changing was successful.
- */
bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager *wm, wmWindow *win)
{
Main *bmain = CTX_data_main(C);
@@ -160,10 +151,6 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
return true;
}
-/**
- * Duplicate a workspace including its layouts. Does not activate the workspace, but
- * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
- */
WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win)
{
WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
@@ -187,9 +174,6 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo
return workspace_new;
}
-/**
- * \return if succeeded.
- */
bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm)
{
if (BLI_listbase_is_single(&bmain->workspaces)) {
@@ -220,10 +204,6 @@ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindo
return true;
}
-/**
- * Some editor data may need to be synced with scene data (3D View camera and layers).
- * This function ensures data is synced for editors in active layout of \a workspace.
- */
void ED_workspace_scene_data_sync(WorkSpaceInstanceHook *hook, Scene *scene)
{
bScreen *screen = BKE_workspace_active_screen_get(hook);
@@ -393,7 +373,7 @@ static void workspace_append_button(uiLayout *layout,
const Main *from_main)
{
const ID *id = (ID *)workspace;
- const char *filepath = from_main->name;
+ const char *filepath = from_main->filepath;
if (strlen(filepath) == 0) {
filepath = BLO_EMBEDDED_STARTUP_BLEND;
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
index 0ec32da0404..e34c4f96aa3 100644
--- a/source/blender/editors/screen/workspace_layout_edit.c
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -37,9 +37,6 @@
#include "screen_intern.h"
-/**
- * Empty screen, with 1 dummy area without space-data. Uses window size.
- */
WorkSpaceLayout *ED_workspace_layout_add(Main *bmain,
WorkSpace *workspace,
wmWindow *win,
@@ -129,10 +126,6 @@ static WorkSpaceLayout *workspace_layout_delete_find_new(const WorkSpaceLayout *
return NULL;
}
-/**
- * \warning Only call outside of area/region loops!
- * \return true if succeeded.
- */
bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_old, bContext *C)
{
const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
@@ -183,12 +176,6 @@ static bool screen_is_used_by_other_window(const wmWindow *win, const bScreen *s
return BKE_screen_is_used(screen) && (screen->winid != win->winid);
}
-/**
- * Make sure there is a non-fullscreen layout to switch to that is not used yet by an other window.
- * Needed for workspace or screen switching to ensure valid screens.
- *
- * \param layout_fallback_base: As last resort, this layout is duplicated and returned.
- */
WorkSpaceLayout *ED_workspace_screen_change_ensure_unused_layout(
Main *bmain,
WorkSpace *workspace,
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 3b668a1bd4c..b826ff8701d 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
paint_hide.c
paint_image.c
paint_image_2d.c
+ paint_image_2d_curve_mask.cc
paint_image_proj.c
paint_mask.c
paint_ops.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index dafc7f45e2e..265746e27cd 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -98,7 +98,6 @@ static TexSnapshot primary_snap = {0};
static TexSnapshot secondary_snap = {0};
static CursorSnapshot cursor_snap = {0};
-/* Delete overlay cursor textures to preserve memory and invalidate all overlay flags. */
void paint_cursor_delete_textures(void)
{
if (primary_snap.overlay_texture) {
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index dbe522bf304..0b59e519f70 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -147,7 +147,6 @@ static void paintcurve_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->pc_ref));
}
-/* Export for ED_undo_sys. */
void ED_paintcurve_undosys_type(UndoType *ut)
{
ut->name = "Paint Curve";
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 6ba5c43f698..dc2eaacca0c 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -87,7 +87,7 @@
* Maybe it should be exposed as part of the paint operation,
* but for now just give a public interface.
*/
-static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+static ImagePaintPartialRedraw imapaintpartial = {{0}};
ImagePaintPartialRedraw *get_imapaintpartial(void)
{
@@ -103,7 +103,7 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
void ED_imapaint_clear_partial_redraw(void)
{
- memset(&imapaintpartial, 0, sizeof(imapaintpartial));
+ BLI_rcti_init_minmax(&imapaintpartial.dirty_region);
}
void imapaint_region_tiles(
@@ -132,19 +132,9 @@ void ED_imapaint_dirty_region(
return;
}
- if (!imapaintpartial.enabled) {
- imapaintpartial.x1 = x;
- imapaintpartial.y1 = y;
- imapaintpartial.x2 = x + w;
- imapaintpartial.y2 = y + h;
- imapaintpartial.enabled = 1;
- }
- else {
- imapaintpartial.x1 = min_ii(imapaintpartial.x1, x);
- imapaintpartial.y1 = min_ii(imapaintpartial.y1, y);
- imapaintpartial.x2 = max_ii(imapaintpartial.x2, x + w);
- imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
- }
+ rcti rect_to_merge;
+ BLI_rcti_init(&rect_to_merge, x, x + w, y, y + h);
+ BLI_rcti_do_minmax_rcti(&imapaintpartial.dirty_region, &rect_to_merge);
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
@@ -167,27 +157,30 @@ void ED_imapaint_dirty_region(
void imapaint_image_update(
SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
{
- if (imapaintpartial.x1 != imapaintpartial.x2 && imapaintpartial.y1 != imapaintpartial.y2) {
- IMB_partial_display_buffer_update_delayed(
- ibuf, imapaintpartial.x1, imapaintpartial.y1, imapaintpartial.x2, imapaintpartial.y2);
+ if (BLI_rcti_is_empty(&imapaintpartial.dirty_region)) {
+ return;
}
if (ibuf->mipmap[0]) {
ibuf->userflags |= IB_MIPMAP_INVALID;
}
+ IMB_partial_display_buffer_update_delayed(ibuf,
+ imapaintpartial.dirty_region.xmin,
+ imapaintpartial.dirty_region.ymin,
+ imapaintpartial.dirty_region.xmax,
+ imapaintpartial.dirty_region.ymax);
+
/* TODO: should set_tpage create ->rect? */
if (texpaint || (sima && sima->lock)) {
- int w = imapaintpartial.x2 - imapaintpartial.x1;
- int h = imapaintpartial.y2 - imapaintpartial.y1;
- if (w && h) {
- /* Testing with partial update in uv editor too */
- BKE_image_update_gputexture(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
- }
+ const int w = BLI_rcti_size_x(&imapaintpartial.dirty_region);
+ const int h = BLI_rcti_size_y(&imapaintpartial.dirty_region);
+ /* Testing with partial update in uv editor too */
+ BKE_image_update_gputexture(
+ image, iuser, imapaintpartial.dirty_region.xmin, imapaintpartial.dirty_region.ymin, w, h);
}
}
-/* paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging */
BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
{
int i, j;
@@ -799,11 +792,6 @@ static void toggle_paint_cursor(Scene *scene, bool enable)
}
}
-/* enable the paint cursor if it isn't already.
- *
- * purpose is to make sure the paint cursor is shown if paint
- * mode is enabled in the image editor. the paint poll will
- * ensure that the cursor is hidden when not in paint mode */
void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
{
ToolSettings *settings = scene->toolsettings;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 318180e5eb4..4c54d3b3b5e 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -78,12 +78,13 @@ typedef struct BrushPainterCache {
ImBuf *ibuf;
ImBuf *texibuf;
- ushort *curve_mask;
ushort *tex_mask;
ushort *tex_mask_old;
uint tex_mask_old_w;
uint tex_mask_old_h;
+ CurveMaskCache curve_mask_cache;
+
int image_size[2];
} BrushPainterCache;
@@ -169,9 +170,6 @@ static void brush_painter_2d_require_imbuf(
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
}
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- }
if (cache->tex_mask) {
MEM_freeN(cache->tex_mask);
}
@@ -179,7 +177,6 @@ static void brush_painter_2d_require_imbuf(
MEM_freeN(cache->tex_mask_old);
}
cache->ibuf = NULL;
- cache->curve_mask = NULL;
cache->tex_mask = NULL;
cache->lastdiameter = -1; /* force ibuf create in refresh */
cache->invert = invert;
@@ -200,9 +197,7 @@ static void brush_painter_cache_2d_free(BrushPainterCache *cache)
if (cache->texibuf) {
IMB_freeImBuf(cache->texibuf);
}
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- }
+ paint_curve_mask_cache_free_data(&cache->curve_mask_cache);
if (cache->tex_mask) {
MEM_freeN(cache->tex_mask);
}
@@ -380,92 +375,6 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
cache->tex_mask_old_h = diameter;
}
-/* create a mask with the falloff strength */
-static ushort *brush_painter_curve_mask_init(
- ushort *mask, BrushPainter *painter, int diameter, float radius, const float pos[2])
-{
- BLI_assert_msg(MEM_allocN_len(mask) == diameter * diameter * sizeof(ushort),
- "Allocated size of mask doesn't match.");
-
- Brush *brush = painter->brush;
-
- int offset = (int)floorf(diameter / 2.0f);
-
- ushort *m;
- m = mask;
-
- int aa_samples = 1.0f / (radius * 0.20f);
- if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) {
- aa_samples = clamp_i(aa_samples, 3, 16);
- }
- else {
- aa_samples = 1;
- }
-
- /* Temporal until we have the brush properties */
- const float hardness = 1.0f;
- const float rotation = 0.0f;
-
- float aa_offset = 1.0f / (2.0f * (float)aa_samples);
- float aa_step = 1.0f / (float)aa_samples;
-
- float bpos[2];
- bpos[0] = pos[0] - floorf(pos[0]) + offset - aa_offset;
- bpos[1] = pos[1] - floorf(pos[1]) + offset - aa_offset;
-
- const float co = cosf(DEG2RADF(rotation));
- const float si = sinf(DEG2RADF(rotation));
-
- float norm_factor = 65535.0f / (float)(aa_samples * aa_samples);
-
- for (int y = 0; y < diameter; y++) {
- for (int x = 0; x < diameter; x++, m++) {
- float total_samples = 0;
- for (int i = 0; i < aa_samples; i++) {
- for (int j = 0; j < aa_samples; j++) {
- float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)};
- float xy_rot[2];
- sub_v2_v2(pixel_xy, bpos);
-
- xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1];
- xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1];
-
- float len = len_v2(xy_rot);
- float p = len / radius;
- if (hardness < 1.0f) {
- p = (p - hardness) / (1.0f - hardness);
- p = 1.0f - p;
- CLAMP(p, 0.0f, 1.0f);
- }
- else {
- p = 1.0;
- }
- float hardness_factor = 3.0f * p * p - 2.0f * p * p * p;
- float curve = BKE_brush_curve_strength_clamped(brush, len, radius);
- total_samples += curve * hardness_factor;
- }
- }
- *m = (ushort)(total_samples * norm_factor);
- }
- }
-
- return mask;
-}
-
-static void brush_painter_curve_mask_refresh(
- BrushPainter *painter, ImagePaintTile *tile, int diameter, float radius, const float pos[2])
-{
- BrushPainterCache *cache = &tile->cache;
-
- if (diameter != cache->lastdiameter) {
- if (cache->curve_mask != NULL) {
- MEM_freeN(cache->curve_mask);
- }
- cache->curve_mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
- }
- brush_painter_curve_mask_init(cache->curve_mask, painter, diameter, radius, pos);
-}
-
/* create imbuf with brush color */
static ImBuf *brush_painter_imbuf_new(
BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance)
@@ -872,7 +781,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
/* Re-initialize the curve mask. Mask is always recreated due to the change of position. */
- brush_painter_curve_mask_refresh(painter, tile, diameter, size, pos);
+ paint_curve_mask_cache_update(&cache->curve_mask_cache, brush, diameter, size, pos);
/* detect if we need to recreate image brush buffer */
if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random ||
@@ -1336,7 +1245,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
&tmpbuf,
frombuf,
mask,
- tile->cache.curve_mask,
+ tile->cache.curve_mask_cache.curve_mask,
tile->cache.tex_mask,
mask_max,
region->destx,
@@ -1485,7 +1394,7 @@ static int paint_2d_op(void *state,
canvas,
frombuf,
NULL,
- tile->cache.curve_mask,
+ tile->cache.curve_mask_cache.curve_mask,
tile->cache.tex_mask,
mask_max,
region[a].destx,
@@ -1868,7 +1777,6 @@ static ImageUser *paint_2d_get_tile_iuser(ImagePaintState *s, int tile_number)
return iuser;
}
-/* this function expects linear space color values */
void paint_2d_bucket_fill(const bContext *C,
const float color[3],
Brush *br,
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc
new file mode 100644
index 00000000000..8d57a3d9152
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc
@@ -0,0 +1,188 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup ed
+ */
+
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+
+#include "BKE_brush.h"
+
+#include "paint_intern.h"
+
+namespace blender::ed::sculpt_paint {
+
+constexpr int AntiAliasingSamplesPerTexelAxisMin = 3;
+constexpr int AntiAliasingSamplesPerTexelAxisMax = 16;
+/**
+ * \brief Number of samples to use between 0..1.
+ */
+constexpr int CurveSamplesBaseLen = 1024;
+/**
+ * \brief Number of samples to store in the cache.
+ *
+ * M_SQRT2 is used as brushes are circles and the curve_mask is square.
+ * + 1 to fix floating rounding issues.
+ */
+constexpr int CurveSamplesLen = M_SQRT2 * CurveSamplesBaseLen + 1;
+
+static int aa_samples_per_texel_axis(const Brush *brush, const float radius)
+{
+ int aa_samples = 1.0f / (radius * 0.20f);
+ if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) {
+ aa_samples = clamp_i(
+ aa_samples, AntiAliasingSamplesPerTexelAxisMin, AntiAliasingSamplesPerTexelAxisMax);
+ }
+ else {
+ aa_samples = 1;
+ }
+ return aa_samples;
+}
+
+/* create a mask with the falloff strength */
+static void update_curve_mask(CurveMaskCache *curve_mask_cache,
+ const Brush *brush,
+ const int diameter,
+ const float radius,
+ const float cursor_position[2])
+{
+ BLI_assert(curve_mask_cache->curve_mask != nullptr);
+ int offset = (int)floorf(diameter / 2.0f);
+
+ unsigned short *m = curve_mask_cache->curve_mask;
+
+ const int aa_samples = aa_samples_per_texel_axis(brush, radius);
+ const float aa_offset = 1.0f / (2.0f * (float)aa_samples);
+ const float aa_step = 1.0f / (float)aa_samples;
+
+ float bpos[2];
+ bpos[0] = cursor_position[0] - floorf(cursor_position[0]) + offset;
+ bpos[1] = cursor_position[1] - floorf(cursor_position[1]) + offset;
+
+ float weight_factor = 65535.0f / (float)(aa_samples * aa_samples);
+
+ for (int y = 0; y < diameter; y++) {
+ for (int x = 0; x < diameter; x++, m++) {
+ float pixel_xy[2];
+ pixel_xy[0] = static_cast<float>(x) + aa_offset;
+ float total_weight = 0;
+
+ for (int i = 0; i < aa_samples; i++) {
+ pixel_xy[1] = static_cast<float>(y) + aa_offset;
+ for (int j = 0; j < aa_samples; j++) {
+ const float len = len_v2v2(pixel_xy, bpos);
+ const int sample_index = min_ii((len / radius) * CurveSamplesBaseLen,
+ CurveSamplesLen - 1);
+ const float sample_weight = curve_mask_cache->sampled_curve[sample_index];
+
+ total_weight += sample_weight;
+
+ pixel_xy[1] += aa_step;
+ }
+ pixel_xy[0] += aa_step;
+ }
+ *m = (unsigned short)(total_weight * weight_factor);
+ }
+ }
+}
+
+static bool is_sampled_curve_valid(const CurveMaskCache *curve_mask_cache, const Brush *brush)
+{
+ if (curve_mask_cache->sampled_curve == nullptr) {
+ return false;
+ }
+ return curve_mask_cache->last_curve_timestamp == brush->curve->changed_timestamp;
+}
+
+static void sampled_curve_free(CurveMaskCache *curve_mask_cache)
+{
+ MEM_SAFE_FREE(curve_mask_cache->sampled_curve);
+ curve_mask_cache->last_curve_timestamp = 0;
+}
+
+static void update_sampled_curve(CurveMaskCache *curve_mask_cache, const Brush *brush)
+{
+ if (curve_mask_cache->sampled_curve == nullptr) {
+ curve_mask_cache->sampled_curve = static_cast<float *>(
+ MEM_mallocN(CurveSamplesLen * sizeof(float), __func__));
+ }
+
+ for (int i = 0; i < CurveSamplesLen; i++) {
+ const float len = i / float(CurveSamplesBaseLen);
+ const float sample_weight = BKE_brush_curve_strength_clamped(brush, len, 1.0f);
+ curve_mask_cache->sampled_curve[i] = sample_weight;
+ }
+ curve_mask_cache->last_curve_timestamp = brush->curve->changed_timestamp;
+}
+
+static size_t diameter_to_curve_mask_size(const int diameter)
+{
+ return diameter * diameter * sizeof(ushort);
+}
+
+static bool is_curve_mask_size_valid(const CurveMaskCache *curve_mask_cache, const int diameter)
+{
+ return curve_mask_cache->curve_mask_size == diameter_to_curve_mask_size(diameter);
+}
+
+static void curve_mask_free(CurveMaskCache *curve_mask_cache)
+{
+ curve_mask_cache->curve_mask_size = 0;
+ MEM_SAFE_FREE(curve_mask_cache->curve_mask);
+}
+
+static void curve_mask_allocate(CurveMaskCache *curve_mask_cache, const int diameter)
+{
+ const size_t curve_mask_size = diameter_to_curve_mask_size(diameter);
+ curve_mask_cache->curve_mask = static_cast<unsigned short *>(
+ MEM_mallocN(curve_mask_size, __func__));
+ curve_mask_cache->curve_mask_size = curve_mask_size;
+}
+
+} // namespace blender::ed::sculpt_paint
+
+using namespace blender::ed::sculpt_paint;
+
+void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache)
+{
+ sampled_curve_free(curve_mask_cache);
+ curve_mask_free(curve_mask_cache);
+}
+
+void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
+ const Brush *brush,
+ const int diameter,
+ const float radius,
+ const float cursor_position[2])
+{
+ if (!is_sampled_curve_valid(curve_mask_cache, brush)) {
+ update_sampled_curve(curve_mask_cache, brush);
+ }
+
+ if (!is_curve_mask_size_valid(curve_mask_cache, diameter)) {
+ curve_mask_free(curve_mask_cache);
+ curve_mask_allocate(curve_mask_cache, diameter);
+ }
+ update_curve_mask(curve_mask_cache, brush, diameter, radius, cursor_position);
+}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index db3e69b0953..7df5848e068 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -4134,8 +4134,9 @@ static bool project_paint_clone_face_skip(ProjPaintState *ps,
if (ps->do_material_slots) {
if (lc->slot_clone != lc->slot_last_clone) {
- if (!slot->uvname || !(lc->mloopuv_clone_base = CustomData_get_layer_named(
- &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
+ if (!lc->slot_clone->uvname ||
+ !(lc->mloopuv_clone_base = CustomData_get_layer_named(
+ &ps->me_eval->ldata, CD_MLOOPUV, lc->slot_clone->uvname))) {
lc->mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
}
lc->slot_last_clone = lc->slot_clone;
@@ -4648,13 +4649,7 @@ static void project_paint_end(ProjPaintState *ps)
/* 1 = an undo, -1 is a redo. */
static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
{
- pr->x1 = INT_MAX;
- pr->y1 = INT_MAX;
-
- pr->x2 = -1;
- pr->y2 = -1;
-
- pr->enabled = 1;
+ BLI_rcti_init_minmax(&pr->dirty_region);
}
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
@@ -4670,16 +4665,11 @@ static bool partial_redraw_array_merge(ImagePaintPartialRedraw *pr,
ImagePaintPartialRedraw *pr_other,
int tot)
{
- bool touch = 0;
+ bool touch = false;
while (tot--) {
- pr->x1 = min_ii(pr->x1, pr_other->x1);
- pr->y1 = min_ii(pr->y1, pr_other->y1);
-
- pr->x2 = max_ii(pr->x2, pr_other->x2);
- pr->y2 = max_ii(pr->y2, pr_other->y2);
-
- if (pr->x2 != -1) {
- touch = 1;
+ BLI_rcti_do_minmax_rcti(&pr->dirty_region, &pr_other->dirty_region);
+ if (!BLI_rcti_is_empty(&pr->dirty_region)) {
+ touch = true;
}
pr++;
@@ -4702,7 +4692,7 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
/* look over each bound cell */
for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) {
pr = &(projIma->partRedrawRect[i]);
- if (pr->x2 != -1) { /* TODO: use 'enabled' ? */
+ if (BLI_rcti_is_valid(&pr->dirty_region)) {
set_imapaintpartial(pr);
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, &projIma->iuser, true);
redraw = 1;
@@ -5116,11 +5106,10 @@ static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, flo
static void image_paint_partial_redraw_expand(ImagePaintPartialRedraw *cell,
const ProjPixel *projPixel)
{
- cell->x1 = min_ii(cell->x1, (int)projPixel->x_px);
- cell->y1 = min_ii(cell->y1, (int)projPixel->y_px);
-
- cell->x2 = max_ii(cell->x2, (int)projPixel->x_px + 1);
- cell->y2 = max_ii(cell->y2, (int)projPixel->y_px + 1);
+ rcti rect_to_add;
+ BLI_rcti_init(
+ &rect_to_add, projPixel->x_px, projPixel->x_px + 1, projPixel->y_px, projPixel->y_px + 1);
+ BLI_rcti_do_minmax_rcti(&cell->dirty_region, &rect_to_add);
}
static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
@@ -6335,8 +6324,6 @@ void ED_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool
!stencil ? " Stencil," : "");
}
-/* Make sure that active object has a material,
- * and assign UVs and image layers if they do not exist */
bool ED_paint_proj_mesh_data_check(
Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
{
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 7341d984c91..90887b9fc39 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -23,6 +23,16 @@
#pragma once
+#include "BKE_paint.h"
+
+#include "BLI_rect.h"
+
+#include "DNA_scene_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ARegion;
struct Brush;
struct ColorManagedDisplay;
@@ -38,13 +48,10 @@ struct Scene;
struct VPaint;
struct ViewContext;
struct bContext;
-struct rcti;
struct wmEvent;
struct wmKeyConfig;
struct wmOperator;
struct wmOperatorType;
-enum ePaintMode;
-enum ePaintSymmetryFlags;
typedef struct CoNo {
float co[3];
@@ -52,6 +59,7 @@ typedef struct CoNo {
} CoNo;
/* paint_stroke.c */
+
typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
typedef void (*StrokeUpdateStep)(struct bContext *C,
@@ -70,13 +78,25 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
int event_type);
void paint_stroke_free(struct bContext *C, struct wmOperator *op);
+/**
+ * Returns zero if the stroke dots should not be spaced, non-zero otherwise.
+ */
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
+/**
+ * Return true if the brush size can change during paint (normally used for pressure).
+ */
bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode);
+/**
+ * Return true if the brush size can change during paint (normally used for pressure).
+ */
bool paint_supports_dynamic_tex_coords(struct Brush *br, enum ePaintMode mode);
bool paint_supports_smooth_stroke(struct Brush *br, enum ePaintMode mode);
bool paint_supports_texture(enum ePaintMode mode);
bool paint_supports_jitter(enum ePaintMode mode);
+/**
+ * Called in paint_ops.c, on each regeneration of key-maps.
+ */
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
@@ -89,14 +109,21 @@ float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool PAINT_brush_tool_poll(struct bContext *C);
void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
+/**
+ * Delete overlay cursor textures to preserve memory and invalidate all overlay flags.
+ */
void paint_cursor_delete_textures(void);
/* paint_vertex.c */
+
bool weight_paint_poll(struct bContext *C);
bool weight_paint_poll_ignore_tool(bContext *C);
bool weight_paint_mode_poll(struct bContext *C);
bool vertex_paint_poll(struct bContext *C);
bool vertex_paint_poll_ignore_tool(struct bContext *C);
+/**
+ * Returns true if vertex paint mode is active.
+ */
bool vertex_paint_mode_poll(struct bContext *C);
typedef void (*VPaintTransform_Callback)(const float col[3],
@@ -119,15 +146,31 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool secondary);
/* paint_vertex_color_utils.c */
+
+/**
+ * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
+ */
unsigned int ED_vpaint_blend_tool(const int tool,
const uint col,
const uint paintcol,
const int alpha_i);
+/**
+ * Apply callback to each vertex of the active vertex color layer.
+ */
bool ED_vpaint_color_transform(struct Object *ob,
VPaintTransform_Callback vpaint_tx_fn,
const void *user_data);
/* paint_vertex_weight_utils.c */
+
+/**
+ * \param weight: Typically the current weight: #MDeformWeight.weight
+ *
+ * \return The final weight, note that this is _not_ clamped from [0-1].
+ * Clamping must be done on the final #MDeformWeight.weight
+ *
+ * \note vertex-paint has an equivalent function: #ED_vpaint_blend_tool
+ */
float ED_wpaint_blend_tool(const int tool,
const float weight,
const float paintval,
@@ -140,13 +183,18 @@ struct WPaintVGroupIndex {
int active;
int mirror;
};
+/**
+ * Ensure we have data on wpaint start, add if needed.
+ */
bool ED_wpaint_ensure_data(struct bContext *C,
struct ReportList *reports,
enum eWPaintFlag flag,
struct WPaintVGroupIndex *vgroup_index);
+/** Return -1 when invalid. */
int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active);
/* paint_vertex_color_ops.c */
+
void PAINT_OT_vertex_color_set(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_from_weight(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_smooth(struct wmOperatorType *ot);
@@ -156,6 +204,7 @@ void PAINT_OT_vertex_color_invert(struct wmOperatorType *ot);
void PAINT_OT_vertex_color_levels(struct wmOperatorType *ot);
/* paint_vertex_weight_ops.c */
+
void PAINT_OT_weight_from_bones(struct wmOperatorType *ot);
void PAINT_OT_weight_sample(struct wmOperatorType *ot);
void PAINT_OT_weight_sample_group(struct wmOperatorType *ot);
@@ -175,8 +224,7 @@ void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle);
/* paint_image.c */
typedef struct ImagePaintPartialRedraw {
- int x1, y1, x2, y2; /* XXX, could use 'rcti' */
- int enabled;
+ rcti dirty_region;
} ImagePaintPartialRedraw;
bool image_texture_paint_poll(struct bContext *C);
@@ -200,6 +248,9 @@ void paint_2d_stroke(void *ps,
float pressure,
float distance,
float size);
+/**
+ * This function expects linear space color values.
+ */
void paint_2d_bucket_fill(const struct bContext *C,
const float color[3],
struct Brush *br,
@@ -245,14 +296,56 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
+/* paint_image_2d_curve_mask.cc */
+/**
+ * \brief Caching structure for curve mask.
+ *
+ * When 2d painting images the curve mask is used as an input.
+ */
+typedef struct CurveMaskCache {
+ /**
+ * \brief Last #CurveMapping.changed_timestamp being read.
+ *
+ * When different the input cache needs to be recalculated.
+ */
+ int last_curve_timestamp;
+
+ /**
+ * \brief sampled version of the brush curve-mapping.
+ */
+ float *sampled_curve;
+
+ /**
+ * \brief Size in bytes of the curve_mask field.
+ *
+ * Used to determine if the curve_mask needs to be re-allocated.
+ */
+ size_t curve_mask_size;
+
+ /**
+ * \brief Curve mask that can be passed as curve_mask parameter when.
+ */
+ ushort *curve_mask;
+} CurveMaskCache;
+
+void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache);
+void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache,
+ const struct Brush *brush,
+ const int diameter,
+ const float radius,
+ const float cursor_position[2]);
+
/* sculpt_uv.c */
+
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
/* paint_utils.c */
-/* Convert the object-space axis-aligned bounding box (expressed as
+/**
+ * Convert the object-space axis-aligned bounding box (expressed as
* its minimum and maximum corners) into a screen-space rectangle,
- * returns zero if the result is empty */
+ * returns zero if the result is empty.
+ */
bool paint_convert_bb_to_rect(struct rcti *rect,
const float bb_min[3],
const float bb_max[3],
@@ -260,9 +353,11 @@ bool paint_convert_bb_to_rect(struct rcti *rect,
struct RegionView3D *rv3d,
struct Object *ob);
-/* Get four planes in object-space that describe the projection of
+/**
+ * Get four planes in object-space that describe the projection of
* screen_rect from screen into object-space (essentially converting a
- * 2D screens-space bounding box into four 3D planes) */
+ * 2D screens-space bounding box into four 3D planes).
+ */
void paint_calc_redraw_planes(float planes[4][4],
const struct ARegion *region,
struct Object *ob,
@@ -282,6 +377,9 @@ void paint_get_tex_pixel_col(const struct MTex *mtex,
bool convert,
struct ColorSpace *colorspace);
+/**
+ * Used for both 3D view and image window.
+ */
void paint_sample_color(
struct bContext *C, struct ARegion *region, int x, int y, bool texpaint_proj, bool palette);
@@ -303,6 +401,9 @@ bool mask_paint_poll(struct bContext *C);
bool paint_curve_poll(struct bContext *C);
bool facemask_paint_poll(struct bContext *C);
+/**
+ * Uses symm to selectively flip any axis of a coordinate.
+ */
void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm);
void flip_qt_qt(float out[4], const float in[4], const enum ePaintSymmetryFlags symm);
@@ -360,9 +461,16 @@ typedef struct {
} BlurKernel;
enum eBlurKernelType;
-/* can be extended to other blur kernels later */
+/**
+ * Paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging.
+ * Can be extended to other blur kernels later,
+ */
BlurKernel *paint_new_blur_kernel(struct Brush *br, bool proj);
void paint_delete_blur_kernel(BlurKernel *);
/* paint curve defines */
#define PAINT_CURVE_NUM_SEGMENTS 40
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index de01bc3a474..c87f4e0aeec 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -1007,7 +1007,6 @@ static void stroke_done(bContext *C, wmOperator *op)
paint_stroke_free(C, op);
}
-/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
{
if ((br->flag & BRUSH_SPACE) == 0) {
@@ -1041,7 +1040,6 @@ static bool sculpt_is_grab_tool(Brush *br)
SCULPT_TOOL_SNAKE_HOOK);
}
-/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_size(Brush *br, ePaintMode mode)
{
if (br->flag & BRUSH_ANCHORED) {
@@ -1094,7 +1092,6 @@ bool paint_supports_texture(ePaintMode mode)
mode, PAINT_MODE_SCULPT, PAINT_MODE_VERTEX, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D);
}
-/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
{
if (br->flag & BRUSH_ANCHORED) {
@@ -1115,7 +1112,6 @@ bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
#define PAINT_STROKE_MODAL_CANCEL 1
-/* Called in paint_ops.c, on each regeneration of key-maps. */
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
{
static struct EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 709e04d807d..541893f7957 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -80,9 +80,6 @@
#include "paint_intern.h"
-/* Convert the object-space axis-aligned bounding box (expressed as
- * its minimum and maximum corners) into a screen-space rectangle,
- * returns zero if the result is empty */
bool paint_convert_bb_to_rect(rcti *rect,
const float bb_min[3],
const float bb_max[3],
@@ -127,9 +124,6 @@ bool paint_convert_bb_to_rect(rcti *rect,
return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
}
-/* Get four planes in object-space that describe the projection of
- * screen_rect from screen into object-space (essentially converting a
- * 2D screens-space bounding box into four 3D planes) */
void paint_calc_redraw_planes(float planes[4][4],
const ARegion *region,
Object *ob,
@@ -403,7 +397,6 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
return ima;
}
-/* Uses symm to selectively flip any axis of a coordinate. */
void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
{
if (symm & PAINT_SYMM_X) {
@@ -449,7 +442,6 @@ void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
axis_angle_normalized_to_quat(out, axis, angle);
}
-/* used for both 3d view and image window */
void paint_sample_color(
bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette)
{
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index fede01a614b..23e03f3e576 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -199,9 +199,6 @@ static void paint_last_stroke_update(Scene *scene, const float location[3])
ups->last_stroke_valid = true;
}
-/* polling - retrieve whether cursor should be set or operator should be done */
-
-/* Returns true if vertex paint mode is active */
bool vertex_paint_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index dbc6044d2d8..a083af14c89 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -41,9 +41,6 @@
#define EPS_SATURATION 0.0005f
-/**
- * Apply callback to each vertex of the active vertex color layer.
- */
bool ED_vpaint_color_transform(struct Object *ob,
VPaintTransform_Callback vpaint_tx_fn,
const void *user_data)
@@ -610,9 +607,6 @@ BLI_INLINE uint mcol_alpha_sub(uint col_src, int fac)
return col_mix;
}
-/**
- * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
- */
uint ED_vpaint_blend_tool(const int tool, const uint col, const uint paintcol, const int alpha_i)
{
switch ((IMB_BlendMode)tool) {
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 1077f66f10c..d10a56be866 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -408,10 +408,11 @@ static int weight_sample_group_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* TODO: we could make this a menu into OBJECT_OT_vertex_group_set_active
- * rather than its own operator */
void PAINT_OT_weight_sample_group(wmOperatorType *ot)
{
+ /* TODO: we could make this a menu into #OBJECT_OT_vertex_group_set_active
+ * rather than its own operator */
+
PropertyRNA *prop = NULL;
/* identifiers */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index 19ffa0c952d..34a27d5a5c2 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -51,7 +51,6 @@
/** \name Weight Paint Sanity Checks
* \{ */
-/* ensure we have data on wpaint start, add if needed */
bool ED_wpaint_ensure_data(bContext *C,
struct ReportList *reports,
enum eWPaintFlag flag,
@@ -131,9 +130,9 @@ bool ED_wpaint_ensure_data(bContext *C,
return true;
}
+
/** \} */
-/* mirror_vgroup is set to -1 when invalid */
int ED_wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
@@ -277,14 +276,6 @@ BLI_INLINE float wval_exclusion(float weight, float paintval, float fac)
return temp * fac + weight * mfac;
}
-/**
- * \param weight: Typically the current weight: #MDeformWeight.weight
- *
- * \return The final weight, note that this is _not_ clamped from [0-1].
- * Clamping must be done on the final #MDeformWeight.weight
- *
- * \note vertex-paint has an equivalent function: #ED_vpaint_blend_tool
- */
float ED_wpaint_blend_tool(const int tool,
const float weight,
const float paintval,
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 7b854e886a0..b764d0e1b5b 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -102,13 +102,15 @@
#include <stdlib.h>
#include <string.h>
-/* Sculpt PBVH abstraction API
+/* -------------------------------------------------------------------- */
+/** \name Sculpt PBVH Abstraction API
*
* This is read-only, for writing use PBVH vertex iterators. There vd.index matches
* the indices used here.
*
* For multi-resolution, the same vertex in multiple grids is counted multiple times, with
- * different index for each grid. */
+ * different index for each grid.
+ * \{ */
void SCULPT_vertex_random_access_ensure(SculptSession *ss)
{
@@ -911,32 +913,18 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
/* Utilities */
-/**
- * Returns true when the step belongs to the stroke that is directly performed by the brush and
- * not by one of the symmetry passes.
- */
bool SCULPT_stroke_is_main_symmetry_pass(StrokeCache *cache)
{
return cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0 &&
cache->tile_pass == 0;
}
-/**
- * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes
- * enabled.
- *
- * This should be used for functionality that needs to be computed once per stroke of a particular
- * tool (allocating memory, updating random seeds...).
- */
bool SCULPT_stroke_is_first_brush_step(StrokeCache *cache)
{
return cache->first_time && cache->mirror_symmetry_pass == 0 &&
cache->radial_symmetry_pass == 0 && cache->tile_pass == 0;
}
-/**
- * Returns true on the first brush step of each symmetry pass.
- */
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(StrokeCache *cache)
{
return cache->first_time;
@@ -1049,7 +1037,6 @@ bool SCULPT_is_symmetry_iteration_valid(char i, char symm)
return i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (!ELEM(i, 3, 5))));
}
-/* Checks if a vertex is inside the brush radius from any of its mirrored axis. */
bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
const float br_co[3],
float radius,
@@ -1083,9 +1070,13 @@ void SCULPT_tag_update_overlays(bContext *C)
}
}
-/* Sculpt Flood Fill API
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Flood Fill API
*
- * Iterate over connected vertices, starting from one or more initial vertices. */
+ * Iterate over connected vertices, starting from one or more initial vertices.
+ * \{ */
void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
{
@@ -1196,12 +1187,13 @@ void SCULPT_floodfill_free(SculptFloodFill *flood)
flood->queue = NULL;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
* share logic with #rna_def_sculpt_capabilities where possible.
- *
* \{ */
static bool sculpt_tool_needs_original(const char sculpt_tool)
@@ -1261,23 +1253,24 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) ||
sculpt_brush_use_topology_rake(ss, brush);
}
-/** \} */
static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
{
return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Init/Update
+ * \{ */
+
typedef enum StrokeFlags {
CLIP_X = 1,
CLIP_Y = 2,
CLIP_Z = 4,
} StrokeFlags;
-/**
- * Initialize a #SculptOrigVertData for accessing original vertex data;
- * handles #BMesh, #Mesh, and multi-resolution.
- */
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
@@ -1297,10 +1290,6 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
}
}
-/**
- * Initialize a #SculptOrigVertData for accessing original vertex data;
- * handles #BMesh, #Mesh, and multi-resolution.
- */
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node)
{
SculptUndoNode *unode;
@@ -1308,9 +1297,6 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *
SCULPT_orig_vert_data_unode_init(data, ob, unode);
}
-/**
- * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
- */
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
@@ -1400,11 +1386,12 @@ static void sculpt_project_v3_normal_align(SculptSession *ss,
grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name SculptProjectVector
*
* Fast-path for #project_plane_v3_v3v3
- *
* \{ */
typedef struct SculptProjectVector {
@@ -1441,14 +1428,10 @@ static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3
/** \} */
-/**********************************************************************/
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Dynamic Topology
+ * \{ */
-/* Returns true if the stroke will use dynamic topology, false
- * otherwise.
- *
- * Factors: some brushes like grab cannot do dynamic topology.
- * Others, like smooth, are better without.
- * Same goes for alt-key smoothing. */
bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -1462,7 +1445,11 @@ bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *bru
SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
-/*** paint mesh ***/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Paint Mesh
+ * \{ */
static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
const int n,
@@ -1573,7 +1560,6 @@ static void sculpt_extend_redraw_rect_previous(Object *ob, rcti *rect)
BLI_rcti_union(rect, &ss->cache->previous_r);
}
-/* Get a screen-space rectangle of the modified area. */
bool SCULPT_get_redraw_rect(ARegion *region, RegionView3D *rv3d, Object *ob, rcti *rect)
{
PBVH *pbvh = ob->sculpt->pbvh;
@@ -1918,6 +1904,8 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
return 1.0f / overlap;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Calculate Normal and Center
*
@@ -2205,7 +2193,6 @@ void SCULPT_calc_area_normal(
SCULPT_pbvh_calc_area_normal(brush, ob, nodes, totnode, true, r_area_no);
}
-/* Expose 'calc_area_normal' externally. */
bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
Object *ob,
PBVHNode **nodes,
@@ -2247,8 +2234,10 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
return data.any_vertex_sampled;
}
-/* This calculates flatten center and area normal together,
- * amortizing the memory bandwidth and loop overhead to calculate both at the same time. */
+/**
+ * This calculates flatten center and area normal together,
+ * amortizing the memory bandwidth and loop overhead to calculate both at the same time.
+ */
static void calc_area_normal_and_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
{
@@ -2308,6 +2297,10 @@ static void calc_area_normal_and_center(
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Generic Brush Utilities
+ * \{ */
+
/**
* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
@@ -2463,7 +2456,6 @@ static float brush_strength(const Sculpt *sd,
}
}
-/* Return a multiplier for brush strength on a particular vertex. */
float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
@@ -2561,7 +2553,6 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
return avg;
}
-/* Test AABB against sphere. */
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
{
SculptSearchSphereData *data = data_v;
@@ -2608,7 +2599,6 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
return len_squared_v3(t) < data->radius_squared;
}
-/* 2D projection (distance to line). */
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
{
SculptSearchCircleData *data = data_v;
@@ -2636,9 +2626,6 @@ bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
return dist_sq < data->radius_squared || true;
}
-/**
- * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags.
- */
void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
{
for (int i = 0; i < 3; i++) {
@@ -2867,6 +2854,12 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Rake (Shared Utility)
+ * \{ */
+
typedef struct {
SculptSession *ss;
const float *ray_start;
@@ -2979,6 +2972,12 @@ static void bmesh_topology_rake(
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Mask Brush
+ * \{ */
+
static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -3050,6 +3049,8 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sculpt Multires Displacement Eraser Brush
* \{ */
@@ -3118,6 +3119,7 @@ static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **node
/** \} */
+/* -------------------------------------------------------------------- */
/** \name Sculpt Multires Displacement Smear Brush
* \{ */
@@ -3260,6 +3262,10 @@ static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Draw Brush
+ * \{ */
+
static void do_draw_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -3414,6 +3420,8 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sculpt Topology Brush
* \{ */
@@ -3738,6 +3746,10 @@ static void calc_sculpt_plane(
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Crease & Blob Brush
+ * \{ */
+
/**
* Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
*/
@@ -4974,6 +4986,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sculpt Clay Brush
* \{ */
@@ -5506,6 +5520,8 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Sculpt Clay Thumb Brush
* \{ */
@@ -5680,6 +5696,10 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Gravity Brush
+ * \{ */
+
static void do_gravity_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -5750,6 +5770,12 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Brush Utilities
+ * \{ */
+
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
{
Mesh *me = (Mesh *)ob->data;
@@ -5954,8 +5980,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
}
- /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with
- * zero radius, thus we have no pbvh nodes on the first brush step. */
+ /* Initialize auto-masking cache. For anchored brushes with spherical falloff,
+ * we start off with zero radius, thus we have no PBVH nodes on the first brush step. */
if (totnode ||
((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) {
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
@@ -6318,7 +6344,6 @@ static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-/* Flush displacement from deformed PBVH to original layer. */
void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
{
SculptSession *ss = ob->sculpt;
@@ -6372,10 +6397,6 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
}
}
-/**
- * Flip all the edit-data across the axis/axes specified by \a symm.
- * Used to calculate multiple modifications to the mesh when symmetry is enabled.
- */
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
const char symm,
const char axis,
@@ -7416,9 +7437,6 @@ float SCULPT_raycast_init(ViewContext *vc,
return dist;
}
-/* Gets the normal, location and active vertex location of the geometry under the cursor. This also
- * updates the active vertex and cursor related data of the SculptSession using the mouse position
- */
bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
const float mouse[2],
@@ -7548,9 +7566,6 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
return true;
}
-/* Do a raycast in the tree to find the 3d brush location
- * (This allows us to ignore the GL depth buffer)
- * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise. */
bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -7714,7 +7729,6 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
}
}
-/* Copy the PBVH bounding box into the object's bounding box. */
void SCULPT_update_object_bounding_box(Object *ob)
{
if (ob->runtime.bb) {
@@ -9398,6 +9412,12 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
1.0f);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Registration
+ * \{ */
+
void ED_operatortypes_sculpt(void)
{
WM_operatortype_append(SCULPT_OT_brush_stroke);
@@ -9436,3 +9456,5 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_expand);
}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 37678ec276a..e238fafb063 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -487,8 +487,6 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
}
}
-/* Main function to get SculptBoundary data both for brush deformation and viewport preview. Can
- * return NULL if there is no boundary from the given vertex using the given radius. */
SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
const int initial_vertex,
@@ -946,7 +944,6 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-/* Main Brush Function. */
void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index fa879214794..dcfd7f7bcdc 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -1052,7 +1052,6 @@ static void cloth_sim_initialize_default_node_state(SculptSession *ss,
MEM_SAFE_FREE(nodes);
}
-/* Public functions. */
SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
const float cloth_mass,
const float cloth_damping,
@@ -1195,7 +1194,6 @@ static void sculpt_cloth_ensure_constraints_in_simulation_area(Sculpt *sd,
sd, ob, nodes, totnode, ss->cache->cloth_sim, sim_location, limit);
}
-/* Main Brush Function. */
void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
@@ -1271,7 +1269,6 @@ void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim)
MEM_SAFE_FREE(cloth_sim);
}
-/* Cursor drawing function. */
void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
const Brush *brush,
const float location[3],
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index edbb98b481e..9082408b8dd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -57,6 +57,10 @@
#include <math.h>
#include <stdlib.h>
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
typedef struct {
const float *ray_start;
bool hit;
@@ -82,6 +86,12 @@ static bool sculpt_and_dynamic_topology_poll(bContext *C)
return SCULPT_mode_poll(C) && ob->sculpt->bm;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Detail Flood Fill
+ * \{ */
+
static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -147,6 +157,12 @@ void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Detail Size
+ * \{ */
+
typedef enum eSculptSampleDetailModeTypes {
SAMPLE_DETAIL_DYNTOPO = 0,
SAMPLE_DETAIL_VOXEL = 1,
@@ -364,13 +380,17 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
"Target sculpting workflow that is going to use the sampled size");
}
-/* Dynamic-topology detail size.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dynamic-topology detail size
*
* Currently, there are two operators editing the detail size:
- * - SCULPT_OT_set_detail_size uses radial control for all methods
- * - SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail
- * resolution (for constant detail method, falls back to radial control for the remaining methods).
- */
+ * - #SCULPT_OT_set_detail_size uses radial control for all methods
+ * - #SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail
+ * resolution (for constant detail method,
+ * falls back to radial control for the remaining methods).
+ * \{ */
static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
{
@@ -429,6 +449,8 @@ void SCULPT_OT_set_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Dyntopo Detail Size Edit Operator
* \{ */
@@ -759,3 +781,5 @@ void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 89e07081802..dc8cda964ea 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -73,6 +73,7 @@
#include <stdlib.h>
/* Utils. */
+
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh)
{
int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 760cf632ae9..ff1a8935ba0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -64,7 +64,6 @@
#include <math.h>
#include <stdlib.h>
-/* Filter orientation utils. */
void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache)
{
switch (filter_cache->orientation) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 16df1efd969..4dd2a786922 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -46,7 +46,9 @@ enum ePaintSymmetryFlags;
bool SCULPT_mode_poll(struct bContext *C);
bool SCULPT_mode_poll_view3d(struct bContext *C);
-/* checks for a brush, not just sculpt mode */
+/**
+ * Checks for a brush, not just sculpt mode.
+ */
bool SCULPT_poll(struct bContext *C);
bool SCULPT_poll_view3d(struct bContext *C);
@@ -63,9 +65,14 @@ typedef enum SculptUpdateType {
void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
+/**
+ * Flush displacement from deformed PBVH to original layer.
+ */
void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
-/* Should be used after modifying the mask or Face Sets IDs. */
+/**
+ * Should be used after modifying the mask or Face Sets IDs.
+ */
void SCULPT_tag_update_overlays(bContext *C);
/* Stroke */
@@ -76,7 +83,16 @@ typedef struct SculptCursorGeometryInfo {
float active_vertex_co[3];
} SculptCursorGeometryInfo;
+/**
+ * Do a ray-cast in the tree to find the 3d brush location
+ * (This allows us to ignore the GL depth buffer)
+ * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise.
+ */
bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
+/**
+ * Gets the normal, location and active vertex location of the geometry under the cursor. This also
+ * updates the active vertex and cursor related data of the SculptSession using the mouse position
+ */
bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
const float mouse[2],
@@ -95,6 +111,7 @@ float SCULPT_raycast_init(struct ViewContext *vc,
char SCULPT_mesh_symmetry_xyz_get(Object *object);
/* Sculpt PBVH abstraction API */
+
void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
int SCULPT_vertex_count_get(struct SculptSession *ss);
@@ -106,15 +123,21 @@ const float *SCULPT_vertex_color_get(SculptSession *ss, int index);
const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index);
void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]);
-/* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */
+/**
+ * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled.
+ */
const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
-/* Returns the info of the limit surface when Multires is available, otherwise it returns the
- * current coordinate of the vertex. */
+/**
+ * Returns the info of the limit surface when multi-res is available,
+ * otherwise it returns the current coordinate of the vertex.
+ */
void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]);
-/* Returns the pointer to the coordinates that should be edited from a brush tool iterator
- * depending on the given deformation target. */
+/**
+ * Returns the pointer to the coordinates that should be edited from a brush tool iterator
+ * depending on the given deformation target.
+ */
float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
const int deform_target,
PBVHVertexIter *iter);
@@ -215,8 +238,22 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
void SCULPT_face_sets_visibility_invert(SculptSession *ss);
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
+/**
+ * Returns true when the step belongs to the stroke that is directly performed by the brush and
+ * not by one of the symmetry passes.
+ */
bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache);
+/**
+ * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes
+ * enabled.
+ *
+ * This should be used for functionality that needs to be computed once per stroke of a particular
+ * tool (allocating memory, updating random seeds...).
+ */
bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache);
+/**
+ * Returns true on the first brush step of each symmetry pass.
+ */
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache);
/* Sculpt Original Data */
@@ -236,8 +273,19 @@ typedef struct {
const float *col;
} SculptOrigVertData;
+/**
+ * Initialize a #SculptOrigVertData for accessing original vertex data;
+ * handles #BMesh, #Mesh, and multi-resolution.
+ */
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
+/**
+ * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
+ */
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
+/**
+ * Initialize a #SculptOrigVertData for accessing original vertex data;
+ * handles #BMesh, #Mesh, and multi-resolution.
+ */
void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data,
Object *ob,
struct SculptUndoNode *unode);
@@ -263,12 +311,18 @@ int SCULPT_plane_point_side(const float co[3], const float plane[4]);
int SCULPT_plane_trim(const struct StrokeCache *cache,
const struct Brush *brush,
const float val[3]);
+/**
+ * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags.
+ */
void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]);
float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss);
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]);
bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm);
+/**
+ * Checks if a vertex is inside the brush radius from any of its mirrored axis.
+ */
bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
const float br_co[3],
float radius,
@@ -329,6 +383,14 @@ void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
Scene *scene,
Object *ob);
+/**
+ * Returns true if the stroke will use dynamic topology, false
+ * otherwise.
+ *
+ * Factors: some brushes like grab cannot do dynamic topology.
+ * Others, like smooth, are better without.
+ * Same goes for alt-key smoothing.
+ */
bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush);
void SCULPT_dynamic_topology_triangulate(struct BMesh *bm);
@@ -391,6 +453,10 @@ void SCULPT_mask_filter_smooth_apply(
/* Brushes. */
/* Cloth Brush. */
+
+/**
+ * Main Brush Function.
+ */
void SCULPT_do_cloth_brush(struct Sculpt *sd,
struct Object *ob,
struct PBVHNode **nodes,
@@ -398,6 +464,8 @@ void SCULPT_do_cloth_brush(struct Sculpt *sd,
void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim);
+/* Public functions. */
+
struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(
struct SculptSession *ss,
const float cloth_mass,
@@ -429,6 +497,9 @@ void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
float initial_location[3],
const float radius);
+/**
+ * Cursor drawing function.
+ */
void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
const struct Brush *brush,
const float location[3],
@@ -490,10 +561,21 @@ BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush)
}
/* Pose Brush. */
+
+/**
+ * Main Brush Function.
+ */
void SCULPT_do_pose_brush(struct Sculpt *sd,
struct Object *ob,
struct PBVHNode **nodes,
int totnode);
+/**
+ * Calculate the pose origin and (Optionally the pose factor)
+ * that is used when using the pose brush.
+ *
+ * \param r_pose_origin: Must be a valid pointer.
+ * \param r_pose_factor: Optional, when set to NULL it won't be calculated.
+ */
void SCULPT_pose_calc_pose_data(struct Sculpt *sd,
struct Object *ob,
struct SculptSession *ss,
@@ -515,11 +597,17 @@ struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd,
void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain);
/* Boundary Brush. */
+
+/**
+ * Main function to get #SculptBoundary data both for brush deformation and viewport preview.
+ * Can return NULL if there is no boundary from the given vertex using the given radius.
+ */
struct SculptBoundary *SCULPT_boundary_data_init(Object *object,
Brush *brush,
const int initial_vertex,
const float radius);
void SCULPT_boundary_data_free(struct SculptBoundary *boundary);
+/* Main Brush Function. */
void SCULPT_do_boundary_brush(struct Sculpt *sd,
struct Object *ob,
struct PBVHNode **nodes,
@@ -532,6 +620,7 @@ void SCULPT_boundary_edges_preview_draw(const uint gpuattr,
void SCULPT_boundary_pivot_line_preview_draw(const uint gpuattr, struct SculptSession *ss);
/* Multi-plane Scrape Brush. */
+/* Main Brush Function. */
void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
Brush *brush,
@@ -548,13 +637,20 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
/* Smooth Brush. */
+
+/**
+ * For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure.
+ */
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index);
-/* Mask the mesh boundaries smoothing only the mesh surface without using automasking. */
+/**
+ * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking.
+ */
void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
void SCULPT_smooth(Sculpt *sd,
@@ -852,7 +948,13 @@ bool SCULPT_brush_test_cube(SculptBrushTest *test,
const float local[4][4],
const float roundness);
bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]);
+/**
+ * Test AABB against sphere.
+ */
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
+/**
+ * 2D projection (distance to line).
+ */
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
@@ -861,6 +963,9 @@ SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
char falloff_shape);
+/**
+ * Return a multiplier for brush strength on a particular vertex.
+ */
float SCULPT_brush_strength_factor(struct SculptSession *ss,
const struct Brush *br,
const float point[3],
@@ -871,15 +976,21 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss,
const int vertex_index,
const int thread_id);
-/* Tilts a normal by the x and y tilt values using the view axis. */
+/**
+ * Tilts a normal by the x and y tilt values using the view axis.
+ */
void SCULPT_tilt_apply_to_normal(float r_normal[3],
struct StrokeCache *cache,
const float tilt_strength);
-/* Get effective surface normal with pen tilt and tilt strength applied to it. */
+/**
+ * Get effective surface normal with pen tilt and tilt strength applied to it.
+ */
void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]);
-/* just for vertex paint. */
+/**
+ * Expose 'calc_area_normal' externally (just for vertex paint).
+ */
bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
Object *ob,
PBVHNode **nodes,
@@ -1085,6 +1196,7 @@ typedef enum SculptTransformDisplacementMode {
SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL = 1,
} SculptTransformDisplacementMode;
+/* Filter orientation utils. */
void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache);
void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache);
void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache);
@@ -1298,6 +1410,10 @@ typedef struct FilterCache {
AutomaskingCache *automasking;
} FilterCache;
+/**
+ * Flip all the edit-data across the axis/axes specified by \a symm.
+ * Used to calculate multiple modifications to the mesh when symmetry is enabled.
+ */
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
const char symm,
const char axis,
@@ -1313,8 +1429,14 @@ void SCULPT_undo_push_end_ex(const bool use_nested_undo);
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]);
+/**
+ * Copy the PBVH bounding box into the object's bounding box.
+ */
void SCULPT_update_object_bounding_box(struct Object *ob);
+/**
+ * Get a screen-space rectangle of the modified area.
+ */
bool SCULPT_get_redraw_rect(struct ARegion *region,
struct RegionView3D *rv3d,
Object *ob,
@@ -1323,10 +1445,12 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
/* Operators. */
/* Expand. */
+
void SCULPT_OT_expand(struct wmOperatorType *ot);
void sculpt_expand_modal_keymap(struct wmKeyConfig *keyconf);
/* Gestures. */
+
void SCULPT_OT_face_set_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot);
@@ -1336,6 +1460,7 @@ void SCULPT_OT_trim_box_gesture(struct wmOperatorType *ot);
void SCULPT_OT_project_line_gesture(struct wmOperatorType *ot);
/* Face Sets. */
+
void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
@@ -1343,32 +1468,41 @@ void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot);
/* Transform. */
+
void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);
/* Mesh Filter. */
+
void SCULPT_OT_mesh_filter(struct wmOperatorType *ot);
/* Cloth Filter. */
+
void SCULPT_OT_cloth_filter(struct wmOperatorType *ot);
/* Color Filter. */
+
void SCULPT_OT_color_filter(struct wmOperatorType *ot);
/* Mask filter and Dirty Mask. */
+
void SCULPT_OT_mask_filter(struct wmOperatorType *ot);
void SCULPT_OT_dirty_mask(struct wmOperatorType *ot);
/* Mask and Face Sets Expand. */
+
void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
/* Mask Init. */
+
void SCULPT_OT_mask_init(struct wmOperatorType *ot);
/* Detail size. */
+
void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot);
void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot);
/* Dyntopo. */
+
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index f78f30a2cfd..05db799cb00 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -229,7 +229,6 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
/* Public functions. */
-/* Main Brush Function. */
void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index 587ce346428..3b939279bf9 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -540,13 +540,6 @@ static bool pose_face_sets_floodfill_cb(
/* Public functions. */
-/**
- * Calculate the pose origin and (Optionally the pose factor)
- * that is used when using the pose brush.
- *
- * \param r_pose_origin: Must be a valid pointer.
- * \param r_pose_factor: Optional, when set to NULL it won't be calculated.
- */
void SCULPT_pose_calc_pose_data(Sculpt *sd,
Object *ob,
SculptSession *ss,
@@ -1132,7 +1125,6 @@ static void sculpt_pose_align_pivot_local_space(float r_mat[4][4],
ortho_basis_v3v3_v3(r_mat[0], r_mat[1], r_mat[2]);
}
-/* Main Brush Function. */
void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 1bfe8e1cbf1..847f42fe9e8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -102,8 +102,6 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3],
mul_v3_v3fl(result, avg, 1.0f / total);
}
-/* For bmesh: Average surrounding verts based on an orthogonality measure.
- * Naturally converges to a quad-like structure. */
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
{
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 501a1e53276..4a88b75cf25 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1598,7 +1598,6 @@ void ED_sculpt_undo_geometry_end(struct Object *ob)
SCULPT_undo_push_end();
}
-/* Export for ED_undo_sys. */
void ED_sculpt_undosys_type(UndoType *ut)
{
ut->name = "Sculpt";
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 9ff46d96207..daa973edfbf 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -70,8 +70,7 @@
/* ************************************************************************** */
/* ACTION CREATION */
-/* Helper function to find the active AnimData block from the Action Editor context */
-AnimData *ED_actedit_animdata_from_context(bContext *C, ID **r_adt_id_owner)
+AnimData *ED_actedit_animdata_from_context(const bContext *C, ID **r_adt_id_owner)
{
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
Object *ob = CTX_data_active_object(C);
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 6f1a90e56a5..0ed55ca5191 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -63,7 +63,6 @@
/* ************************************************************************* */
/* Channel List */
-/* left hand part */
void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
@@ -131,7 +130,54 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
/* extra padding for lengths (to go under scrollers) */
#define EXTRA_SCROLL_PAD 100.0f
-/* draw keyframes in each channel */
+/* Draw manually set intended playback frame ranges for actions. */
+static void draw_channel_action_ranges(bAnimContext *ac, ListBase *anim_data, View2D *v2d)
+{
+ /* Variables for coalescing the Y region of one action. */
+ bAction *cur_action = NULL;
+ AnimData *cur_adt = NULL;
+ float cur_ymax;
+
+ /* Walk through channels, grouping contiguous spans referencing the same action. */
+ float ymax = ACHANNEL_FIRST_TOP(ac) + ACHANNEL_SKIP / 2;
+ float ystep = ACHANNEL_STEP(ac);
+ float ymin = ymax - ystep;
+
+ for (bAnimListElem *ale = anim_data->first; ale; ale = ale->next, ymax = ymin, ymin -= ystep) {
+ bAction *action = NULL;
+ AnimData *adt = NULL;
+
+ /* check if visible */
+ if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
+ IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) {
+ /* check if anything to show for this channel */
+ if (ale->datatype != ALE_NONE) {
+ action = ANIM_channel_action_get(ale);
+
+ if (action) {
+ adt = ale->adt;
+ }
+ }
+ }
+
+ /* Extend the current region, or flush and restart. */
+ if (action != cur_action || adt != cur_adt) {
+ if (cur_action) {
+ ANIM_draw_action_framerange(cur_adt, cur_action, v2d, ymax, cur_ymax);
+ }
+
+ cur_action = action;
+ cur_adt = adt;
+ cur_ymax = ymax;
+ }
+ }
+
+ /* Flush the last region. */
+ if (cur_action) {
+ ANIM_draw_action_framerange(cur_adt, cur_action, v2d, ymax, cur_ymax);
+ }
+}
+
void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
@@ -166,6 +212,13 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
int height = ACHANNEL_TOT_HEIGHT(ac, items);
v2d->tot.ymin = -height;
+ /* Draw the manual frame ranges for actions in the background of the dopesheet.
+ * The action editor has already drawn the range for its action so it's not needed. */
+ if (ac->datatype == ANIMCONT_DOPESHEET) {
+ draw_channel_action_ranges(ac, &anim_data, v2d);
+ }
+
+ /* Draw the background strips. */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index ffe0606c98f..581356a89d0 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -41,7 +41,14 @@ void action_buttons_register(struct ARegionType *art);
/* ***************************************** */
/* action_draw.c */
+
+/**
+ * Left hand part.
+ */
void draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *region);
+/**
+ * Draw keyframes in each channel.
+ */
void draw_channel_strips(struct bAnimContext *ac,
struct SpaceAction *saction,
struct ARegion *region);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 738eeb21e2e..4463856f40a 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -25,6 +25,7 @@
#include <string.h>
#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -35,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_nla.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -204,6 +206,13 @@ static void action_main_region_draw(const bContext *C, ARegion *region)
/* start and end frame */
ANIM_draw_framerange(scene, v2d);
+ /* Draw the manually set intended playback frame range highlight in the Action editor. */
+ if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && saction->action) {
+ AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
+
+ ANIM_draw_action_framerange(adt, saction->action, v2d, -FLT_MAX, FLT_MAX);
+ }
+
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
draw_channel_strips(&ac, saction, region);
@@ -853,7 +862,6 @@ static void action_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_action(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype action");
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 149067a94fe..035bc7e297d 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -70,7 +70,6 @@
#include "io_ops.h"
-/* Only called once on startup. storage is global in BKE kernel listbase. */
void ED_spacetypes_init(void)
{
/* UI unit is a variable, may be used in some space type inits. */
@@ -186,10 +185,6 @@ void ED_spacemacros_init(void)
}
}
-/**
- * \note Keymap definitions are registered only once per WM initialize,
- * usually on file read, using the keymap the actual areas/regions add the handlers.
- * \note Called in wm.c. */
void ED_spacetypes_keymap(wmKeyConfig *keyconf)
{
ED_keymap_screen(keyconf);
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 9cb363ff0c9..5eddea2cc40 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -88,6 +88,7 @@ typedef struct ButsContextTexture {
/* internal exports only */
/* buttons_context.c */
+
void buttons_context_compute(const struct bContext *C, struct SpaceProperties *sbuts);
int buttons_context(const struct bContext *C,
const char *member,
@@ -98,12 +99,17 @@ struct ID *buttons_context_id_path(const struct bContext *C);
extern const char *buttons_context_dir[]; /* doc access */
/* buttons_texture.c */
+
void buttons_texture_context_compute(const struct bContext *C, struct SpaceProperties *sbuts);
/* buttons_ops.c */
+
void BUTTONS_OT_start_filter(struct wmOperatorType *ot);
void BUTTONS_OT_clear_filter(struct wmOperatorType *ot);
void BUTTONS_OT_toggle_pin(struct wmOperatorType *ot);
void BUTTONS_OT_file_browse(struct wmOperatorType *ot);
+/**
+ * Second operator, only difference from #BUTTONS_OT_file_browse is #WM_FILESEL_DIRECTORY.
+ */
void BUTTONS_OT_directory_browse(struct wmOperatorType *ot);
void BUTTONS_OT_context_menu(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 798f4898aaa..46d6df7c69c 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -383,7 +383,6 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
FILE_SORT_DEFAULT);
}
-/* Second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY. */
void BUTTONS_OT_directory_browse(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index f1debcef5a9..554edf680be 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -667,7 +667,6 @@ static void template_texture_show(bContext *C, void *data_p, void *prop_p)
}
}
-/* Button to quickly show texture in Properties Editor texture tab. */
void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop)
{
/* Only show the button if there is actually a texture assigned. */
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index b04291b7ab4..007a9105c76 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -166,11 +166,6 @@ static void buttons_main_region_init(wmWindowManager *wm, ARegion *region)
/** \name Property Editor Layout
* \{ */
-/**
- * Fills an array with the tab context values for the properties editor. -1 signals a separator.
- *
- * \return The total number of items in the array returned.
- */
int ED_buttons_tabs_list(SpaceProperties *sbuts, short *context_tabs_array)
{
int length = 0;
@@ -445,7 +440,7 @@ static void property_search_all_tabs(const bContext *C,
i,
property_search_for_context(C, region_copy, &sbuts_copy));
- UI_blocklist_free(C, &region_copy->uiblocks);
+ UI_blocklist_free(C, region_copy);
}
BKE_area_region_free(area_copy.type, region_copy);
@@ -924,7 +919,6 @@ static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id
/** \name Space Type Initialization
* \{ */
-/* only called once, from space/spacetypes.c */
void ED_spacetype_buttons(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype buttons");
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 4bccb3664da..68444cc0313 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -1981,7 +1981,6 @@ void clip_draw_cache_and_notes(const bContext *C, SpaceClip *sc, ARegion *region
}
}
-/* draw grease pencil */
void clip_draw_grease_pencil(bContext *C, int onlyv2d)
{
SpaceClip *sc = CTX_wm_space_clip(C);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 834ef847069..5a999b1fad7 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -223,7 +223,6 @@ void ED_space_clip_get_aspect_dimension_aware(SpaceClip *sc, float *aspx, float
}
}
-/* return current frame number in clip space */
int ED_space_clip_get_clip_frame_number(SpaceClip *sc)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -272,7 +271,7 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale
}
bool ED_space_clip_get_position(struct SpaceClip *sc,
- struct ARegion *ar,
+ struct ARegion *region,
int mval[2],
float fpos[2])
{
@@ -282,13 +281,12 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
}
/* map the mouse coords to the backdrop image space */
- ED_clip_mouse_pos(sc, ar, mval, fpos);
+ ED_clip_mouse_pos(sc, region, mval, fpos);
IMB_freeImBuf(ibuf);
return true;
}
-/* Returns color in linear space, matching ED_space_image_color_sample(). */
bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
{
ImBuf *ibuf;
@@ -511,10 +509,6 @@ void ED_clip_point_stable_pos(
}
}
-/**
- * \brief the reverse of #ED_clip_point_stable_pos(), gets the marker region coords.
- * better name here? view_to_track / track_to_view or so?
- */
void ED_clip_point_stable_pos__reverse(SpaceClip *sc,
ARegion *region,
const float co[2],
@@ -539,7 +533,6 @@ void ED_clip_point_stable_pos__reverse(SpaceClip *sc,
r_co[1] = (pos[1] * height * zoomy) + (float)sy;
}
-/* takes event->mval */
void ED_clip_mouse_pos(SpaceClip *sc, ARegion *region, const int mval[2], float co[2])
{
ED_clip_point_stable_pos(sc, region, mval[0], mval[1], &co[0], &co[1]);
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 202dc00e365..20cc6e3da15 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -50,25 +50,34 @@ struct wmOperatorType;
/* internal exports only */
/* clip_buttons.c */
+
void ED_clip_buttons_register(struct ARegionType *art);
/* clip_dopesheet_draw.c */
+
void clip_draw_dopesheet_main(struct SpaceClip *sc, struct ARegion *region, struct Scene *scene);
void clip_draw_dopesheet_channels(const struct bContext *C, struct ARegion *region);
/* clip_dopesheet_ops.c */
+
void CLIP_OT_dopesheet_select_channel(struct wmOperatorType *ot);
void CLIP_OT_dopesheet_view_all(struct wmOperatorType *ot);
/* clip_draw.c */
+
void clip_draw_main(const struct bContext *C, struct SpaceClip *sc, struct ARegion *region);
+
+/* draw grease pencil */
+
void clip_draw_grease_pencil(struct bContext *C, int onlyv2d);
void clip_draw_cache_and_notes(const bContext *C, SpaceClip *sc, ARegion *region);
/* clip_editor.c */
+
void clip_start_prefetch_job(const struct bContext *C);
/* clip_graph_draw.c */
+
void clip_draw_graph(struct SpaceClip *sc, struct ARegion *region, struct Scene *scene);
/* clip_graph_ops.c */
@@ -171,6 +180,9 @@ void clip_delete_plane_track(struct bContext *C,
struct MovieClip *clip,
struct MovieTrackingPlaneTrack *plane_track);
+/**
+ * Calculate space clip offset to be centered at the given point.
+ */
void clip_view_offset_for_center_to_point(
SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y);
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
@@ -178,6 +190,10 @@ void clip_view_center_to_point(SpaceClip *sc, float x, float y);
bool clip_view_calculate_view_selection(
const struct bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom);
+/**
+ * Returns truth if lock-to-selection is enabled and possible.
+ * Locking to selection is not possible if there is no selection.
+ */
bool clip_view_has_locked_selection(const struct bContext *C);
void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index b1f8949871b..0aa7e35aed6 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -209,7 +209,7 @@ static int open_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "directory", dir_only);
if (relative) {
- BLI_path_rel(dir_only, bmain->name);
+ BLI_path_rel(dir_only, bmain->filepath);
}
prop = RNA_struct_find_property(op->ptr, "files");
@@ -285,7 +285,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
if (clip) {
BLI_strncpy(path, clip->filepath, sizeof(path));
- BLI_path_abs(path, CTX_data_main(C)->name);
+ BLI_path_abs(path, CTX_data_main(C)->filepath);
BLI_path_parent_dir(path);
}
else {
@@ -911,6 +911,7 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
-FLT_MAX,
FLT_MAX);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -988,6 +989,7 @@ void CLIP_OT_view_all(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1052,6 +1054,7 @@ void CLIP_OT_view_selected(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1172,6 +1175,7 @@ void CLIP_OT_change_frame(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1584,6 +1588,7 @@ void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1623,10 +1628,10 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
}
-#ifdef WITH_INPUT_NDOF
-
/** \} */
+#ifdef WITH_INPUT_NDOF
+
/* -------------------------------------------------------------------- */
/** \name NDOF Operator
* \{ */
@@ -1725,6 +1730,7 @@ void CLIP_OT_prefetch(wmOperatorType *ot)
ot->invoke = clip_prefetch_invoke;
ot->modal = clip_prefetch_modal;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1764,6 +1770,7 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
ot->exec = clip_set_scene_frames_exec;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 23dd290e13f..5f5a24a9407 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -398,7 +398,6 @@ void clip_delete_plane_track(bContext *C, MovieClip *clip, MovieTrackingPlaneTra
DEG_id_tag_update(&clip->id, 0);
}
-/* Calculate space clip offset to be centered at the given point. */
void clip_view_offset_for_center_to_point(
SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y)
{
@@ -608,8 +607,6 @@ bool clip_view_calculate_view_selection(
return true;
}
-/* Returns truth if lock-to-selection is enabled and possible.
- * Locking to selection is not possible if there is no selection. */
bool clip_view_has_locked_selection(const bContext *C)
{
SpaceClip *space_clip = CTX_wm_space_clip(C);
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index e2fbb4a5a59..91083fa9682 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -1335,7 +1335,6 @@ static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_clip(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype clip");
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 84be24e96ac..e66c3898d04 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -293,7 +293,6 @@ static void console_main_region_listener(const wmRegionListenerParams *params)
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_console(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype console");
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 4b508f16c1e..1651269869e 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -17,6 +17,7 @@
set(INC
../include
+ ../asset
../../blenfont
../../blenkernel
../../blenlib
@@ -36,6 +37,7 @@ set(INC
set(SRC
asset_catalog_tree_view.cc
file_draw.c
+ file_indexer.cc
file_ops.c
file_panels.c
file_utils.c
@@ -44,6 +46,7 @@ set(SRC
fsmenu.c
space_file.c
+ file_indexer.h
file_intern.h
filelist.h
fsmenu.h
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 41559278910..86c4b78dea4 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -33,6 +33,7 @@
#include "ED_asset.h"
#include "ED_fileselect.h"
+#include "ED_undo.h"
#include "RNA_access.h"
@@ -52,6 +53,8 @@ using namespace blender::bke;
namespace blender::ed::asset_browser {
+class AssetCatalogTreeViewAllItem;
+
class AssetCatalogTreeView : public ui::AbstractTreeView {
::AssetLibrary *asset_library_;
/** The asset catalog tree this tree-view represents. */
@@ -61,6 +64,7 @@ class AssetCatalogTreeView : public ui::AbstractTreeView {
friend class AssetCatalogTreeViewItem;
friend class AssetCatalogDropController;
+ friend class AssetCatalogTreeViewAllItem;
public:
AssetCatalogTreeView(::AssetLibrary *library,
@@ -69,11 +73,13 @@ class AssetCatalogTreeView : public ui::AbstractTreeView {
void build_tree() override;
+ void activate_catalog_by_id(CatalogID catalog_id);
+
private:
- ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewItemContainer &view_parent_item,
+ ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewOrItem &view_parent_item,
AssetCatalogTreeItem &catalog);
- void add_all_item();
+ AssetCatalogTreeViewAllItem &add_all_item();
void add_unassigned_item();
bool is_active_catalog(CatalogID catalog_id) const;
};
@@ -92,7 +98,7 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
void build_row(uiLayout &row) override;
void build_context_menu(bContext &C, uiLayout &column) const override;
- bool can_rename() const override;
+ bool supports_renaming() const override;
bool rename(StringRefNull new_name) override;
/** Add drag support for catalog items. */
@@ -105,10 +111,12 @@ class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController
AssetCatalogTreeItem &catalog_item_;
public:
- explicit AssetCatalogDragController(AssetCatalogTreeItem &catalog_item);
+ explicit AssetCatalogDragController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item);
int get_drag_type() const override;
void *create_drag_data() const override;
+ void on_drag_start() override;
};
class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController {
@@ -119,19 +127,26 @@ class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
std::string drop_tooltip(const wmDrag &drag) const override;
- bool on_drop(const wmDrag &drag) override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
::AssetLibrary &get_asset_library() const;
- AssetCatalog *get_drag_catalog(const wmDrag &drag) const;
+ static AssetCatalog *get_drag_catalog(const wmDrag &drag, const ::AssetLibrary &asset_library);
static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint);
- static bool drop_assets_into_catalog(const AssetCatalogTreeView &tree_view,
+ static bool drop_assets_into_catalog(struct bContext *C,
+ const AssetCatalogTreeView &tree_view,
const wmDrag &drag,
CatalogID catalog_id,
StringRefNull simple_name = "");
+ /**
+ * \param drop_catalog_id: Can be unset to drop into the root level of the tree.
+ */
+ static bool drop_asset_catalog_into_catalog(
+ const wmDrag &drag,
+ AssetCatalogTreeView &tree_view,
+ const std::optional<CatalogID> drop_catalog_id = std::nullopt);
private:
- bool drop_asset_catalog_into_catalog(const wmDrag &drag);
std::string drop_tooltip_asset_list(const wmDrag &drag) const;
std::string drop_tooltip_asset_catalog(const wmDrag &drag) const;
};
@@ -142,6 +157,16 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
void build_row(uiLayout &row) override;
+
+ struct DropController : public ui::AbstractTreeViewItemDropController {
+ DropController(AssetCatalogTreeView &tree_view);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
+ };
+
+ std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
};
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
@@ -152,7 +177,7 @@ class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
std::string drop_tooltip(const wmDrag &drag) const override;
- bool on_drop(const wmDrag &drag) override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
@@ -172,14 +197,13 @@ AssetCatalogTreeView::AssetCatalogTreeView(::AssetLibrary *library,
void AssetCatalogTreeView::build_tree()
{
- add_all_item();
+ AssetCatalogTreeViewAllItem &all_item = add_all_item();
+ all_item.set_collapsed(false);
if (catalog_tree_) {
- catalog_tree_->foreach_root_item([this](AssetCatalogTreeItem &item) {
- ui::BasicTreeViewItem &child_view_item = build_catalog_items_recursive(*this, item);
-
- /* Open root-level items by default. */
- child_view_item.set_collapsed(false);
+ /* Pass the "All" item on as parent of the actual catalog items. */
+ catalog_tree_->foreach_root_item([this, &all_item](AssetCatalogTreeItem &item) {
+ build_catalog_items_recursive(all_item, item);
});
}
@@ -187,11 +211,12 @@ void AssetCatalogTreeView::build_tree()
}
ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
- ui::TreeViewItemContainer &view_parent_item, AssetCatalogTreeItem &catalog)
+ ui::TreeViewOrItem &view_parent_item, AssetCatalogTreeItem &catalog)
{
ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>(
&catalog);
- view_item.is_active([this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
+ view_item.set_is_active_fn(
+ [this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) {
build_catalog_items_recursive(view_item, child);
@@ -199,18 +224,18 @@ ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
return view_item;
}
-void AssetCatalogTreeView::add_all_item()
+AssetCatalogTreeViewAllItem &AssetCatalogTreeView::add_all_item()
{
FileAssetSelectParams *params = params_;
- AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"),
- ICON_HOME);
- item.on_activate([params](ui::BasicTreeViewItem & /*item*/) {
+ AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"));
+ item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
});
- item.is_active(
+ item.set_is_active_fn(
[params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; });
+ return item;
}
void AssetCatalogTreeView::add_unassigned_item()
@@ -220,14 +245,21 @@ void AssetCatalogTreeView::add_unassigned_item()
AssetCatalogTreeViewUnassignedItem &item = add_tree_item<AssetCatalogTreeViewUnassignedItem>(
IFACE_("Unassigned"), ICON_FILE_HIDDEN);
- item.on_activate([params](ui::BasicTreeViewItem & /*item*/) {
+ item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
});
- item.is_active(
+ item.set_is_active_fn(
[params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; });
}
+void AssetCatalogTreeView::activate_catalog_by_id(CatalogID catalog_id)
+{
+ params_->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
+ params_->catalog_id = catalog_id;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+}
+
bool AssetCatalogTreeView::is_active_catalog(CatalogID catalog_id) const
{
return (params_->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG) &&
@@ -243,11 +275,8 @@ AssetCatalogTreeViewItem::AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog
void AssetCatalogTreeViewItem::on_activate()
{
- const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
- get_tree_view());
- tree_view.params_->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
- tree_view.params_->catalog_id = catalog_item_.get_catalog_id();
- WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ AssetCatalogTreeView &tree_view = static_cast<AssetCatalogTreeView &>(get_tree_view());
+ tree_view.activate_catalog_by_id(catalog_item_.get_catalog_id());
}
void AssetCatalogTreeViewItem::build_row(uiLayout &row)
@@ -304,7 +333,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
UI_menutype_draw(&C, mt, &column);
}
-bool AssetCatalogTreeViewItem::can_rename() const
+bool AssetCatalogTreeViewItem::supports_renaming() const
{
return true;
}
@@ -330,7 +359,8 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem
std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem::
create_drag_controller() const
{
- return std::make_unique<AssetCatalogDragController>(catalog_item_);
+ return std::make_unique<AssetCatalogDragController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
}
/* ---------------------------------------------------------------------- */
@@ -344,14 +374,18 @@ AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tre
bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_disabled_hint) const
{
if (drag.type == WM_DRAG_ASSET_CATALOG) {
- const AssetCatalog *drag_catalog = get_drag_catalog(drag);
- /* Note: Technically it's not an issue to allow this (the catalog will just receive a new
+ const AssetCatalog *drag_catalog = get_drag_catalog(drag, get_asset_library());
+ /* NOTE: Technically it's not an issue to allow this (the catalog will just receive a new
* path and the catalog system will generate missing parents from the path). But it does
* appear broken to users, so disabling entirely. */
if (catalog_item_.catalog_path().is_contained_in(drag_catalog->path)) {
*r_disabled_hint = "Catalog cannot be dropped into itself";
return false;
}
+ if (catalog_item_.catalog_path() == drag_catalog->path.parent()) {
+ *r_disabled_hint = "Catalog is already placed inside this catalog";
+ return false;
+ }
return true;
}
if (drag.type == WM_DRAG_ASSET_LIST) {
@@ -371,7 +405,7 @@ std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const
std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag &drag) const
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
- const AssetCatalog *src_catalog = get_drag_catalog(drag);
+ const AssetCatalog *src_catalog = get_drag_catalog(drag, get_asset_library());
return std::string(TIP_("Move Catalog")) + " '" + src_catalog->path.name() + "' " +
TIP_("into") + " '" + catalog_item_.get_name() + "'";
@@ -393,29 +427,35 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr
")";
}
-bool AssetCatalogDropController::on_drop(const wmDrag &drag)
+bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag)
{
if (drag.type == WM_DRAG_ASSET_CATALOG) {
- return drop_asset_catalog_into_catalog(drag);
+ return drop_asset_catalog_into_catalog(
+ drag, tree_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
}
- return drop_assets_into_catalog(tree_view<AssetCatalogTreeView>(),
+ return drop_assets_into_catalog(C,
+ tree_view<AssetCatalogTreeView>(),
drag,
catalog_item_.get_catalog_id(),
catalog_item_.get_simple_name());
}
-bool AssetCatalogDropController::drop_asset_catalog_into_catalog(const wmDrag &drag)
+bool AssetCatalogDropController::drop_asset_catalog_into_catalog(
+ const wmDrag &drag,
+ AssetCatalogTreeView &tree_view,
+ const std::optional<CatalogID> drop_catalog_id)
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
- ED_asset_catalog_move(
- &get_asset_library(), catalog_drag->drag_catalog_id, catalog_item_.get_catalog_id());
+ ED_asset_catalog_move(tree_view.asset_library_, catalog_drag->drag_catalog_id, drop_catalog_id);
+ tree_view.activate_catalog_by_id(catalog_drag->drag_catalog_id);
WM_main_add_notifier(NC_ASSET | ND_ASSET_CATALOGS, nullptr);
return true;
}
-bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTreeView &tree_view,
+bool AssetCatalogDropController::drop_assets_into_catalog(struct bContext *C,
+ const AssetCatalogTreeView &tree_view,
const wmDrag &drag,
CatalogID catalog_id,
StringRefNull simple_name)
@@ -426,11 +466,14 @@ bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTree
return false;
}
+ bool did_update = false;
LISTBASE_FOREACH (wmDragAssetListItem *, asset_item, asset_drags) {
if (asset_item->is_external) {
/* Only internal assets can be modified! */
continue;
}
+
+ did_update = true;
BKE_asset_metadata_catalog_id_set(
asset_item->asset_data.local_id->asset_data, catalog_id, simple_name.c_str());
@@ -440,16 +483,20 @@ bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTree
WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, nullptr);
}
+ if (did_update) {
+ ED_undo_push(C, "Assign Asset Catalog");
+ }
return true;
}
-AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag) const
+AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag,
+ const ::AssetLibrary &asset_library)
{
if (drag.type != WM_DRAG_ASSET_CATALOG) {
return nullptr;
}
const bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
- &get_asset_library());
+ &asset_library);
const wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
return catalog_service->find_catalog(catalog_drag->drag_catalog_id);
@@ -468,7 +515,7 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
}
}
- *r_disabled_hint = "Only assets from this current file can be moved between catalogs";
+ *r_disabled_hint = TIP_("Only assets from this current file can be moved between catalogs");
return false;
}
@@ -479,8 +526,9 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
/* ---------------------------------------------------------------------- */
-AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeItem &catalog_item)
- : catalog_item_(catalog_item)
+AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item)
+ : ui::AbstractTreeViewItemDragController(tree_view), catalog_item_(catalog_item)
{
}
@@ -497,6 +545,12 @@ void *AssetCatalogDragController::create_drag_data() const
return drag_catalog;
}
+void AssetCatalogDragController::on_drag_start()
+{
+ AssetCatalogTreeView &tree_view_ = tree_view<AssetCatalogTreeView>();
+ tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
+}
+
/* ---------------------------------------------------------------------- */
void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
@@ -514,6 +568,56 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
RNA_string_set(props, "parent_path", nullptr);
}
+std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllItem::
+ create_drop_controller() const
+{
+ return std::make_unique<AssetCatalogTreeViewAllItem::DropController>(
+ static_cast<AssetCatalogTreeView &>(get_tree_view()));
+}
+
+AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view)
+ : ui::AbstractTreeViewItemDropController(tree_view)
+{
+}
+
+bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag,
+ const char **r_disabled_hint) const
+{
+ if (drag.type != WM_DRAG_ASSET_CATALOG) {
+ return false;
+ }
+
+ const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
+ drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ if (drag_catalog->path.parent() == "") {
+ *r_disabled_hint = "Catalog is already placed at the highest level";
+ return false;
+ }
+
+ return true;
+}
+
+std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
+ drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+
+ return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " +
+ TIP_("to the top level of the tree");
+}
+
+bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext *UNUSED(C),
+ const wmDrag &drag)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ return AssetCatalogDropController::drop_asset_catalog_into_catalog(
+ drag,
+ tree_view<AssetCatalogTreeView>(),
+ /* No value to drop into the root level. */
+ std::nullopt);
+}
+
/* ---------------------------------------------------------------------- */
std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem::
@@ -547,11 +651,12 @@ std::string AssetCatalogTreeViewUnassignedItem::DropController::drop_tooltip(
TIP_("Move asset out of any catalog");
}
-bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(const wmDrag &drag)
+bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext *C,
+ const wmDrag &drag)
{
/* Assign to nil catalog ID. */
return AssetCatalogDropController::drop_assets_into_catalog(
- tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
+ C, tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
}
} // namespace blender::ed::asset_browser
@@ -586,10 +691,6 @@ void file_delete_asset_catalog_filter_settings(
OBJECT_GUARDED_SAFE_DELETE(*filter_settings, AssetCatalogFilterSettings);
}
-/**
- * \return True if the file list should update its filtered results (e.g. because filtering
- * parameters changed).
- */
bool file_set_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index e393cc41a86..44e9735866d 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -479,7 +479,7 @@ static void file_draw_preview(const SpaceFile *sfile,
const uchar light[4] = {255, 255, 255, 255};
icon_x = xco + ex - UI_UNIT_X;
icon_y = yco + ey - UI_UNIT_Y;
- UI_icon_draw_ex(icon_x, icon_y, ICON_FILE_BLEND, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
/* Contrasting outline around some preview types. */
@@ -1132,10 +1132,6 @@ static void file_draw_invalid_library_hint(const bContext *C,
}
}
-/**
- * Draw a string hint if the file list is invalid.
- * \return true if the list is invalid and a hint was drawn.
- */
bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region)
{
FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
diff --git a/source/blender/editors/space_file/file_indexer.cc b/source/blender/editors/space_file/file_indexer.cc
new file mode 100644
index 00000000000..95e0afd7a1e
--- /dev/null
+++ b/source/blender/editors/space_file/file_indexer.cc
@@ -0,0 +1,96 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edfile
+ *
+ * This file implements the default file browser indexer and has some helper function to work with
+ * `FileIndexerEntries`.
+ */
+#include "file_indexer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+namespace blender::ed::file::indexer {
+
+static eFileIndexerResult read_index(const char *UNUSED(file_name),
+ FileIndexerEntries *UNUSED(entries),
+ int *UNUSED(r_read_entries_len),
+ void *UNUSED(user_data))
+{
+ return FILE_INDEXER_NEEDS_UPDATE;
+}
+
+static void update_index(const char *UNUSED(file_name),
+ FileIndexerEntries *UNUSED(entries),
+ void *UNUSED(user_data))
+{
+}
+
+constexpr FileIndexerType default_indexer()
+{
+ FileIndexerType indexer = {nullptr};
+ indexer.read_index = read_index;
+ indexer.update_index = update_index;
+ return indexer;
+}
+
+static FileIndexerEntry *file_indexer_entry_create_from_datablock_info(
+ const BLODataBlockInfo *datablock_info, const int idcode)
+{
+ FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
+ MEM_mallocN(sizeof(FileIndexerEntry), __func__));
+ entry->datablock_info = *datablock_info;
+ entry->idcode = idcode;
+ return entry;
+}
+
+} // namespace blender::ed::file::indexer
+
+extern "C" {
+
+void ED_file_indexer_entries_extend_from_datablock_infos(
+ FileIndexerEntries *indexer_entries,
+ const LinkNode * /* BLODataBlockInfo */ datablock_infos,
+ const int idcode)
+{
+ for (const LinkNode *ln = datablock_infos; ln; ln = ln->next) {
+ const BLODataBlockInfo *datablock_info = static_cast<const BLODataBlockInfo *>(ln->link);
+ FileIndexerEntry *file_indexer_entry =
+ blender::ed::file::indexer::file_indexer_entry_create_from_datablock_info(datablock_info,
+ idcode);
+ BLI_linklist_prepend(&indexer_entries->entries, file_indexer_entry);
+ }
+}
+
+static void ED_file_indexer_entry_free(void *indexer_entry)
+{
+ MEM_freeN(indexer_entry);
+}
+
+void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries)
+{
+ BLI_linklist_free(indexer_entries->entries, ED_file_indexer_entry_free);
+ indexer_entries->entries = nullptr;
+}
+
+const FileIndexerType file_indexer_noop = blender::ed::file::indexer::default_indexer();
+}
diff --git a/source/blender/blenkernel/intern/extern_implementations.cc b/source/blender/editors/space_file/file_indexer.h
index 07a4b6fc455..ea42f10498b 100644
--- a/source/blender/blenkernel/intern/extern_implementations.cc
+++ b/source/blender/editors/space_file/file_indexer.h
@@ -14,14 +14,23 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "BKE_attribute_access.hh"
+/** \file
+ * \ingroup edfile
+ */
+#pragma once
+
+#include "ED_file_indexer.h"
-namespace blender::bke {
+#ifdef __cplusplus
+extern "C" {
+#endif
-template class OutputAttribute_Typed<float>;
-template class OutputAttribute_Typed<int>;
-template class OutputAttribute_Typed<float3>;
-template class OutputAttribute_Typed<bool>;
-template class OutputAttribute_Typed<ColorGeometry4f>;
+/**
+ * Default indexer to use when listing files. The implementation is a no-operation indexing. When
+ * set it won't use indexing. It is added to increase the code clarity.
+ */
+extern const FileIndexerType file_indexer_noop;
-} // namespace blender::bke
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 4be5d6d8008..3fe48157a09 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -41,20 +41,30 @@ struct uiLayout;
struct View2D;
/* file_draw.c */
+
#define ATTRIBUTE_COLUMN_PADDING (0.5f * UI_UNIT_X)
-#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */
+/** Related to #FileSelectParams.thumbnail_size. */
+#define SMALL_SIZE_CHECK(_size) ((_size) < 64)
void file_calc_previews(const bContext *C, ARegion *region);
void file_draw_list(const bContext *C, ARegion *region);
+/**
+ * Draw a string hint if the file list is invalid.
+ * \return true if the list is invalid and a hint was drawn.
+ */
bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region);
void file_draw_check_ex(bContext *C, struct ScrArea *area);
void file_draw_check(bContext *C);
+/**
+ * For use with; #UI_block_func_set.
+ */
void file_draw_check_cb(bContext *C, void *arg1, void *arg2);
bool file_draw_check_exists(SpaceFile *sfile);
/* file_ops.h */
+
struct wmOperator;
struct wmOperatorType;
@@ -72,6 +82,10 @@ void FILE_OT_bookmark_move(struct wmOperatorType *ot);
void FILE_OT_reset_recent(wmOperatorType *ot);
void FILE_OT_hidedot(struct wmOperatorType *ot);
void FILE_OT_execute(struct wmOperatorType *ot);
+/**
+ * Variation of #FILE_OT_execute that accounts for some mouse specific handling.
+ * Otherwise calls the same logic.
+ */
void FILE_OT_mouse_execute(struct wmOperatorType *ot);
void FILE_OT_cancel(struct wmOperatorType *ot);
void FILE_OT_parent(struct wmOperatorType *ot);
@@ -79,7 +93,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot);
void FILE_OT_previous(struct wmOperatorType *ot);
void FILE_OT_next(struct wmOperatorType *ot);
void FILE_OT_refresh(struct wmOperatorType *ot);
-void FILE_OT_asset_library_refresh(struct wmOperatorType *ot);
void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
@@ -93,6 +106,9 @@ void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but);
int file_highlight_set(struct SpaceFile *sfile, struct ARegion *region, int mx, int my);
+/**
+ * Use to set the file selector path from some arbitrary source.
+ */
void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath);
void file_sfile_to_operator_ex(struct Main *bmain,
struct wmOperator *op,
@@ -103,17 +119,28 @@ void file_sfile_to_operator(struct Main *bmain, struct wmOperator *op, struct Sp
void file_operator_to_sfile(struct Main *bmain, struct SpaceFile *sfile, struct wmOperator *op);
/* space_file.c */
+
extern const char *file_context_dir[]; /* doc access */
/* filesel.c */
+
void fileselect_refresh_params(struct SpaceFile *sfile);
+/**
+ * Sets #FileSelectParams.file (name of selected file)
+ */
void fileselect_file_set(SpaceFile *sfile, const int index);
bool file_attribute_column_type_enabled(const FileSelectParams *params,
FileAttributeColumnType column);
+/**
+ * Check if the region coordinate defined by \a x and \a y are inside the column header.
+ */
bool file_attribute_column_header_is_inside(const struct View2D *v2d,
const FileLayout *layout,
int x,
int y);
+/**
+ * Find the column type at region coordinate given by \a x (y doesn't matter for this).
+ */
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
const FileSelectParams *params,
FileLayout *layout,
@@ -130,13 +157,26 @@ void file_params_smoothscroll_timer_clear(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile);
void file_params_renamefile_clear(struct FileSelectParams *params);
+/**
+ * Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll
+ * timer. To be used right after a file was renamed.
+ * Note that the caller is responsible for setting the correct rename-file info
+ * (#FileSelectParams.renamefile or #FileSelectParams.rename_id).
+ */
void file_params_invoke_rename_postscroll(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile);
+/**
+ * To be executed whenever renaming ends (successfully or not).
+ */
void file_params_rename_end(struct wmWindowManager *wm,
struct wmWindow *win,
SpaceFile *sfile,
struct FileDirEntry *rename_file);
+/**
+ * Helper used by both main update code, and smooth-scroll timer,
+ * to try to enable rename editing from #FileSelectParams.renamefile name.
+ */
void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params);
typedef void *onReloadFnData;
@@ -148,20 +188,27 @@ typedef struct SpaceFile_Runtime {
onReloadFnData on_reload_custom_data;
} SpaceFile_Runtime;
-/* Register an on-reload callback function. Note that there can only be one such function at a
- * time; registering a new one will overwrite the previous one. */
+/**
+ * Register an on-reload callback function. Note that there can only be one such function at a
+ * time; registering a new one will overwrite the previous one.
+ */
void file_on_reload_callback_register(struct SpaceFile *sfile,
onReloadFn callback,
onReloadFnData custom_data);
/* file_panels.c */
+
void file_tool_props_region_panels_register(struct ARegionType *art);
void file_execute_region_panels_register(struct ARegionType *art);
void file_tools_region_panels_register(struct ARegionType *art);
/* file_utils.c */
+
void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int file, rcti *r_bounds);
+/**
+ * If \a path leads to a .blend, remove the trailing slash (if needed).
+ */
void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
/* asset_catalog_tree_view.cc */
@@ -173,7 +220,8 @@ FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings(
void file_delete_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle **filter_settings_handle);
/**
- * \return True if the stored filter settings were modified.
+ * \return True if the file list should update its filtered results
+ * (e.g. because filtering parameters changed).
*/
bool file_set_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 844514759f3..8178e54e023 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -211,6 +211,11 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
filelist_setrecursion(sfile->files, params->recursion_level);
}
}
+ else if (file->redirection_path) {
+ BLI_strncpy(params->dir, file->redirection_path, sizeof(params->dir));
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
+ BLI_path_slash_ensure(params->dir);
+ }
else {
BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
strcat(params->dir, file->relpath);
@@ -1413,8 +1418,13 @@ int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
return 0;
}
- numfiles = filelist_files_ensure(sfile->files);
params = ED_fileselect_get_active_params(sfile);
+ /* In case #SpaceFile.browse_mode just changed, the area may be pending a refresh still, which is
+ * what creates the params for the current browse mode. See T93508. */
+ if (!params) {
+ return false;
+ }
+ numfiles = filelist_files_ensure(sfile->files);
origfile = params->highlight_file;
@@ -1684,9 +1694,6 @@ void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op)
/* XXX, files and dirs updates missing, not really so important though */
}
-/**
- * Use to set the file selector path from some arbitrary source.
- */
void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
@@ -1736,7 +1743,6 @@ void file_draw_check(bContext *C)
file_draw_check_ex(C, area);
}
-/* for use with; UI_block_func_set */
void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
{
file_draw_check(C);
@@ -1897,10 +1903,6 @@ static int file_execute_mouse_invoke(bContext *C, wmOperator *UNUSED(op), const
return OPERATOR_FINISHED;
}
-/**
- * Variation of #FILE_OT_execute that accounts for some mouse specific handling. Otherwise calls
- * the same logic.
- */
void FILE_OT_mouse_execute(wmOperatorType *ot)
{
/* identifiers */
@@ -1956,35 +1958,6 @@ void FILE_OT_refresh(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Refresh Asset Library Operator
- * \{ */
-
-static int file_asset_library_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- SpaceFile *sfile = CTX_wm_space_file(C);
-
- ED_fileselect_clear(wm, sfile);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void FILE_OT_asset_library_refresh(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Refresh Asset Library";
- ot->description = "Reread assets and asset catalogs from the asset library on disk";
- ot->idname = "FILE_OT_asset_library_refresh";
-
- /* api callbacks */
- ot->exec = file_asset_library_refresh_exec;
- ot->poll = ED_operator_asset_browsing_active;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Navigate Parent Operator
* \{ */
@@ -2490,9 +2463,10 @@ static void file_expand_directory(bContext *C)
if (params) {
if (BLI_path_is_rel(params->dir)) {
/* Use of 'default' folder here is just to avoid an error message on '//' prefix. */
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
BLI_path_abs(params->dir,
- G.relbase_valid ? BKE_main_blendfile_path(bmain) :
- BKE_appdir_folder_default_or_root());
+ (blendfile_path[0] != '\0') ? blendfile_path :
+ BKE_appdir_folder_default_or_root());
}
else if (params->dir[0] == '~') {
char tmpstr[sizeof(params->dir) - 1];
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 0e468718a04..7da9f65a1a2 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -41,6 +41,7 @@
#include "ED_fileselect.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "WM_api.h"
@@ -246,8 +247,21 @@ static void file_panel_asset_catalog_buttons_draw(const bContext *C, Panel *pane
RNA_pointer_create(&screen->id, &RNA_FileAssetSelectParams, params, &params_ptr);
uiItemR(row, &params_ptr, "asset_library_ref", 0, "", ICON_NONE);
- if (params->asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
- uiItemO(row, "", ICON_FILE_REFRESH, "FILE_OT_asset_library_refresh");
+ if (params->asset_library_ref.type == ASSET_LIBRARY_LOCAL) {
+ bContext *mutable_ctx = CTX_copy(C);
+ if (WM_operator_name_poll(mutable_ctx, "asset.bundle_install")) {
+ uiItemS(col);
+ uiItemMenuEnumO(col,
+ mutable_ctx,
+ "asset.bundle_install",
+ "asset_library_ref",
+ "Copy Bundle to Asset Library...",
+ ICON_IMPORT);
+ }
+ CTX_free(mutable_ctx);
+ }
+ else {
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
}
uiItemS(col);
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index 186bc04fafe..fbe2426021b 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -46,9 +46,6 @@ void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int fil
ymax);
}
-/**
- * If \a path leads to a .blend, remove the trailing slash (if needed).
- */
void file_path_to_ui_path(const char *path, char *r_path, int max_size)
{
char tmp_path[PATH_MAX];
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index b85dadf1f8e..e4ea832fe2f 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -89,6 +89,7 @@
#include "atomic_ops.h"
+#include "file_indexer.h"
#include "file_intern.h"
#include "filelist.h"
@@ -178,7 +179,6 @@ int folderlist_clear_next(struct SpaceFile *sfile)
return 1;
}
-/* not listbase itself */
void folderlist_free(ListBase *folderlist)
{
if (folderlist) {
@@ -352,9 +352,6 @@ typedef struct FileListEntryPreview {
char path[FILE_MAX];
uint flags;
int index;
- /* Some file types load the memory from runtime data, not from disk. We just wait until it's done
- * generating (BKE_previewimg_is_finished()). */
- PreviewImage *in_memory_preview;
int icon_id;
} FileListEntryPreview;
@@ -399,6 +396,11 @@ typedef struct FileList {
FileListFilter filter_data;
+ /**
+ * File indexer to use. Attribute is always set.
+ */
+ const struct FileIndexerType *indexer;
+
struct FileListIntern filelist_intern;
struct FileListEntryCache filelist_cache;
@@ -509,6 +511,53 @@ static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
}
/**
+ * If all relevant characteristics match (e.g. the file type when sorting by file types), this
+ * should be used as tiebreaker. It makes sure there's a well defined sorting even in such cases.
+ *
+ * Multiple files with the same name can appear with recursive file loading and/or when displaying
+ * IDs of different types, so these cases need to be handled.
+ *
+ * 1) Sort files by name using natural sorting.
+ * 2) If not possible (file names match) and both represent local IDs, sort by ID-type.
+ * 3) If not possible and only one is a local ID, place files representing local IDs first.
+ *
+ * TODO (not actually implemented, but should be):
+ * 4) If no file represents a local ID, sort by file path, so that files higher up the file system
+ * hierarchy are placed first.
+ */
+static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
+{
+ /* Case 1. */
+ {
+ const int order = BLI_strcasecmp_natural(entry1->name, entry2->name);
+ if (order) {
+ return order;
+ }
+ }
+
+ /* Case 2. */
+ if (entry1->local_data.id && entry2->local_data.id) {
+ if (entry1->blentype < entry2->blentype) {
+ return -1;
+ }
+ if (entry1->blentype > entry2->blentype) {
+ return 1;
+ }
+ }
+ /* Case 3. */
+ {
+ if (entry1->local_data.id && !entry2->local_data.id) {
+ return -1;
+ }
+ if (!entry1->local_data.id && entry2->local_data.id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
* Handles inverted sorting itself (currently there's nothing to invert), so if this returns non-0,
* it should be used as-is and not inverted.
*/
@@ -568,17 +617,13 @@ static int compare_name(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
- int ret;
+ int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
return ret;
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_date(void *user_data, const void *a1, const void *a2)
@@ -586,10 +631,9 @@ static int compare_date(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
int64_t time1, time2;
- int ret;
+ int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
return ret;
}
@@ -603,10 +647,7 @@ static int compare_date(void *user_data, const void *a1, const void *a2)
return compare_apply_inverted(-1, sort_data);
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_size(void *user_data, const void *a1, const void *a2)
@@ -614,7 +655,6 @@ static int compare_size(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
uint64_t size1, size2;
int ret;
@@ -631,10 +671,7 @@ static int compare_size(void *user_data, const void *a1, const void *a2)
return compare_apply_inverted(-1, sort_data);
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
static int compare_extension(void *user_data, const void *a1, const void *a2)
@@ -642,7 +679,6 @@ static int compare_extension(void *user_data, const void *a1, const void *a2)
const FileListInternEntry *entry1 = a1;
const FileListInternEntry *entry2 = a2;
const struct FileSortData *sort_data = user_data;
- char *name1, *name2;
int ret;
if ((ret = compare_direntry_generic(entry1, entry2))) {
@@ -690,10 +726,7 @@ static int compare_extension(void *user_data, const void *a1, const void *a2)
}
}
- name1 = entry1->name;
- name2 = entry2->name;
-
- return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
+ return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
}
void filelist_sort(struct FileList *filelist)
@@ -1128,10 +1161,14 @@ void filelist_setfilter_options(FileList *filelist,
}
}
-/**
- * \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is
- * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
- */
+void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
+{
+ BLI_assert(filelist);
+ BLI_assert(indexer);
+
+ filelist->indexer = indexer;
+}
+
void filelist_set_asset_catalog_filter_options(
FileList *filelist,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
@@ -1171,9 +1208,6 @@ static bool filelist_compare_asset_libraries(const AssetLibraryReference *librar
return true;
}
-/**
- * \param asset_library_ref: May be NULL to unset the library.
- */
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
{
/* Unset if needed. */
@@ -1351,7 +1385,7 @@ static int filelist_geticon_ex(const FileDirEntry *file,
}
if (typeflag & FILE_TYPE_BLENDER) {
- return ICON_FILE_BLEND;
+ return (is_main || file->preview_icon_id) ? ICON_FILE_BLEND : ICON_BLENDER;
}
if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
return ICON_FILE_BACKUP;
@@ -1577,74 +1611,55 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
FileListEntryPreview *preview = preview_taskdata->preview;
ThumbSource source = 0;
- bool done = false;
// printf("%s: Start (%d)...\n", __func__, threadid);
- if (preview->in_memory_preview) {
- if (BKE_previewimg_is_finished(preview->in_memory_preview, ICON_SIZE_PREVIEW)) {
- ImBuf *imbuf = BKE_previewimg_to_imbuf(preview->in_memory_preview, ICON_SIZE_PREVIEW);
- if (imbuf) {
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
- }
- done = true;
- }
- }
- else {
- // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- BLI_assert(preview->flags &
- (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
- FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
+ // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ BLI_assert(preview->flags &
+ (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
+ FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
- if (preview->flags & FILE_TYPE_IMAGE) {
- source = THB_SOURCE_IMAGE;
- }
- else if (preview->flags &
- (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
- source = THB_SOURCE_BLEND;
- }
- else if (preview->flags & FILE_TYPE_MOVIE) {
- source = THB_SOURCE_MOVIE;
- }
- else if (preview->flags & FILE_TYPE_FTFONT) {
- source = THB_SOURCE_FONT;
- }
-
- IMB_thumb_path_lock(preview->path);
- /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
- * in case user switch to a bigger preview size. */
- ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
- IMB_thumb_path_unlock(preview->path);
- if (imbuf) {
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
- }
-
- done = true;
+ if (preview->flags & FILE_TYPE_IMAGE) {
+ source = THB_SOURCE_IMAGE;
+ }
+ else if (preview->flags &
+ (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
+ source = THB_SOURCE_BLEND;
+ }
+ else if (preview->flags & FILE_TYPE_MOVIE) {
+ source = THB_SOURCE_MOVIE;
+ }
+ else if (preview->flags & FILE_TYPE_FTFONT) {
+ source = THB_SOURCE_FONT;
}
- if (done) {
- /* That way task freeing function won't free th preview, since it does not own it anymore. */
- atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL);
- BLI_thread_queue_push(cache->previews_done, preview);
- atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
+ IMB_thumb_path_lock(preview->path);
+ /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
+ * in case user switch to a bigger preview size. */
+ ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
+ IMB_thumb_path_unlock(preview->path);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
}
+ /* Move ownership to the done queue. */
+ preview_taskdata->preview = NULL;
+
+ BLI_thread_queue_push(cache->previews_done, preview);
+ atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
+
// printf("%s: End (%d)...\n", __func__, threadid);
}
static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
- FileListEntryPreview *preview = preview_taskdata->preview;
- /* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent
- * to previews_done queue. */
- if (preview != NULL) {
- if (preview->icon_id) {
- BKE_icon_delete(preview->icon_id);
- }
- MEM_freeN(preview);
+ /* In case the preview wasn't moved to the "done" queue yet. */
+ if (preview_taskdata->preview) {
+ MEM_freeN(preview_taskdata->preview);
}
+
MEM_freeN(preview_taskdata);
}
@@ -1719,34 +1734,51 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
return;
}
- FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
-
- if (entry->redirection_path) {
- BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
- }
- else {
- BLI_join_dirfile(
- preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ PreviewImage *preview_in_memory = intern_entry->local_data.preview_image;
+ if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) {
+ /* Nothing to set yet. Wait for next call. */
+ return;
}
+ filelist_cache_preview_ensure_running(cache);
+ entry->flags |= FILE_ENTRY_PREVIEW_LOADING;
+
+ FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
preview->index = index;
preview->flags = entry->typeflag;
- preview->in_memory_preview = intern_entry->local_data.preview_image;
preview->icon_id = 0;
- // printf("%s: %d - %s\n", __func__, preview->index, preview->path);
- filelist_cache_preview_ensure_running(cache);
+ if (preview_in_memory) {
+ /* TODO(mano-wii): No need to use the thread API here. */
+ BLI_assert(BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW));
+ preview->path[0] = '\0';
+ ImBuf *imbuf = BKE_previewimg_to_imbuf(preview_in_memory, ICON_SIZE_PREVIEW);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ }
+ BLI_thread_queue_push(cache->previews_done, preview);
+ atomic_fetch_and_sub_z(&cache->previews_todo_count, 1);
+ }
+ else {
+ if (entry->redirection_path) {
+ BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
+ }
+ else {
+ BLI_join_dirfile(
+ preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ }
+ // printf("%s: %d - %s\n", __func__, preview->index, preview->path);
- FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
- __func__);
- preview_taskdata->preview = preview;
- entry->flags |= FILE_ENTRY_PREVIEW_LOADING;
- BLI_task_pool_push(cache->previews_pool,
- filelist_cache_preview_runf,
- preview_taskdata,
- true,
- filelist_cache_preview_freef);
+ FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
+ __func__);
+ preview_taskdata->preview = preview;
+ BLI_task_pool_push(cache->previews_pool,
+ filelist_cache_preview_runf,
+ preview_taskdata,
+ true,
+ filelist_cache_preview_freef);
+ }
}
static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
@@ -1844,6 +1876,8 @@ FileList *filelist_new(short type)
p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
filelist_settype(p, type);
+ p->indexer = &file_indexer_noop;
+
return p;
}
@@ -1963,10 +1997,6 @@ void filelist_clear(FileList *filelist)
filelist_clear_ex(filelist, true, true, true);
}
-/**
- * A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist
- * force-reset flags.
- */
void filelist_clear_from_reset_tag(FileList *filelist)
{
/* Do a full clear if needed. */
@@ -2073,9 +2103,6 @@ bool filelist_is_dir(struct FileList *filelist, const char *path)
return filelist->check_dir_fn(filelist, (char *)path, false);
}
-/**
- * May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
- */
void filelist_setdir(struct FileList *filelist, char *r_dir)
{
const bool allow_invalid = filelist->asset_library_ref != NULL;
@@ -2133,12 +2160,6 @@ bool filelist_needs_reset_on_main_changes(const FileList *filelist)
return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0;
}
-/**
- * Limited version of full update done by space_file's file_refresh(),
- * to be used by operators and such.
- * Ensures given filelist is ready to be used (i.e. it is filtered and sorted),
- * unless it is tagged for a full refresh.
- */
int filelist_files_ensure(FileList *filelist)
{
if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) {
@@ -2251,10 +2272,6 @@ FileDirEntry *filelist_file(struct FileList *filelist, int index)
return filelist_file_ex(filelist, index, true);
}
-/**
- * Find a file from a file name, or more precisely, its file-list relative path, inside the
- * filtered items. \return The index of the found file or -1.
- */
int filelist_file_find_path(struct FileList *filelist, const char *filename)
{
if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
@@ -2275,10 +2292,6 @@ int filelist_file_find_path(struct FileList *filelist, const char *filename)
return -1;
}
-/**
- * Find a file representing \a id.
- * \return The index of the found file or -1.
- */
int filelist_file_find_id(const FileList *filelist, const ID *id)
{
if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
@@ -2295,9 +2308,6 @@ int filelist_file_find_id(const FileList *filelist, const ID *id)
return -1;
}
-/**
- * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
- */
ID *filelist_file_get_id(const FileDirEntry *file)
{
return file->id;
@@ -2393,7 +2403,6 @@ static void filelist_file_cache_block_release(struct FileList *filelist,
}
}
-/* Load in cache all entries "around" given index (as much as block cache may hold). */
bool filelist_file_cache_block(struct FileList *filelist, const int index)
{
FileListEntryCache *cache = &filelist->filelist_cache;
@@ -2661,7 +2670,6 @@ bool filelist_cache_previews_update(FileList *filelist)
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
if (entry) {
- entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING;
if (preview->icon_id) {
/* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous
* process from trying to generate the same preview icon. */
@@ -2678,6 +2686,7 @@ bool filelist_cache_previews_update(FileList *filelist)
* preview will be retried quite often anyway. */
entry->flags |= FILE_ENTRY_INVALID_PREVIEW;
}
+ entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING;
}
else {
BKE_icon_delete(preview->icon_id);
@@ -2736,8 +2745,6 @@ static bool file_is_blend_backup(const char *str)
return retval;
}
-/* TODO: Maybe we should move this to BLI?
- * On the other hand, it's using defines from space-file area, so not sure... */
int ED_path_extension_type(const char *path)
{
if (BLO_has_bfile_extension(path)) {
@@ -2965,9 +2972,6 @@ bool filelist_entry_is_selected(FileList *filelist, const int index)
return selection_state != 0;
}
-/**
- * Set selection of the '..' parent entry, but only if it's actually visible.
- */
void filelist_entry_parent_select_set(FileList *filelist,
FileSelType select,
uint flag,
@@ -2978,7 +2982,6 @@ void filelist_entry_parent_select_set(FileList *filelist,
}
}
-/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group)
{
return BLO_library_path_explode(filelist->filelist.root, dir, r_group, NULL);
@@ -3134,6 +3137,29 @@ static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idc
return entry;
}
+static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
+ const BLODataBlockInfo *datablock_info,
+ const bool prefix_relpath_with_group_name,
+ const int idcode,
+ const char *group_name)
+{
+ FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
+ if (prefix_relpath_with_group_name) {
+ entry->relpath = BLI_sprintfN("%s/%s", group_name, datablock_info->name);
+ }
+ else {
+ entry->relpath = BLI_strdup(datablock_info->name);
+ }
+ entry->typeflag |= FILE_TYPE_BLENDERLIB;
+ if (datablock_info && datablock_info->asset_data) {
+ entry->typeflag |= FILE_TYPE_ASSET;
+ /* Moves ownership! */
+ entry->imported_asset_data = datablock_info->asset_data;
+ }
+ entry->blentype = idcode;
+ BLI_addtail(entries, entry);
+}
+
static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
LinkNode *datablock_infos,
const bool prefix_relpath_with_group_name,
@@ -3141,29 +3167,71 @@ static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
const char *group_name)
{
for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
- struct BLODataBlockInfo *info = ln->link;
- FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
- if (prefix_relpath_with_group_name) {
- entry->relpath = BLI_sprintfN("%s/%s", group_name, info->name);
- }
- else {
- entry->relpath = BLI_strdup(info->name);
- }
- entry->typeflag |= FILE_TYPE_BLENDERLIB;
- if (info && info->asset_data) {
- entry->typeflag |= FILE_TYPE_ASSET;
- /* Moves ownership! */
- entry->imported_asset_data = info->asset_data;
- }
- entry->blentype = idcode;
+ struct BLODataBlockInfo *datablock_info = ln->link;
+ filelist_readjob_list_lib_add_datablock(
+ entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
+ }
+}
+
+static void filelist_readjob_list_lib_add_from_indexer_entries(
+ ListBase *entries,
+ const FileIndexerEntries *indexer_entries,
+ const bool prefix_relpath_with_group_name)
+{
+ for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) {
+ const FileIndexerEntry *indexer_entry = (const FileIndexerEntry *)ln->link;
+ const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode);
+ filelist_readjob_list_lib_add_datablock(entries,
+ &indexer_entry->datablock_info,
+ prefix_relpath_with_group_name,
+ indexer_entry->idcode,
+ group_name);
+ }
+}
+
+static FileListInternEntry *filelist_readjob_list_lib_navigate_to_parent_entry_create(void)
+{
+ FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
+ entry->relpath = BLI_strdup(FILENAME_PARENT);
+ entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR);
+ return entry;
+}
+
+/**
+ * Structure to keep the file indexer and its user data together.
+ */
+typedef struct FileIndexer {
+ const FileIndexerType *callbacks;
+
+ /**
+ * User data. Contains the result of `callbacks.init_user_data`.
+ */
+ void *user_data;
+} FileIndexer;
+
+static int filelist_readjob_list_lib_populate_from_index(ListBase *entries,
+ const ListLibOptions options,
+ const int read_from_index,
+ const FileIndexerEntries *indexer_entries)
+{
+ int navigate_to_parent_len = 0;
+ if (options & LIST_LIB_ADD_PARENT) {
+ FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create();
BLI_addtail(entries, entry);
+ navigate_to_parent_len = 1;
}
+
+ filelist_readjob_list_lib_add_from_indexer_entries(entries, indexer_entries, true);
+ return read_from_index + navigate_to_parent_len;
}
static int filelist_readjob_list_lib(const char *root,
ListBase *entries,
- const ListLibOptions options)
+ const ListLibOptions options,
+ FileIndexer *indexer_runtime)
{
+ BLI_assert(indexer_runtime);
+
char dir[FILE_MAX_LIBEXTRA], *group;
struct BlendHandle *libfiledata = NULL;
@@ -3171,13 +3239,37 @@ static int filelist_readjob_list_lib(const char *root,
/* Check if the given root is actually a library. All folders are passed to
* `filelist_readjob_list_lib` and based on the number of found entries `filelist_readjob_do`
* will do a dir listing only when this function does not return any entries. */
- /* TODO: We should consider introducing its own function to detect if it is a lib and
+ /* TODO(jbakker): We should consider introducing its own function to detect if it is a lib and
* call it directly from `filelist_readjob_do` to increase readability. */
const bool is_lib = BLO_library_path_explode(root, dir, &group, NULL);
if (!is_lib) {
return 0;
}
+ const bool group_came_from_path = group != NULL;
+
+ /* Try read from indexer_runtime. */
+ /* Indexing returns all entries in a blend file. We should ignore the index when listing a group
+ * inside a blend file, so the `entries` isn't filled with undesired entries.
+ * This happens when linking or appending data-blocks, where you can navigate into a group (ie
+ * Materials/Objects) where you only want to work with partial indexes.
+ *
+ * Adding support for partial reading/updating indexes would increase the complexity.
+ */
+ const bool use_indexer = !group_came_from_path;
+ FileIndexerEntries indexer_entries = {NULL};
+ if (use_indexer) {
+ int read_from_index = 0;
+ eFileIndexerResult indexer_result = indexer_runtime->callbacks->read_index(
+ dir, &indexer_entries, &read_from_index, indexer_runtime->user_data);
+ if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) {
+ int entries_read = filelist_readjob_list_lib_populate_from_index(
+ entries, options, read_from_index, &indexer_entries);
+ ED_file_indexer_entries_clear(&indexer_entries);
+ return entries_read;
+ }
+ }
+
/* Open the library file. */
BlendFileReadReport bf_reports = {.reports = NULL};
libfiledata = BLO_blendhandle_from_file(dir, &bf_reports);
@@ -3186,18 +3278,18 @@ static int filelist_readjob_list_lib(const char *root,
}
/* Add current parent when requested. */
- int parent_len = 0;
+ /* Is the navigate to previous level added to the list of entries. When added the return value
+ * should be increased to match the actual number of entries added. It is introduced to keep
+ * the code clean and readable and not counting in a single variable. */
+ int navigate_to_parent_len = 0;
if (options & LIST_LIB_ADD_PARENT) {
- FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
- entry->relpath = BLI_strdup(FILENAME_PARENT);
- entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR);
+ FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create();
BLI_addtail(entries, entry);
- parent_len = 1;
+ navigate_to_parent_len = 1;
}
int group_len = 0;
int datablock_len = 0;
- const bool group_came_from_path = group != NULL;
if (group_came_from_path) {
const int idcode = groupname_to_code(group);
LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info(
@@ -3222,6 +3314,10 @@ static int filelist_readjob_list_lib(const char *root,
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len);
filelist_readjob_list_lib_add_datablocks(
entries, group_datablock_infos, true, idcode, group_name);
+ if (use_indexer) {
+ ED_file_indexer_entries_extend_from_datablock_infos(
+ &indexer_entries, group_datablock_infos, idcode);
+ }
BLI_linklist_freeN(group_datablock_infos);
datablock_len += group_datablock_len;
}
@@ -3232,8 +3328,14 @@ static int filelist_readjob_list_lib(const char *root,
BLO_blendhandle_close(libfiledata);
+ /* Update the index. */
+ if (use_indexer) {
+ indexer_runtime->callbacks->update_index(dir, &indexer_entries, indexer_runtime->user_data);
+ ED_file_indexer_entries_clear(&indexer_entries);
+ }
+
/* Return the number of items added to entries. */
- int added_entries_len = group_len + datablock_len + parent_len;
+ int added_entries_len = group_len + datablock_len + navigate_to_parent_len;
return added_entries_len;
}
@@ -3425,11 +3527,11 @@ typedef struct FileListReadJob {
* The job system calls #filelist_readjob_update which moves any read file from #tmp_filelist
* into #filelist in a thread-safe way.
*
- * #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread, and
- * moved to #filelist once all categories are loaded.
+ * #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread,
+ * and moved to #filelist once all categories are loaded.
*
- * NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be set
- * to NULL to avoid double-freeing them. */
+ * NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be
+ * set to NULL to avoid double-freeing them. */
struct FileList *tmp_filelist;
} FileListReadJob;
@@ -3466,8 +3568,8 @@ static bool filelist_readjob_should_recurse_into_entry(const int max_recursion,
/* No more levels of recursion left. */
return false;
}
- /* Show entries when recursion is set to `Blend file` even when `current_recursion_level` exceeds
- * `max_recursion`. */
+ /* Show entries when recursion is set to `Blend file` even when `current_recursion_level`
+ * exceeds `max_recursion`. */
if (!is_lib && (current_recursion_level >= max_recursion) &&
((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) {
return false;
@@ -3515,6 +3617,12 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
BLI_path_normalize_dir(job_params->main_name, dir);
td_dir->dir = BLI_strdup(dir);
+ /* Init the file indexer. */
+ FileIndexer indexer_runtime = {.callbacks = filelist->indexer};
+ if (indexer_runtime.callbacks->init_user_data) {
+ indexer_runtime.user_data = indexer_runtime.callbacks->init_user_data(dir, sizeof(dir));
+ }
+
while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
FileListInternEntry *entry;
int nbr_entries = 0;
@@ -3557,7 +3665,8 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
if (filelist->asset_library_ref) {
list_lib_options |= LIST_LIB_ASSETS_ONLY;
}
- nbr_entries = filelist_readjob_list_lib(subdir, &entries, list_lib_options);
+ nbr_entries = filelist_readjob_list_lib(
+ subdir, &entries, list_lib_options, &indexer_runtime);
if (nbr_entries > 0) {
is_lib = true;
}
@@ -3599,6 +3708,15 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
MEM_freeN(subdir);
}
+ /* Finalize and free indexer. */
+ if (indexer_runtime.callbacks->filelist_finished && BLI_stack_is_empty(todo_dirs)) {
+ indexer_runtime.callbacks->filelist_finished(indexer_runtime.user_data);
+ }
+ if (indexer_runtime.callbacks->free_user_data && indexer_runtime.user_data) {
+ indexer_runtime.callbacks->free_user_data(indexer_runtime.user_data);
+ indexer_runtime.user_data = NULL;
+ }
+
/* If we were interrupted by stop, stack may not be empty and we need to free
* pending dir paths. */
while (!BLI_stack_is_empty(todo_dirs)) {
@@ -3741,8 +3859,8 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
*/
static bool filelist_contains_main(const FileList *filelist, const Main *bmain)
{
- const char *main_path = BKE_main_blendfile_path(bmain);
- return main_path[0] && BLI_path_contains(filelist->filelist.root, main_path);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
+ return blendfile_path[0] && BLI_path_contains(filelist->filelist.root, blendfile_path);
}
static void filelist_readjob_asset_library(FileListReadJob *job_params,
@@ -3949,7 +4067,13 @@ void filelist_readjob_start(FileList *filelist, const int space_notifier, const
/* Init even for single threaded execution. Called functions use it. */
BLI_mutex_init(&flrj->lock);
- if (filelist->tags & FILELIST_TAGS_NO_THREADS) {
+ /* The file list type may not support threading so execute immediately. Same when only rereading
+ * #Main data (which we do quite often on changes to #Main, since it's the easiest and safest way
+ * to ensure the displayed data is up to date), because some operations executing right after
+ * main data changed may need access to the ID files (see T93691). */
+ const bool no_threads = (filelist->tags & FILELIST_TAGS_NO_THREADS) || flrj->only_main_data;
+
+ if (no_threads) {
short dummy_stop = false;
short dummy_do_update = false;
float dummy_progress = 0.0f;
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 0048a349dca..0119a9b4f52 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -29,6 +29,7 @@ extern "C" {
struct AssetLibraryReference;
struct BlendHandle;
+struct FileIndexerType;
struct FileList;
struct FileSelection;
struct bUUID;
@@ -50,6 +51,7 @@ typedef enum FileCheckType {
CHECK_ALL = 3,
} FileCheckType;
+/* not listbase itself */
void folderlist_free(struct ListBase *folderlist);
void folderlist_popdir(struct ListBase *folderlist, char *dir);
void folderlist_pushdir(struct ListBase *folderlist, const char *dir);
@@ -72,12 +74,25 @@ void filelist_setfilter_options(struct FileList *filelist,
const bool filter_assets_only,
const char *filter_glob,
const char *filter_search);
+/**
+ * Set the indexer to be used by the filelist.
+ *
+ * The given indexer allocation should be handled by the caller or defined statically.
+ */
+void filelist_setindexer(struct FileList *filelist, const struct FileIndexerType *indexer);
+/**
+ * \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is
+ * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
+ */
void filelist_set_asset_catalog_filter_options(
struct FileList *filelist,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
const struct bUUID *catalog_id);
void filelist_tag_needs_filtering(struct FileList *filelist);
void filelist_filter(struct FileList *filelist);
+/**
+ * \param asset_library_ref: May be NULL to unset the library.
+ */
void filelist_setlibrary(struct FileList *filelist,
const struct AssetLibraryReference *asset_library_ref);
@@ -96,24 +111,51 @@ void filelist_clear_ex(struct FileList *filelist,
const bool do_asset_library,
const bool do_cache,
const bool do_selection);
+/**
+ * A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist
+ * force-reset flags.
+ */
void filelist_clear_from_reset_tag(struct FileList *filelist);
void filelist_free(struct FileList *filelist);
const char *filelist_dir(struct FileList *filelist);
bool filelist_is_dir(struct FileList *filelist, const char *path);
+/**
+ * May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
+ */
void filelist_setdir(struct FileList *filelist, char *r_dir);
+/**
+ * Limited version of full update done by space_file's file_refresh(),
+ * to be used by operators and such.
+ * Ensures given filelist is ready to be used (i.e. it is filtered and sorted),
+ * unless it is tagged for a full refresh.
+ */
int filelist_files_ensure(struct FileList *filelist);
int filelist_needs_reading(struct FileList *filelist);
FileDirEntry *filelist_file(struct FileList *filelist, int index);
FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request);
+/**
+ * Find a file from a file name, or more precisely, its file-list relative path, inside the
+ * filtered items. \return The index of the found file or -1.
+ */
int filelist_file_find_path(struct FileList *filelist, const char *file);
+/**
+ * Find a file representing \a id.
+ * \return The index of the found file or -1.
+ */
int filelist_file_find_id(const struct FileList *filelist, const struct ID *id);
+/**
+ * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET.
+ */
struct ID *filelist_file_get_id(const struct FileDirEntry *file);
bool filelist_uid_is_set(const FileUID uid);
void filelist_uid_unset(FileUID *r_uid);
void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size);
+/**
+ * Load in cache all entries "around" given index (as much as block cache may hold).
+ */
bool filelist_file_cache_block(struct FileList *filelist, const int index);
bool filelist_needs_force_reset(struct FileList *filelist);
@@ -145,6 +187,9 @@ unsigned int filelist_entry_select_index_get(struct FileList *filelist,
const int index,
FileCheckType check);
bool filelist_entry_is_selected(struct FileList *filelist, const int index);
+/**
+ * Set selection of the '..' parent entry, but only if it's actually visible.
+ */
void filelist_entry_parent_select_set(struct FileList *filelist,
FileSelType select,
unsigned int flag,
@@ -155,6 +200,9 @@ void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
struct AssetLibrary *filelist_asset_library(struct FileList *filelist);
struct BlendHandle *filelist_lib(struct FileList *filelist);
+/**
+ * \param dir: Must be #FILE_MAX_LIBEXTRA long!
+ */
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group);
void filelist_freelib(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 11757975a62..e3ac5840da3 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -358,9 +358,6 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
return params;
}
-/**
- * If needed, create and return the file select parameters for the active browse mode.
- */
FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile)
{
switch ((eFileBrowse_Mode)sfile->browse_mode) {
@@ -380,9 +377,6 @@ FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile)
return NULL;
}
-/**
- * Get the file select parameters for the active browse mode.
- */
FileSelectParams *ED_fileselect_get_active_params(const SpaceFile *sfile)
{
if (!sfile) {
@@ -411,6 +405,15 @@ FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile)
return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : NULL;
}
+bool ED_fileselect_is_local_asset_library(const SpaceFile *sfile)
+{
+ const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
+ if (asset_params == NULL) {
+ return false;
+ }
+ return asset_params->asset_library_ref.type == ASSET_LIBRARY_LOCAL;
+}
+
static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params)
{
AssetLibraryReference *library = &asset_params->asset_library_ref;
@@ -638,13 +641,6 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
}
}
-/**
- * Update the user-preference data for the file space. In fact, this also contains some
- * non-FileSelectParams data, but we can safely ignore this.
- *
- * \param temp_win_size: If the browser was opened in a temporary window,
- * pass its size here so we can store that in the preferences. Otherwise NULL.
- */
void ED_fileselect_params_to_userdef(SpaceFile *sfile,
const int temp_win_size[2],
const bool is_maximized)
@@ -682,9 +678,6 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile,
}
}
-/**
- * Sets FileSelectParams->file (name of selected file)
- */
void fileselect_file_set(SpaceFile *sfile, const int index)
{
const struct FileDirEntry *file = filelist_file(sfile->files, index);
@@ -805,10 +798,6 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y)
return active_file;
}
-/**
- * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the
- * top column-header row.
- */
void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect)
{
*r_rect = v2d->mask;
@@ -848,9 +837,6 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
}
}
-/**
- * Check if the region coordinate defined by \a x and \a y are inside the column header.
- */
bool file_attribute_column_header_is_inside(const View2D *v2d,
const FileLayout *layout,
int x,
@@ -877,9 +863,6 @@ bool file_attribute_column_type_enabled(const FileSelectParams *params,
}
}
-/**
- * Find the column type at region coordinate given by \a x (y doesn't matter for this).
- */
FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d,
const FileSelectParams *params,
FileLayout *layout,
@@ -1096,10 +1079,6 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *region)
return sfile->layout;
}
-/**
- * Support updating the directory even when this isn't the active space
- * needed so RNA properties update function isn't context sensitive, see T70255.
- */
void ED_file_change_dir_ex(bContext *C, ScrArea *area)
{
/* May happen when manipulating non-active spaces. */
@@ -1295,12 +1274,6 @@ void file_params_smoothscroll_timer_clear(wmWindowManager *wm, wmWindow *win, Sp
sfile->smoothscroll_timer = NULL;
}
-/**
- * Set the renaming-state to #FILE_PARAMS_RENAME_POSTSCROLL_PENDING and trigger the smooth-scroll
- * timer. To be used right after a file was renamed.
- * Note that the caller is responsible for setting the correct rename-file info
- * (#FileSelectParams.renamefile or #FileSelectParams.rename_id).
- */
void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, SpaceFile *sfile)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
@@ -1314,9 +1287,6 @@ void file_params_invoke_rename_postscroll(wmWindowManager *wm, wmWindow *win, Sp
sfile->scroll_offset = 0;
}
-/**
- * To be executed whenever renaming ends (successfully or not).
- */
void file_params_rename_end(wmWindowManager *wm,
wmWindow *win,
SpaceFile *sfile,
@@ -1348,10 +1318,6 @@ static int file_params_find_renamed(const FileSelectParams *params, struct FileL
filelist_file_find_path(filelist, params->renamefile);
}
-/**
- * Helper used by both main update code, and smooth-scroll timer,
- * to try to enable rename editing from #FileSelectParams.renamefile name.
- */
void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
{
BLI_assert(params->rename_flag != 0);
@@ -1363,7 +1329,7 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
BLI_assert(params->renamefile[0] != '\0' || params->rename_id != NULL);
- const int idx = file_params_find_renamed(params, sfile->files);
+ int idx = file_params_find_renamed(params, sfile->files);
if (idx >= 0) {
FileDirEntry *file = filelist_file(sfile->files, idx);
BLI_assert(file != NULL);
@@ -1376,7 +1342,11 @@ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params)
params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
}
else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) {
+ /* file_select_deselect_all() will resort and re-filter, so `idx` will probably have changed.
+ * Need to get the correct #FileDirEntry again. */
file_select_deselect_all(sfile, FILE_SEL_SELECTED);
+ idx = file_params_find_renamed(params, sfile->files);
+ file = filelist_file(sfile->files, idx);
filelist_entry_select_set(
sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED | FILE_SEL_HIGHLIGHTED, CHECK_ALL);
params->active_file = idx;
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index b115c63a569..bbf3c6f768c 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
@@ -44,6 +45,7 @@
#include "WM_types.h"
#include "ED_asset.h"
+#include "ED_asset_indexer.h"
#include "ED_fileselect.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -59,6 +61,10 @@
#include "filelist.h"
#include "fsmenu.h"
+/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for
+ * object snapping. See {D12990}. */
+//#define SPACE_FILE_ENABLE_ASSET_INDEXING
+
static ARegion *file_ui_region_ensure(ScrArea *area, ARegion *region_prev)
{
ARegion *region;
@@ -353,6 +359,12 @@ static void file_refresh(const bContext *C, ScrArea *area)
sfile->files, asset_params->asset_catalog_visibility, &asset_params->catalog_id);
}
+#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING
+ if (ED_fileselect_is_asset_browser(sfile)) {
+ filelist_setindexer(sfile->files, &file_indexer_asset);
+ }
+#endif
+
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
sfile->system_bookmarknr = fsmenu_get_active_indices(
@@ -688,7 +700,6 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_previous);
WM_operatortype_append(FILE_OT_next);
WM_operatortype_append(FILE_OT_refresh);
- WM_operatortype_append(FILE_OT_asset_library_refresh);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
WM_operatortype_append(FILE_OT_bookmark_cleanup);
@@ -992,7 +1003,6 @@ static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *
file_reset_filelist_showing_main_data(area, sfile);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_file(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype file");
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index af88bbced9c..ed5993c77a7 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -1060,21 +1060,21 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
-
- immUniform1i("colors_len", 0); /* Simple dashes. */
if (BKE_fcurve_is_protected(fcu)) {
- /* protected curves (non editable) are drawn with dotted lines */
+ /* Protected curves (non editable) are drawn with dotted lines. */
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+ immUniform1i("colors_len", 0); /* Simple dashes. */
immUniform1f("dash_width", 4.0f);
immUniform1f("dash_factor", 0.5f);
}
else {
- immUniform1f("dash_factor", 2.0f); /* solid line */
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport_size[2]);
+ immUniform1f("lineWidth", GPU_line_width_get());
}
if (((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) || (fcu->flag & FCURVE_MUTED)) {
@@ -1314,9 +1314,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
/* Public Curve-Drawing API ---------------- */
-/* Draw the 'ghost' F-Curves (i.e. snapshots of the curve)
- * NOTE: unit mapping has already been applied to the values, so do not try and apply again
- */
void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region)
{
FCurve *fcu;
@@ -1364,9 +1361,6 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region
GPU_blend(GPU_BLEND_NONE);
}
-/* This is called twice from space_graph.c -> graph_main_region_draw()
- * Unselected then selected F-Curves are drawn so that they do not occlude each other.
- */
void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, short sel)
{
ListBase anim_data = {NULL, NULL};
@@ -1408,7 +1402,6 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
/** \name Channel List
* \{ */
-/* left hand part */
void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
{
ListBase anim_data = {NULL, NULL};
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 7add2f7cbb8..4db1eb5214e 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -34,12 +34,23 @@ struct bContext;
/* ***************************************** */
/* graph_draw.c */
+/**
+ * Left hand part.
+ */
void graph_draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *region);
+/**
+ * This is called twice from space_graph.c -> graph_main_region_draw()
+ * Unselected then selected F-Curves are drawn so that they do not occlude each other.
+ */
void graph_draw_curves(struct bAnimContext *ac,
struct SpaceGraph *sipo,
struct ARegion *region,
short sel);
+/**
+ * Draw the 'ghost' F-Curves (i.e. snapshots of the curve)
+ * \note unit mapping has already been applied to the values, so do not try and apply again.
+ */
void graph_draw_ghost_curves(struct bAnimContext *ac,
struct SpaceGraph *sipo,
struct ARegion *region);
@@ -47,6 +58,17 @@ void graph_draw_ghost_curves(struct bAnimContext *ac,
/* ***************************************** */
/* graph_select.c */
+/**
+ * Deselects keyframes in the Graph Editor
+ * - This is called by the deselect all operator, as well as other ones!
+ *
+ * - test: check if select or deselect all
+ * - sel: how to select keyframes
+ * 0 = deselect
+ * 1 = select
+ * 2 = invert
+ * - do_channels: whether to affect selection status of channels
+ */
void deselect_graph_keys(struct bAnimContext *ac, bool test, short sel, bool do_channels);
void GRAPH_OT_select_all(struct wmOperatorType *ot);
@@ -78,6 +100,10 @@ enum eGraphKeys_ColumnSelect_Mode {
/* ***************************************** */
/* graph_edit.c */
+/**
+ * Get the min/max keyframes.
+ * \note it should return total bound-box, filter for selection only can be argument.
+ */
void get_graph_keyframe_extents(struct bAnimContext *ac,
float *xmin,
float *xmax,
@@ -166,12 +192,36 @@ void graph_buttons_register(struct ARegionType *art);
/* ***************************************** */
/* graph_utils.c */
+/**
+ * Find 'active' F-Curve.
+ * It must be editable, since that's the purpose of these buttons (subject to change).
+ * We return the 'wrapper' since it contains valuable context info (about hierarchy),
+ * which will need to be freed when the caller is done with it.
+ *
+ * \note curve-visible flag isn't included,
+ * otherwise selecting a curve via list to edit is too cumbersome.
+ */
struct bAnimListElem *get_active_fcurve_channel(struct bAnimContext *ac);
+/**
+ * Check if there are any visible keyframes (for selection tools).
+ */
bool graphop_visible_keyframes_poll(struct bContext *C);
+/**
+ * Check if there are any visible + editable keyframes (for editing tools).
+ */
bool graphop_editable_keyframes_poll(struct bContext *C);
+/**
+ * Has active F-Curve that's editable.
+ */
bool graphop_active_fcurve_poll(struct bContext *C);
+/**
+ * Has active F-Curve in the context that's editable.
+ */
bool graphop_active_editable_fcurve_ctx_poll(struct bContext *C);
+/**
+ * Has selected F-Curve that's editable.
+ */
bool graphop_selected_fcurve_poll(struct bContext *C);
/* ***************************************** */
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 03bfd1092c6..29eb5b43e6c 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -346,17 +346,6 @@ static tNearestVertInfo *find_nearest_fcurve_vert(bAnimContext *ac, const int mv
* 3) (de)select all - no testing is done; only for use internal tools as normal function...
* \{ */
-/**
- * Deselects keyframes in the Graph Editor
- * - This is called by the deselect all operator, as well as other ones!
- *
- * - test: check if select or deselect all
- * - sel: how to select keyframes
- * 0 = deselect
- * 1 = select
- * 2 = invert
- * - do_channels: whether to affect selection status of channels
- */
void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channels)
{
ListBase anim_data = {NULL, NULL};
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 4e62ab2df2d..0bb5e8b8d9c 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -75,13 +75,16 @@ typedef struct tGraphSliderOp {
ARegion *region;
/** A 0-1 value for determining how much we should decimate. */
- PropertyRNA *percentage_prop;
+ PropertyRNA *factor_prop;
/** The original bezt curve data (used for restoring fcurves). */
ListBase bezt_arr_list;
struct tSlider *slider;
+ /* Each operator has a specific update function. */
+ void (*modal_update)(struct bContext *, struct wmOperator *);
+
NumInput num;
} tGraphSliderOp;
@@ -177,37 +180,10 @@ static void reset_bezts(tGraphSliderOp *gso)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Decimate Keyframes Operator
+/** \name Common Modal Functions
* \{ */
-typedef enum tDecimModes {
- DECIM_RATIO = 1,
- DECIM_ERROR,
-} tDecimModes;
-
-static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max)
-{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
-
- /* Filter data. */
- ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
-
- /* Loop through filtered data and clean curves. */
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) {
- /* The selection contains unsupported keyframe types! */
- WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!");
- }
-
- ale->update |= ANIM_UPDATE_DEFAULT;
- }
-
- ANIM_animdata_update(ac, &anim_data);
- ANIM_animdata_freelist(&anim_data);
-}
-
-static void decimate_exit(bContext *C, wmOperator *op)
+static void graph_slider_exit(bContext *C, wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
wmWindow *win = CTX_wm_window(C);
@@ -235,36 +211,84 @@ static void decimate_exit(bContext *C, wmOperator *op)
WM_cursor_modal_restore(win);
ED_area_status_text(area, NULL);
- /* Cleanup. */
+ /* cleanup */
op->customdata = NULL;
}
-/* Draw a percentage indicator in workspace footer. */
-static void decimate_draw_status(bContext *C, tGraphSliderOp *gso)
+static int graph_slider_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- char status_str[UI_MAX_DRAW_STR];
- char mode_str[32];
- char slider_string[UI_MAX_DRAW_STR];
+ tGraphSliderOp *gso = op->customdata;
- ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+ const bool has_numinput = hasNumInput(&gso->num);
- strcpy(mode_str, TIP_("Decimate Keyframes"));
+ ED_slider_modal(gso->slider, event);
- if (hasNumInput(&gso->num)) {
- char str_ofs[NUM_STR_REP_LEN];
+ switch (event->type) {
+ /* Confirm */
+ case LEFTMOUSE:
+ case EVT_RETKEY:
+ case EVT_PADENTER: {
+ if (event->val == KM_PRESS) {
+ graph_slider_exit(C, op);
- outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
- }
- else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ /* Cancel */
+ case EVT_ESCKEY:
+ case RIGHTMOUSE: {
+ if (event->val == KM_PRESS) {
+ reset_bezts(gso);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ graph_slider_exit(C, op);
+
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+
+ /* When the mouse is moved, the percentage and the keyframes update. */
+ case MOUSEMOVE: {
+ if (has_numinput == false) {
+ /* Do the update as specified by the operator. */
+ gso->modal_update(C, op);
+ }
+ break;
+ }
+ default: {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &gso->num, event)) {
+ float value;
+ float percentage = RNA_property_float_get(op->ptr, gso->factor_prop);
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float.
+ */
+ value = percentage * 100.0f;
+ applyNumInput(&gso->num, &value);
+
+ percentage = value / 100.0f;
+ ED_slider_factor_set(gso->slider, percentage);
+ RNA_property_float_set(op->ptr, gso->factor_prop, percentage);
+
+ gso->modal_update(C, op);
+ break;
+ }
+
+ /* Unhandled event - maybe it was some view manipulation? */
+ /* Allow to pass through. */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
}
- ED_workspace_status_text(C, status_str);
+ return OPERATOR_RUNNING_MODAL;
}
-static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+/* Allocate tGraphSliderOp and assign to op->customdata. */
+static int graph_slider_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tGraphSliderOp *gso;
@@ -275,12 +299,10 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
/* Get editor data. */
if (ANIM_animdata_get_context(C, &gso->ac) == 0) {
- decimate_exit(C, op);
+ graph_slider_exit(C, op);
return OPERATOR_CANCELLED;
}
- gso->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio");
-
gso->scene = CTX_data_scene(C);
gso->area = CTX_wm_area(C);
gso->region = CTX_wm_region(C);
@@ -289,14 +311,11 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
gso->slider = ED_slider_create(C);
ED_slider_init(gso->slider, event);
- ED_slider_allow_overshoot_set(gso->slider, false);
-
- decimate_draw_status(C, gso);
if (gso->bezt_arr_list.first == NULL) {
WM_report(RPT_WARNING,
- "Fcurve Decimate: Can't decimate baked channels. Unbake them and try again.");
- decimate_exit(C, op);
+ "Fcurve Slider: Can't work on baked channels. Unbake them and try again.");
+ graph_slider_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -304,102 +323,101 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
-static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Decimate Keyframes Operator
+ * \{ */
+
+typedef enum tDecimModes {
+ DECIM_RATIO = 1,
+ DECIM_ERROR,
+} tDecimModes;
+
+static void decimate_graph_keys(bAnimContext *ac, float factor, float error_sq_max)
{
- /* Perform decimate updates - in response to some user action
- * (e.g. pressing a key or moving the mouse). */
- tGraphSliderOp *gso = op->customdata;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
- decimate_draw_status(C, gso);
+ /* Filter data. */
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
- /* Reset keyframe data (so we get back to the original state). */
- reset_bezts(gso);
+ /* Loop through filtered data and clean curves. */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ if (!decimate_fcurve(ale, factor, error_sq_max)) {
+ /* The selection contains unsupported keyframe types! */
+ WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!");
+ }
- /* Apply... */
- float remove_ratio = ED_slider_factor_get(gso->slider);
- RNA_property_float_set(op->ptr, gso->percentage_prop, remove_ratio);
- /* We don't want to limit the decimation to a certain error margin. */
- const float error_sq_max = FLT_MAX;
- decimate_graph_keys(&gso->ac, remove_ratio, error_sq_max);
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
-static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *event)
+/* Draw a percentage indicator in workspace footer. */
+static void decimate_draw_status(bContext *C, tGraphSliderOp *gso)
{
- /* This assumes that we are in "DECIM_RATIO" mode. This is because the error margin is very hard
- * and finicky to control with this modal mouse grab method. Therefore, it is expected that the
- * error margin mode is not adjusted by the modal operator but instead tweaked via the redo
- * panel. */
- tGraphSliderOp *gso = op->customdata;
-
- const bool has_numinput = hasNumInput(&gso->num);
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
- ED_slider_modal(gso->slider, event);
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
- switch (event->type) {
- case LEFTMOUSE: /* Confirm */
- case EVT_RETKEY:
- case EVT_PADENTER: {
- if (event->val == KM_PRESS) {
- decimate_exit(C, op);
+ strcpy(mode_str, TIP_("Decimate Keyframes"));
- return OPERATOR_FINISHED;
- }
- break;
- }
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
- case EVT_ESCKEY: /* Cancel */
- case RIGHTMOUSE: {
- if (event->val == KM_PRESS) {
- reset_bezts(gso);
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
- decimate_exit(C, op);
+ ED_workspace_status_text(C, status_str);
+}
- return OPERATOR_CANCELLED;
- }
- break;
- }
+static void decimate_modal_update(bContext *C, wmOperator *op)
+{
+ /* Perform decimate updates - in response to some user action
+ * (e.g. pressing a key or moving the mouse). */
+ tGraphSliderOp *gso = op->customdata;
- /* Percentage Change... */
- case MOUSEMOVE: /* Calculate new position. */
- {
- if (has_numinput == false) {
- /* Update pose to reflect the new values. */
- graphkeys_decimate_modal_update(C, op);
- }
- break;
- }
- default: {
- if ((event->val == KM_PRESS) && handleNumInput(C, &gso->num, event)) {
- float value;
- float percentage = RNA_property_float_get(op->ptr, gso->percentage_prop);
+ decimate_draw_status(C, gso);
- /* Grab percentage from numeric input, and store this new value for redo
- * NOTE: users see ints, while internally we use a 0-1 float.
- */
- value = percentage * 100.0f;
- applyNumInput(&gso->num, &value);
+ /* Reset keyframe data (so we get back to the original state). */
+ reset_bezts(gso);
- percentage = value / 100.0f;
- RNA_property_float_set(op->ptr, gso->percentage_prop, percentage);
+ /* Apply... */
+ float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
+ /* We don't want to limit the decimation to a certain error margin. */
+ const float error_sq_max = FLT_MAX;
+ decimate_graph_keys(&gso->ac, factor, error_sq_max);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
- /* Update decimate output to reflect the new values. */
- graphkeys_decimate_modal_update(C, op);
- break;
- }
+static int decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
- /* Unhandled event - maybe it was some view manipulation? */
- /* Allow to pass through. */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
- }
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_RUNNING_MODAL;
+ tGraphSliderOp *gso = op->customdata;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ gso->modal_update = decimate_modal_update;
+ ED_slider_allow_overshoot_set(gso->slider, false);
+
+ return invoke_result;
}
-static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
+static int decimate_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -410,13 +428,13 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
tDecimModes mode = RNA_enum_get(op->ptr, "mode");
/* We want to be able to work on all available keyframes. */
- float remove_ratio = 1.0f;
+ float factor = 1.0f;
/* We don't want to limit the decimation to a certain error margin. */
float error_sq_max = FLT_MAX;
switch (mode) {
case DECIM_RATIO:
- remove_ratio = RNA_float_get(op->ptr, "remove_ratio");
+ factor = RNA_float_get(op->ptr, "factor");
break;
case DECIM_ERROR:
error_sq_max = RNA_float_get(op->ptr, "remove_error_margin");
@@ -426,12 +444,12 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
break;
}
- if (remove_ratio == 0.0f || error_sq_max == 0.0f) {
+ if (factor == 0.0f || error_sq_max == 0.0f) {
/* Nothing to remove. */
return OPERATOR_FINISHED;
}
- decimate_graph_keys(&ac, remove_ratio, error_sq_max);
+ decimate_graph_keys(&ac, factor, error_sq_max);
/* Set notifier that keyframes have changed. */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -439,16 +457,16 @@ static int graphkeys_decimate_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C),
- wmOperator *op,
- const PropertyRNA *prop)
+static bool decimate_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
if (STRPREFIX(prop_id, "remove")) {
int mode = RNA_enum_get(op->ptr, "mode");
- if (STREQ(prop_id, "remove_ratio") && mode != DECIM_RATIO) {
+ if (STREQ(prop_id, "factor") && mode != DECIM_RATIO) {
return false;
}
if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) {
@@ -459,9 +477,7 @@ static bool graphkeys_decimate_poll_property(const bContext *UNUSED(C),
return true;
}
-static char *graphkeys_decimate_desc(bContext *UNUSED(C),
- wmOperatorType *UNUSED(op),
- PointerRNA *ptr)
+static char *decimate_desc(bContext *UNUSED(C), wmOperatorType *UNUSED(op), PointerRNA *ptr)
{
if (RNA_enum_get(ptr, "mode") == DECIM_ERROR) {
@@ -497,11 +513,11 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
"Decimate F-Curves by removing keyframes that influence the curve shape the least";
/* API callbacks */
- ot->poll_property = graphkeys_decimate_poll_property;
- ot->get_description = graphkeys_decimate_desc;
- ot->invoke = graphkeys_decimate_invoke;
- ot->modal = graphkeys_decimate_modal;
- ot->exec = graphkeys_decimate_exec;
+ ot->poll_property = decimate_poll_property;
+ ot->get_description = decimate_desc;
+ ot->invoke = decimate_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = decimate_exec;
ot->poll = graphop_editable_keyframes_poll;
/* Flags */
@@ -516,7 +532,7 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
"Which mode to use for decimation");
RNA_def_float_factor(ot->srna,
- "remove_ratio",
+ "factor",
1.0f / 3.0f,
0.0f,
1.0f,
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index 89e7fefd9ac..d78af4c4bcf 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -50,9 +50,6 @@
/** \name Set Up Drivers Editor
* \{ */
-/* Set up UI configuration for Drivers Editor */
-/* NOTE: Currently called from window-manager
- * (new drivers editor window) and RNA (mode switching) */
void ED_drivers_editor_init(bContext *C, ScrArea *area)
{
SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
@@ -96,15 +93,6 @@ void ED_drivers_editor_init(bContext *C, ScrArea *area)
/** \name Active F-Curve
* \{ */
-/**
- * Find 'active' F-Curve.
- * It must be editable, since that's the purpose of these buttons (subject to change).
- * We return the 'wrapper' since it contains valuable context info (about hierarchy),
- * which will need to be freed when the caller is done with it.
- *
- * \note curve-visible flag isn't included,
- * otherwise selecting a curve via list to edit is too cumbersome.
- */
bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -134,7 +122,6 @@ bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
/** \name Operator Polling Callbacks
* \{ */
-/* Check if there are any visible keyframes (for selection tools) */
bool graphop_visible_keyframes_poll(bContext *C)
{
bAnimContext ac;
@@ -187,7 +174,6 @@ bool graphop_visible_keyframes_poll(bContext *C)
return found;
}
-/* Check if there are any visible + editable keyframes (for editing tools) */
bool graphop_editable_keyframes_poll(bContext *C)
{
bAnimContext ac;
@@ -242,7 +228,6 @@ bool graphop_editable_keyframes_poll(bContext *C)
return found;
}
-/* has active F-Curve that's editable */
bool graphop_active_fcurve_poll(bContext *C)
{
bAnimContext ac;
@@ -286,7 +271,6 @@ bool graphop_active_fcurve_poll(bContext *C)
return has_fcurve;
}
-/* has active F-Curve in the context that's editable */
bool graphop_active_editable_fcurve_ctx_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve);
@@ -294,7 +278,6 @@ bool graphop_active_editable_fcurve_ctx_poll(bContext *C)
return ptr.data != NULL;
}
-/* has selected F-Curve that's editable */
bool graphop_selected_fcurve_poll(bContext *C)
{
bAnimContext ac;
diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c
index a12c6053877..a2f31a01a70 100644
--- a/source/blender/editors/space_graph/graph_view.c
+++ b/source/blender/editors/space_graph/graph_view.c
@@ -56,8 +56,6 @@
/** \name Calculate Range
* \{ */
-/* Get the min/max keyframes. */
-/* NOTE: it should return total boundbox, filter for selection only can be argument... */
void get_graph_keyframe_extents(bAnimContext *ac,
float *xmin,
float *xmax,
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 0e2c9b85bc6..40c95d4f382 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -829,7 +829,6 @@ static void graph_space_subtype_item_extend(bContext *UNUSED(C),
RNA_enum_items_add(item, totitem, rna_enum_space_graph_mode_items);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_ipo(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype ipo");
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 6a50f6d42e8..4b8388a0002 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -63,7 +63,6 @@
#define B_NOP -1
#define MAX_IMAGE_INFO_LEN 128
-/* gets active viewer user */
struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
{
bNode *node;
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index d76b1842c94..ade5993cdb9 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -135,7 +135,6 @@ static void draw_render_info(
}
}
-/* used by node view too */
void ED_image_draw_info(Scene *scene,
ARegion *region,
bool color_manage,
@@ -614,11 +613,6 @@ void ED_space_image_grid_steps(SpaceImage *sima,
}
}
-/**
- * Calculate the increment snapping value for UV/image editor based on the zoom factor
- * The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for
- * drawing the grid overlay for the UV/Image editor.
- */
float ED_space_image_increment_snap_value(const int grid_dimesnions,
const float grid_steps[SI_GRID_STEPS_LEN],
const float zoom_factor)
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 05124f49a20..470cff20718 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -177,7 +177,6 @@ void ED_space_image_release_buffer(SpaceImage *sima, ImBuf *ibuf, void *lock)
}
}
-/* Get the SpaceImage flag that is valid for the given ibuf. */
int ED_space_image_get_display_channel_mask(ImBuf *ibuf)
{
int result = (SI_USE_ALPHA | SI_SHOW_ALPHA | SI_SHOW_ZBUF | SI_SHOW_R | SI_SHOW_G | SI_SHOW_B);
@@ -318,7 +317,6 @@ void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float *
}
}
-/* takes event->mval */
void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2])
{
int sx, sy, width, height;
@@ -377,10 +375,6 @@ void ED_image_point_pos__reverse(SpaceImage *sima,
r_co[1] = (co[1] * height * zoomy) + (float)sy;
}
-/**
- * This is more a user-level functionality, for going to `next/prev` used slot,
- * Stepping onto the last unused slot too.
- */
bool ED_image_slot_cycle(struct Image *image, int direction)
{
const int cur = image->render_slot;
@@ -482,7 +476,6 @@ bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
return false;
}
-/* matches clip function */
bool ED_space_image_check_show_maskedit(SpaceImage *sima, Object *obedit)
{
/* check editmode - this is reserved for UV editing */
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 6af0f3a416b..63c537467f7 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -36,11 +36,13 @@ struct wmOperatorType;
extern const char *image_context_dir[]; /* doc access */
/* image_draw.c */
+
void draw_image_main_helpers(const struct bContext *C, struct ARegion *region);
void draw_image_cache(const struct bContext *C, struct ARegion *region);
void draw_image_sample_line(struct SpaceImage *sima);
/* image_ops.c */
+
bool space_image_main_region_poll(struct bContext *C);
bool space_image_view_center_cursor_poll(struct bContext *C);
@@ -59,7 +61,13 @@ void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
#endif
void IMAGE_OT_new(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void IMAGE_OT_open(struct wmOperatorType *ot);
+/**
+ * Called by other space types too.
+ */
void IMAGE_OT_match_movie_length(struct wmOperatorType *ot);
void IMAGE_OT_replace(struct wmOperatorType *ot);
void IMAGE_OT_reload(struct wmOperatorType *ot);
@@ -94,5 +102,9 @@ void IMAGE_OT_tile_remove(struct wmOperatorType *ot);
void IMAGE_OT_tile_fill(struct wmOperatorType *ot);
/* image_panels.c */
+
+/**
+ * Gets active viewer user.
+ */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 478e484924a..f9160774c41 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -728,10 +728,10 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
WM_operator_properties_use_cursor_init(ot);
}
-#ifdef WITH_INPUT_NDOF
-
/** \} */
+#ifdef WITH_INPUT_NDOF
+
/* -------------------------------------------------------------------- */
/** \name NDOF Operator
* \{ */
@@ -1499,7 +1499,6 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
}
}
-/* called by other space types too */
void IMAGE_OT_open(wmOperatorType *ot)
{
/* identifiers */
@@ -1574,7 +1573,6 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* called by other space types too */
void IMAGE_OT_match_movie_length(wmOperatorType *ot)
{
/* identifiers */
@@ -3190,8 +3188,10 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/** \name Sample Image Operator
* \{ */
-/* Returns mouse position in image space. */
-bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2])
+bool ED_space_image_get_position(SpaceImage *sima,
+ struct ARegion *region,
+ int mval[2],
+ float fpos[2])
{
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
@@ -3201,13 +3201,12 @@ bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[
return false;
}
- UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
+ UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
ED_space_image_release_buffer(sima, ibuf, lock);
return true;
}
-/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(
SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
{
@@ -4137,3 +4136,5 @@ void IMAGE_OT_tile_fill(wmOperatorType *ot)
def_fill_tile(ot->srna);
}
+
+/** \} */
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index c4f111264a3..87bff913ff2 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -217,7 +217,6 @@ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_u
}
}
-/* Used for both images and volume file loading. */
ListBase ED_image_filesel_detect_sequences(Main *bmain, wmOperator *op, const bool detect_udim)
{
ListBase ranges;
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 3fbcc8348c8..e81f3b6a490 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -989,7 +989,6 @@ static void image_undosys_foreach_ID_ref(UndoStep *us_p,
}
}
-/* Export for ED_undo_sys. */
void ED_image_undosys_type(UndoType *ut)
{
ut->name = "Image";
@@ -1040,7 +1039,6 @@ ListBase *ED_image_paint_tile_list_get(void)
return &us->paint_tiles;
}
-/* Restore painting image to previous state. Used for anchored and drag-dot style brushes. */
void ED_image_undo_restore(UndoStep *us)
{
ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
@@ -1059,10 +1057,6 @@ static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
return us;
}
-/**
- * The caller is responsible for running #ED_image_undo_push_end,
- * failure to do so causes an invalid state for the undo system.
- */
void ED_image_undo_push_begin(const char *name, int paint_mode)
{
image_undo_push_begin(name, paint_mode);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 516ffcd1e75..dad494e6984 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -1042,7 +1042,6 @@ static void image_space_subtype_item_extend(bContext *UNUSED(C),
/**************************** spacetype *****************************/
-/* only called once, from space/spacetypes.c */
void ED_spacetype_image(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype image");
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 8e37e5fe9a8..2a797fd1a78 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -408,13 +408,14 @@ void FILE_OT_unpack_item(wmOperatorType *ot)
static int make_paths_relative_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
BKE_report(op->reports, RPT_WARNING, "Cannot set relative paths with an unsaved blend file");
return OPERATOR_CANCELLED;
}
- BKE_bpath_relative_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
+ BKE_bpath_relative_convert(bmain, blendfile_path, op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -445,13 +446,14 @@ void FILE_OT_make_paths_relative(wmOperatorType *ot)
static int make_paths_absolute_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (!G.relbase_valid) {
+ if (blendfile_path[0] == '\0') {
BKE_report(op->reports, RPT_WARNING, "Cannot set absolute paths with an unsaved blend file");
return OPERATOR_CANCELLED;
}
- BKE_bpath_absolute_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
+ BKE_bpath_absolute_convert(bmain, blendfile_path, op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 1062b76b1df..ce17450549e 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -299,6 +299,7 @@ static int box_select_exec(bContext *C, wmOperator *op)
}
/* ****** Box Select ****** */
+
void INFO_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index 19c98fb4d17..bcf26743030 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -721,11 +721,6 @@ static void stats_row(int col1,
BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
}
-/**
- * \param v3d_local: Pass this argument to calculate view-port local statistics.
- * Note that this must only be used for local-view, otherwise report specific statistics
- * will be written into the global scene statistics giving incorrect results.
- */
void ED_info_draw_stats(
Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height)
{
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index e56bb44b1e6..1d28aace7f2 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -264,7 +264,6 @@ static void info_header_region_message_subscribe(const wmRegionMessageSubscribeP
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_info(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype info");
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index e656155fb13..cc14abd8bb3 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -303,13 +303,6 @@ static bool textview_draw_string(TextViewDrawState *tds,
return true;
}
-/**
- * \param r_mval_pick_item: The resulting item clicked on using \a mval_init.
- * Set from the void pointer which holds the current iterator.
- * Its type depends on the data being iterated over.
- * \param r_mval_pick_offset: The offset in bytes of the \a mval_init.
- * Use for selection.
- */
int textview_draw(TextViewContext *tvc,
const bool do_draw,
const int mval_init[2],
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index 7520dbce191..96f537b4b97 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -73,6 +73,13 @@ typedef struct TextViewContext {
} TextViewContext;
+/**
+ * \param r_mval_pick_item: The resulting item clicked on using \a mval_init.
+ * Set from the void pointer which holds the current iterator.
+ * Its type depends on the data being iterated over.
+ * \param r_mval_pick_offset: The offset in bytes of the \a mval_init.
+ * Use for selection.
+ */
int textview_draw(struct TextViewContext *tvc,
const bool do_draw,
const int mval_init[2],
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 1b87a8c6b9d..47af7a66f6f 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -629,7 +629,6 @@ void NLA_OT_action_unlink(wmOperatorType *ot)
/* ******************** Add Tracks Operator ***************************** */
/* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
-/* helper - add NLA Tracks alongside existing ones */
bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
{
ListBase anim_data = {NULL, NULL};
@@ -678,7 +677,6 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
return added;
}
-/* helper - add NLA Tracks to empty (and selected) AnimData blocks */
bool nlaedit_add_tracks_empty(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index bf2d20cf4c9..12f0011b499 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -65,9 +65,6 @@
/* Action-Line ---------------------- */
-/* get colors for drawing Action-Line
- * NOTE: color returned includes fine-tuned alpha!
- */
void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
{
if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
@@ -111,11 +108,11 @@ static void nla_action_draw_keyframes(
/* draw a darkened region behind the strips
* - get and reset the background color, this time without the alpha to stand out better
- * (amplified alpha is used instead)
+ * (amplified alpha is used instead, but clamped to avoid 100% opacity)
*/
float color[4];
nla_action_get_color(adt, act, color);
- color[3] *= 2.5f;
+ color[3] = min_ff(0.7f, color[3] * 2.5f);
GPUVertFormat *format = immVertexFormat();
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -786,6 +783,11 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
case ANIMTYPE_NLAACTION: {
AnimData *adt = ale->adt;
+ /* Draw the manually set intended playback frame range highlight. */
+ if (ale->data) {
+ ANIM_draw_action_framerange(adt, ale->data, v2d, ymin, ymax);
+ }
+
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 62f8906d136..1376dade659 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -71,7 +71,6 @@
/** \name Public Utilities
* \{ */
-/* Perform validation for blending/extend settings */
void ED_nla_postop_refresh(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
@@ -205,7 +204,6 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot)
/** \name Disable Tweak-Mode Operator
* \{ */
-/* NLA Editor internal API function for exiting tweak-mode. */
bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
{
ListBase anim_data = {NULL, NULL};
@@ -2193,8 +2191,19 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
* and recalculate the extents of the action now that it has been scaled
* but leave everything else alone
*/
+ const float start = nlastrip_get_frame(strip, strip->actstart, NLATIME_CONVERT_MAP);
+ const float end = nlastrip_get_frame(strip, strip->actend, NLATIME_CONVERT_MAP);
+
+ if (strip->act->flag & ACT_FRAME_RANGE) {
+ strip->act->frame_start = nlastrip_get_frame(
+ strip, strip->act->frame_start, NLATIME_CONVERT_MAP);
+ strip->act->frame_end = nlastrip_get_frame(
+ strip, strip->act->frame_end, NLATIME_CONVERT_MAP);
+ }
+
strip->scale = 1.0f;
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+ strip->actstart = start;
+ strip->actend = end;
ale->update |= ANIM_UPDATE_DEPS;
}
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index 9a9ea161f56..dd322dd2ad1 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -75,6 +75,9 @@ enum eNlaEdit_Snap_Mode {
/* --- */
+/**
+ * NLA Editor internal API function for exiting tweak-mode.
+ */
bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo);
void NLA_OT_tweakmode_enter(wmOperatorType *ot);
@@ -121,7 +124,13 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot);
/* **************************************** */
/* nla_channels.c */
+/**
+ * Helper - add NLA Tracks alongside existing ones.
+ */
bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel);
+/**
+ * helper - add NLA Tracks to empty (and selected) AnimData blocks.
+ */
bool nlaedit_add_tracks_empty(bAnimContext *ac);
/* --- */
@@ -139,9 +148,18 @@ void NLA_OT_selected_objects_add(wmOperatorType *ot);
/* **************************************** */
/* nla_ops.c */
+/**
+ * Tweak-mode is NOT enabled.
+ */
bool nlaop_poll_tweakmode_off(bContext *C);
+/**
+ * Tweak-mode IS enabled.
+ */
bool nlaop_poll_tweakmode_on(bContext *C);
+/**
+ * Is tweak-mode enabled - for use in NLA operator code.
+ */
bool nlaedit_is_tweakmode_on(bAnimContext *ac);
/* --- */
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 28f194877fa..33449bed798 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -39,7 +39,6 @@
/* ************************** poll callbacks for operators **********************************/
-/* Tweak-mode is NOT enabled. */
bool nlaop_poll_tweakmode_off(bContext *C)
{
Scene *scene;
@@ -62,7 +61,6 @@ bool nlaop_poll_tweakmode_off(bContext *C)
return 1;
}
-/* Tweak-mode IS enabled. */
bool nlaop_poll_tweakmode_on(bContext *C)
{
Scene *scene;
@@ -85,7 +83,6 @@ bool nlaop_poll_tweakmode_on(bContext *C)
return 1;
}
-/* is tweak-mode enabled - for use in NLA operator code */
bool nlaedit_is_tweakmode_on(bAnimContext *ac)
{
if (ac && ac->scene) {
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 8b44c26f07c..0771153c5f5 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -591,7 +591,6 @@ static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_nla(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype nla");
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index e88d61fe880..94b67e43651 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -39,6 +39,7 @@ set(INC
set(SRC
drawnode.cc
+ link_drag_search.cc
node_add.cc
node_context_path.cc
node_draw.cc
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index cf79893a8cb..bbfd886ce56 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -22,8 +22,6 @@
* \brief lower level node drawing for nodes (boarders, headers etc), also node layout.
*/
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
#include "BLI_system.h"
#include "BLI_threads.h"
@@ -31,7 +29,6 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
-#include "DNA_text_types.h"
#include "DNA_userdef_types.h"
#include "BKE_context.h"
@@ -79,6 +76,8 @@
#include "NOD_texture.h"
#include "node_intern.hh" /* own include */
+using blender::float2;
+
/* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */
#define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME
@@ -236,6 +235,7 @@ static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), Pointe
static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE);
if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
NODE_MAP_RANGE_SMOOTHSTEP,
@@ -250,22 +250,50 @@ static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
-static int node_resize_area_default(bNode *node, int x, int y)
+NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y)
{
+ if (node->type == NODE_FRAME) {
+ const float size = 10.0f;
+ NodeFrame *data = (NodeFrame *)node->storage;
+
+ /* shrinking frame size is determined by child nodes */
+ if (!(data->flag & NODE_FRAME_RESIZEABLE)) {
+ return NODE_RESIZE_NONE;
+ }
+
+ NodeResizeDirection dir = NODE_RESIZE_NONE;
+
+ const rctf &totr = node->totr;
+ if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
+ dir |= NODE_RESIZE_RIGHT;
+ }
+ if (x >= totr.xmin && x < totr.xmin + size && y >= totr.ymin && y < totr.ymax) {
+ dir |= NODE_RESIZE_LEFT;
+ }
+ if (x >= totr.xmin && x < totr.xmax && y >= totr.ymax - size && y < totr.ymax) {
+ dir |= NODE_RESIZE_TOP;
+ }
+ if (x >= totr.xmin && x < totr.xmax && y >= totr.ymin && y < totr.ymin + size) {
+ dir |= NODE_RESIZE_BOTTOM;
+ }
+
+ return dir;
+ }
+
if (node->flag & NODE_HIDDEN) {
- rctf totr = node->totr;
/* right part of node */
+ rctf totr = node->totr;
totr.xmin = node->totr.xmax - 1.0f * U.widget_unit;
if (BLI_rctf_isect_pt(&totr, x, y)) {
return NODE_RESIZE_RIGHT;
}
- return 0;
+ return NODE_RESIZE_NONE;
}
const float size = NODE_RESIZE_MARGIN;
- rctf totr = node->totr;
- int dir = 0;
+ const rctf &totr = node->totr;
+ NodeResizeDirection dir = NODE_RESIZE_NONE;
if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
dir |= NODE_RESIZE_RIGHT;
@@ -284,225 +312,6 @@ static void node_draw_buttons_group(uiLayout *layout, bContext *C, PointerRNA *p
layout, C, ptr, "node_tree", nullptr, nullptr, nullptr, UI_TEMPLATE_ID_FILTER_ALL, nullptr);
}
-/* XXX Does a bounding box update by iterating over all children.
- * Not ideal to do this in every draw call, but doing as transform callback doesn't work,
- * since the child node totr rects are not updated properly at that point.
- */
-static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree, bNode *node)
-{
- const float margin = 1.5f * U.widget_unit;
- NodeFrame *data = (NodeFrame *)node->storage;
-
- /* init rect from current frame size */
- rctf rect;
- node_to_view(node, node->offsetx, node->offsety, &rect.xmin, &rect.ymax);
- node_to_view(
- node, node->offsetx + node->width, node->offsety - node->height, &rect.xmax, &rect.ymin);
-
- /* frame can be resized manually only if shrinking is disabled or no children are attached */
- data->flag |= NODE_FRAME_RESIZEABLE;
- /* for shrinking bbox, initialize the rect from first child node */
- bool bbinit = (data->flag & NODE_FRAME_SHRINK);
- /* fit bounding box to all children */
- LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
- if (tnode->parent != node) {
- continue;
- }
-
- /* add margin to node rect */
- rctf noderect = tnode->totr;
- noderect.xmin -= margin;
- noderect.xmax += margin;
- noderect.ymin -= margin;
- noderect.ymax += margin;
-
- /* first child initializes frame */
- if (bbinit) {
- bbinit = false;
- rect = noderect;
- data->flag &= ~NODE_FRAME_RESIZEABLE;
- }
- else {
- BLI_rctf_union(&rect, &noderect);
- }
- }
-
- /* now adjust the frame size from view-space bounding box */
- node_from_view(node, rect.xmin, rect.ymax, &node->offsetx, &node->offsety);
- float xmax, ymax;
- node_from_view(node, rect.xmax, rect.ymin, &xmax, &ymax);
- node->width = xmax - node->offsetx;
- node->height = -ymax + node->offsety;
-
- node->totr = rect;
-}
-
-static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float aspect)
-{
- /* XXX font id is crap design */
- const int fontid = UI_style_get()->widgetlabel.uifont_id;
- NodeFrame *data = (NodeFrame *)node->storage;
- const float font_size = data->label_size / aspect;
-
- char label[MAX_NAME];
- nodeLabel(ntree, node, label, sizeof(label));
-
- BLF_enable(fontid, BLF_ASPECT);
- BLF_aspect(fontid, aspect, aspect, 1.0f);
- /* clamp otherwise it can suck up a LOT of memory */
- BLF_size(fontid, MIN2(24.0f, font_size), U.dpi);
-
- /* title color */
- int color_id = node_get_colorid(node);
- uchar color[3];
- UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
- BLF_color3ubv(fontid, color);
-
- const float margin = (float)(NODE_DY / 4);
- const float width = BLF_width(fontid, label, sizeof(label));
- const float ascender = BLF_ascender(fontid);
- const int label_height = ((margin / aspect) + (ascender * aspect));
-
- /* 'x' doesn't need aspect correction */
- rctf *rct = &node->totr;
- /* XXX a bit hacky, should use separate align values for x and y */
- float x = BLI_rctf_cent_x(rct) - (0.5f * width);
- float y = rct->ymax - label_height;
-
- /* label */
- const bool has_label = node->label[0] != '\0';
- if (has_label) {
- BLF_position(fontid, x, y, 0);
- BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
- }
-
- /* draw text body */
- if (node->id) {
- Text *text = (Text *)node->id;
- const int line_height_max = BLF_height_max(fontid);
- const float line_spacing = (line_height_max * aspect);
- const float line_width = (BLI_rctf_size_x(rct) - margin) / aspect;
-
- /* 'x' doesn't need aspect correction */
- x = rct->xmin + margin;
- y = rct->ymax - label_height - (has_label ? line_spacing : 0);
-
- /* early exit */
- int y_min = y + ((margin * 2) - (y - rct->ymin));
-
- BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
- BLF_clipping(fontid,
- rct->xmin,
- /* round to avoid clipping half-way through a line */
- y - (floorf(((y - rct->ymin) - (margin * 2)) / line_spacing) * line_spacing),
- rct->xmin + line_width,
- rct->ymax);
-
- BLF_wordwrap(fontid, line_width);
-
- LISTBASE_FOREACH (TextLine *, line, &text->lines) {
- struct ResultBLF info;
- if (line->line[0]) {
- BLF_position(fontid, x, y, 0);
- BLF_draw_ex(fontid, line->line, line->len, &info);
- y -= line_spacing * info.lines;
- }
- else {
- y -= line_spacing;
- }
- if (y < y_min) {
- break;
- }
- }
-
- BLF_disable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
- }
-
- BLF_disable(fontid, BLF_ASPECT);
-}
-
-static void node_draw_frame(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
-
- /* skip if out of view */
- if (BLI_rctf_isect(&node->totr, &region->v2d.cur, nullptr) == false) {
- UI_block_end(C, node->block);
- node->block = nullptr;
- return;
- }
-
- float color[4];
- UI_GetThemeColor4fv(TH_NODE_FRAME, color);
- const float alpha = color[3];
-
- /* shadow */
- node_draw_shadow(snode, node, BASIS_RAD, alpha);
-
- /* body */
- if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], alpha);
- }
- else {
- UI_GetThemeColor4fv(TH_NODE_FRAME, color);
- }
-
- const rctf *rct = &node->totr;
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_4fv(rct, true, BASIS_RAD, color);
-
- /* outline active and selected emphasis */
- if (node->flag & SELECT) {
- if (node->flag & NODE_ACTIVE) {
- UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color);
- }
- else {
- UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
- }
-
- UI_draw_roundbox_aa(rct, false, BASIS_RAD, color);
- }
-
- /* label and text */
- node_draw_frame_label(ntree, node, snode->runtime->aspect);
-
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
-}
-
-static int node_resize_area_frame(bNode *node, int x, int y)
-{
- const float size = 10.0f;
- NodeFrame *data = (NodeFrame *)node->storage;
- rctf totr = node->totr;
- int dir = 0;
-
- /* shrinking frame size is determined by child nodes */
- if (!(data->flag & NODE_FRAME_RESIZEABLE)) {
- return 0;
- }
-
- if (x >= totr.xmax - size && x < totr.xmax && y >= totr.ymin && y < totr.ymax) {
- dir |= NODE_RESIZE_RIGHT;
- }
- if (x >= totr.xmin && x < totr.xmin + size && y >= totr.ymin && y < totr.ymax) {
- dir |= NODE_RESIZE_LEFT;
- }
- if (x >= totr.xmin && x < totr.xmax && y >= totr.ymax - size && y < totr.ymax) {
- dir |= NODE_RESIZE_TOP;
- }
- if (x >= totr.xmin && x < totr.xmax && y >= totr.ymin && y < totr.ymin + size) {
- dir |= NODE_RESIZE_BOTTOM;
- }
-
- return dir;
-}
-
static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "label_size", DEFAULT_FLAGS, IFACE_("Label Size"), ICON_NONE);
@@ -510,124 +319,6 @@ static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA
uiItemR(layout, ptr, "text", DEFAULT_FLAGS, nullptr, ICON_NONE);
}
-#define NODE_REROUTE_SIZE 8.0f
-
-static void node_draw_reroute_prepare(const bContext *UNUSED(C),
- bNodeTree *UNUSED(ntree),
- bNode *node)
-{
- /* get "global" coords */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
-
- /* reroute node has exactly one input and one output, both in the same place */
- bNodeSocket *nsock = (bNodeSocket *)node->outputs.first;
- nsock->locx = locx;
- nsock->locy = locy;
-
- nsock = (bNodeSocket *)node->inputs.first;
- nsock->locx = locx;
- nsock->locy = locy;
-
- const float size = NODE_REROUTE_SIZE;
- node->width = size * 2;
- node->totr.xmin = locx - size;
- node->totr.xmax = locx + size;
- node->totr.ymax = locy + size;
- node->totr.ymin = locy - size;
-}
-
-static void node_draw_reroute(const bContext *C,
- ARegion *region,
- SpaceNode *UNUSED(snode),
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
- char showname[128]; /* 128 used below */
- rctf *rct = &node->totr;
-
- /* skip if out of view */
- if (node->totr.xmax < region->v2d.cur.xmin || node->totr.xmin > region->v2d.cur.xmax ||
- node->totr.ymax < region->v2d.cur.ymin || node->totr.ymin > region->v2d.cur.ymax) {
- UI_block_end(C, node->block);
- node->block = nullptr;
- return;
- }
-
- /* XXX only kept for debugging
- * selection state is indicated by socket outline below!
- */
-#if 0
- float size = NODE_REROUTE_SIZE;
-
- /* body */
- float debug_color[4];
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_GetThemeColor4fv(TH_NODE, debug_color);
- UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
-
- /* outline active and selected emphasis */
- if (node->flag & SELECT) {
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
- /* Using different shades of #TH_TEXT_HI for the emphasis, like triangle. */
- if (node->flag & NODE_ACTIVE) {
- UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, 0, -40, debug_color);
- }
- else {
- UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, -20, -120, debug_color);
- }
- UI_draw_roundbox_4fv(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
-
- GPU_line_smooth(false);
- GPU_blend(GPU_BLEND_NONE);
- }
-#endif
-
- if (node->label[0] != '\0') {
- /* draw title (node label) */
- BLI_strncpy(showname, node->label, sizeof(showname));
- uiDefBut(node->block,
- UI_BTYPE_LABEL,
- 0,
- showname,
- (int)(rct->xmin - NODE_DYS),
- (int)(rct->ymax),
- (short)512,
- (short)NODE_DY,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
-
- /* only draw input socket. as they all are placed on the same position.
- * highlight also if node itself is selected, since we don't display the node body separately!
- */
- node_draw_sockets(&region->v2d, C, ntree, node, false, node->flag & SELECT);
-
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
-}
-
-/* Special tweak area for reroute node.
- * Since this node is quite small, we use a larger tweak area for grabbing than for selection.
- */
-static int node_tweak_area_reroute(bNode *node, int x, int y)
-{
- /* square of tweak radius */
- const float tweak_radius_sq = square_f(24.0f);
-
- bNodeSocket *sock = (bNodeSocket *)node->inputs.first;
- float dx = sock->locx - x;
- float dy = sock->locy - y;
- return (dx * dx + dy * dy <= tweak_radius_sq);
-}
-
static void node_common_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
@@ -635,15 +326,7 @@ static void node_common_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_draw_buttons_group;
break;
case NODE_FRAME:
- ntype->draw_nodetype = node_draw_frame;
- ntype->draw_nodetype_prepare = node_draw_frame_prepare;
ntype->draw_buttons_ex = node_buts_frame_ex;
- ntype->resize_area_func = node_resize_area_frame;
- break;
- case NODE_REROUTE:
- ntype->draw_nodetype = node_draw_reroute;
- ntype->draw_nodetype_prepare = node_draw_reroute_prepare;
- ntype->tweak_area_func = node_tweak_area_reroute;
break;
}
}
@@ -1412,763 +1095,6 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
uiTemplateImage(layout, C, ptr, "image", &iuserptr, false, true);
}
-static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- uiLayout *col, *row;
-
- uiTemplateID(layout,
- C,
- ptr,
- "scene",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE);
-
- PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
- const char *layer_name;
- if (!(RNA_property_enum_identifier(
- C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) {
- return;
- }
-
- PointerRNA scn_ptr;
- char scene_name[MAX_ID_NAME - 2];
- scn_ptr = RNA_pointer_get(ptr, "scene");
- RNA_string_get(&scn_ptr, "name", scene_name);
-
- PointerRNA op_ptr;
- uiItemFullO(
- row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "layer", layer_name);
- RNA_string_set(&op_ptr, "scene", scene_name);
-}
-
-static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- col = uiLayoutColumn(layout, false);
- const int filter = RNA_enum_get(ptr, "filter_type");
- const int reference = RNA_boolean_get(ptr, "use_variable_size");
-
- uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (filter != R_FILTER_FAST_GAUSS) {
- uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (!reference) {
- uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_boolean_get(ptr, "use_relative")) {
- uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
- }
- else {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
- }
- uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Center:"), ICON_NONE);
- uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
-
- uiItemS(layout);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemS(layout);
-
- uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bilateralblur(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiLayout *sub, *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
- uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
- uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateID(layout,
- C,
- ptr,
- "scene",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
- uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE);
- uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE);
- uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE);
-}
-
-/* glare node */
-static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") != 1) {
- uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") != 0) {
- uiItemR(
- layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
- }
-
- uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "glare_type") == 0) {
- uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- }
- if (RNA_enum_get(ptr, "glare_type") == 1) {
- uiItemR(layout, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE);
- if (RNA_enum_get(ptr, "tonemap_type") == 0) {
- uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(col, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
- uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Speed:"), ICON_NONE);
- uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);
- uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
-
- uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- if (RNA_boolean_get(ptr, "relative")) {
- uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
- }
-}
-
-static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(col, ptr, "factor", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_double_edge_mask(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
- uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
- uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *sub, *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "premul", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- switch (RNA_enum_get(ptr, "mode")) {
- case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
- uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, nullptr, ICON_NONE);
- break;
- case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
- uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, nullptr, ICON_NONE);
- break;
- }
-}
-
-static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_distance_matte(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- col = uiLayoutColumn(layout, true);
-
- uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "limit_method") == 0) {
- uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_boolean_get(ptr, "use_unspill") == true) {
- uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- /* Removed for now. */
- // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- /* Removed for now. */
- // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_channel_matte(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
-
- uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "limit_method") == 0) {
- uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- }
-
- uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "index", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
-
- if (multilayer) {
- uiItemL(layout, IFACE_("Path:"), ICON_NONE);
- }
- else {
- uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
- }
- uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE);
-}
-static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- Scene *scene = CTX_data_scene(C);
- PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- PointerRNA active_input_ptr, op_ptr;
- uiLayout *row, *col;
- const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
- const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
- const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
-
- node_composit_buts_file_output(layout, C, ptr);
- uiTemplateImageSettings(layout, &imfptr, false);
-
- /* disable stereo output for multilayer, too much work for something that no one will use */
- /* if someone asks for that we can implement it */
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
- }
-
- uiItemS(layout);
-
- uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket");
-
- row = uiLayoutRow(layout, false);
- col = uiLayoutColumn(row, true);
-
- const int active_index = RNA_int_get(ptr, "active_input_index");
- /* using different collection properties if multilayer format is enabled */
- if (multilayer) {
- uiTemplateList(col,
- C,
- "UI_UL_list",
- "file_output_node",
- ptr,
- "layer_slots",
- ptr,
- "active_input_index",
- nullptr,
- 0,
- 0,
- 0,
- 0,
- UI_TEMPLATE_LIST_FLAG_NONE);
- RNA_property_collection_lookup_int(
- ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
- }
- else {
- uiTemplateList(col,
- C,
- "UI_UL_list",
- "file_output_node",
- ptr,
- "file_slots",
- ptr,
- "active_input_index",
- nullptr,
- 0,
- 0,
- 0,
- 0,
- UI_TEMPLATE_LIST_FLAG_NONE);
- RNA_property_collection_lookup_int(
- ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
- }
- /* XXX collection lookup does not return the ID part of the pointer,
- * setting this manually here */
- active_input_ptr.owner_id = ptr->owner_id;
-
- col = uiLayoutColumn(row, true);
- wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
- uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_enum_set(&op_ptr, "direction", 1);
- uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_enum_set(&op_ptr, "direction", 2);
-
- if (active_input_ptr.data) {
- if (multilayer) {
- col = uiLayoutColumn(layout, true);
-
- uiItemL(col, IFACE_("Layer:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemFullO(row,
- "NODE_OT_output_file_remove_active_socket",
- "",
- ICON_X,
- nullptr,
- WM_OP_EXEC_DEFAULT,
- UI_ITEM_R_ICON_ONLY,
- nullptr);
- }
- else {
- col = uiLayoutColumn(layout, true);
-
- uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemFullO(row,
- "NODE_OT_output_file_remove_active_socket",
- "",
- ICON_X,
- nullptr,
- WM_OP_EXEC_DEFAULT,
- UI_ITEM_R_ICON_ONLY,
- nullptr);
-
- /* format details for individual files */
- imfptr = RNA_pointer_get(&active_input_ptr, "format");
-
- col = uiLayoutColumn(layout, true);
- uiItemL(col, IFACE_("Format:"), ICON_NONE);
- uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
- const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format");
-
- if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) {
- uiItemR(col, &active_input_ptr, "save_as_render", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, use_node_format == false);
- uiTemplateImageSettings(col, &imfptr, false);
-
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
- }
- }
- }
-}
-
-static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
- uiLayout *row;
- uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE);
- uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE);
- }
-}
-
-static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "channel", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *split, *col, *row;
-
- uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "correction_method") == 0) {
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "lift", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "gain", true, true, true, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "offset", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "power", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(split, false);
- uiTemplateColorPicker(col, ptr, "slope", true, true, false, true);
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-static void node_composit_buts_colorbalance_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (RNA_enum_get(ptr, "correction_method") == 0) {
-
- uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
- uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true);
- uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true);
- uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true);
- uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "power", true, true, false, true);
- uiItemR(layout, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true);
- uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
@@ -2190,260 +1116,6 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-}
-
-static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- PointerRNA clipptr;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- clipptr = RNA_pointer_get(ptr, "clip");
-
- uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings");
-}
-
-static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (!node->id) {
- return;
- }
-
- uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_composit_buts_colorcorrection(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, "", ICON_NONE);
- uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemL(row, IFACE_("Lift"), ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Master"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Highlights"), ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Midtones"), ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, IFACE_("Shadows"), ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE);
- row = layout;
- uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemL(row, IFACE_("Lift"), ICON_NONE);
- uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "check", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_switch_view_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
-{
- uiItemFullO(layout,
- "NODE_OT_switch_view_update",
- "Update Views",
- ICON_FILE_REFRESH,
- nullptr,
- WM_OP_INVOKE_DEFAULT,
- 0,
- nullptr);
-}
-
-static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE); /* UNUSED */
- uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
static void node_composit_backdrop_viewer(
SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
{
@@ -2563,227 +1235,6 @@ static void node_composit_backdrop_ellipsemask(
immUnbindProgram();
}
-static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
- uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "tile_order") == 0) {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "mask",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
- uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
- uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- nullptr,
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- uiLayout *col;
- PointerRNA tracking_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, true);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
- }
-}
-
-static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */
-
- uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- uiLayout *col;
- PointerRNA tracking_ptr;
- NodeTrackPosData *data = (NodeTrackPosData *)node->storage;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
-
- object = BKE_tracking_object_get_named(tracking, data->tracking_object);
- if (object) {
- PointerRNA object_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
-
- uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
- }
- else {
- uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA);
- }
-
- uiItemR(layout, ptr, "position", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
- uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- }
-}
-
-static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage;
-
- uiTemplateID(layout,
- C,
- ptr,
- "clip",
- nullptr,
- "CLIP_OT_open",
- nullptr,
- UI_TEMPLATE_ID_FILTER_ALL,
- false,
- nullptr);
-
- if (node->id) {
- MovieClip *clip = (MovieClip *)node->id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- uiLayout *col;
- PointerRNA tracking_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
-
- col = uiLayoutColumn(layout, false);
- uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
-
- object = BKE_tracking_object_get_named(tracking, data->tracking_object);
- if (object) {
- PointerRNA object_ptr;
-
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
-
- uiItemPointerR(
- col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA);
- }
- else {
- uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
- }
- }
-
- uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout),
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
-{
-}
-
-static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
-}
-
static void node_composit_buts_cryptomatte_legacy(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
@@ -2859,31 +1310,6 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *C, Pointe
uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
}
-static void node_composit_buts_brightcontrast(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
-#ifndef WITH_OPENIMAGEDENOISE
- uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
-#else
- /* Always supported through Accelerate framework BNNS on macOS. */
-# ifndef __APPLE__
- if (!BLI_cpu_support_sse41()) {
- uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
- }
-# endif
-#endif
-
- uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
- uiItemR(layout, ptr, "prefilter", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2892,15 +1318,6 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_composit_buts_image;
ntype->draw_buttons_ex = node_composit_buts_image_ex;
break;
- case CMP_NODE_R_LAYERS:
- ntype->draw_buttons = node_composit_buts_viewlayers;
- break;
- case CMP_NODE_NORMAL:
- ntype->draw_buttons = node_buts_normal;
- break;
- case CMP_NODE_CURVE_VEC:
- ntype->draw_buttons = node_buts_curvevec;
- break;
case CMP_NODE_CURVE_RGB:
ntype->draw_buttons = node_buts_curvecol;
break;
@@ -2910,213 +1327,34 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_RGB:
ntype->draw_buttons = node_buts_rgb;
break;
- case CMP_NODE_FLIP:
- ntype->draw_buttons = node_composit_buts_flip;
- break;
- case CMP_NODE_SPLITVIEWER:
- ntype->draw_buttons = node_composit_buts_splitviewer;
- break;
case CMP_NODE_MIX_RGB:
ntype->draw_buttons = node_buts_mix_rgb;
break;
case CMP_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
- case CMP_NODE_CROP:
- ntype->draw_buttons = node_composit_buts_crop;
- break;
- case CMP_NODE_BLUR:
- ntype->draw_buttons = node_composit_buts_blur;
- break;
- case CMP_NODE_DBLUR:
- ntype->draw_buttons = node_composit_buts_dblur;
- break;
- case CMP_NODE_BILATERALBLUR:
- ntype->draw_buttons = node_composit_buts_bilateralblur;
- break;
- case CMP_NODE_DEFOCUS:
- ntype->draw_buttons = node_composit_buts_defocus;
- break;
- case CMP_NODE_ANTIALIASING:
- ntype->draw_buttons = node_composit_buts_antialiasing;
- break;
- case CMP_NODE_GLARE:
- ntype->draw_buttons = node_composit_buts_glare;
- break;
- case CMP_NODE_TONEMAP:
- ntype->draw_buttons = node_composit_buts_tonemap;
- break;
- case CMP_NODE_LENSDIST:
- ntype->draw_buttons = node_composit_buts_lensdist;
- break;
- case CMP_NODE_VECBLUR:
- ntype->draw_buttons = node_composit_buts_vecblur;
- break;
- case CMP_NODE_FILTER:
- ntype->draw_buttons = node_composit_buts_filter;
- break;
- case CMP_NODE_MAP_VALUE:
- ntype->draw_buttons = node_composit_buts_map_value;
- break;
- case CMP_NODE_MAP_RANGE:
- ntype->draw_buttons = node_composit_buts_map_range;
- break;
case CMP_NODE_TIME:
ntype->draw_buttons = node_buts_time;
break;
- case CMP_NODE_ALPHAOVER:
- ntype->draw_buttons = node_composit_buts_alphaover;
- break;
case CMP_NODE_TEXTURE:
ntype->draw_buttons = node_buts_texture;
break;
- case CMP_NODE_DILATEERODE:
- ntype->draw_buttons = node_composit_buts_dilateerode;
- break;
- case CMP_NODE_INPAINT:
- ntype->draw_buttons = node_composit_buts_inpaint;
- break;
- case CMP_NODE_DESPECKLE:
- ntype->draw_buttons = node_composit_buts_despeckle;
- break;
- case CMP_NODE_OUTPUT_FILE:
- ntype->draw_buttons = node_composit_buts_file_output;
- ntype->draw_buttons_ex = node_composit_buts_file_output_ex;
- break;
- case CMP_NODE_DIFF_MATTE:
- ntype->draw_buttons = node_composit_buts_diff_matte;
- break;
- case CMP_NODE_DIST_MATTE:
- ntype->draw_buttons = node_composit_buts_distance_matte;
- break;
- case CMP_NODE_COLOR_SPILL:
- ntype->draw_buttons = node_composit_buts_color_spill;
- break;
- case CMP_NODE_CHROMA_MATTE:
- ntype->draw_buttons = node_composit_buts_chroma_matte;
- break;
- case CMP_NODE_COLOR_MATTE:
- ntype->draw_buttons = node_composit_buts_color_matte;
- break;
- case CMP_NODE_SCALE:
- ntype->draw_buttons = node_composit_buts_scale;
- break;
- case CMP_NODE_ROTATE:
- ntype->draw_buttons = node_composit_buts_rotate;
- break;
- case CMP_NODE_CHANNEL_MATTE:
- ntype->draw_buttons = node_composit_buts_channel_matte;
- break;
- case CMP_NODE_LUMA_MATTE:
- ntype->draw_buttons = node_composit_buts_luma_matte;
- break;
- case CMP_NODE_MAP_UV:
- ntype->draw_buttons = node_composit_buts_map_uv;
- break;
- case CMP_NODE_ID_MASK:
- ntype->draw_buttons = node_composit_buts_id_mask;
- break;
- case CMP_NODE_DOUBLEEDGEMASK:
- ntype->draw_buttons = node_composit_buts_double_edge_mask;
- break;
case CMP_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
- case CMP_NODE_INVERT:
- ntype->draw_buttons = node_composit_buts_invert;
- break;
- case CMP_NODE_PREMULKEY:
- ntype->draw_buttons = node_composit_buts_premulkey;
- break;
- case CMP_NODE_VIEW_LEVELS:
- ntype->draw_buttons = node_composit_buts_view_levels;
- break;
- case CMP_NODE_COLORBALANCE:
- ntype->draw_buttons = node_composit_buts_colorbalance;
- ntype->draw_buttons_ex = node_composit_buts_colorbalance_ex;
- break;
case CMP_NODE_HUECORRECT:
ntype->draw_buttons = node_composit_buts_huecorrect;
break;
- case CMP_NODE_ZCOMBINE:
- ntype->draw_buttons = node_composit_buts_zcombine;
- break;
case CMP_NODE_COMBYCCA:
case CMP_NODE_SEPYCCA:
ntype->draw_buttons = node_composit_buts_ycc;
break;
- case CMP_NODE_MOVIECLIP:
- ntype->draw_buttons = node_composit_buts_movieclip;
- ntype->draw_buttons_ex = node_composit_buts_movieclip_ex;
- break;
- case CMP_NODE_STABILIZE2D:
- ntype->draw_buttons = node_composit_buts_stabilize2d;
- break;
- case CMP_NODE_TRANSFORM:
- ntype->draw_buttons = node_composit_buts_transform;
- break;
- case CMP_NODE_TRANSLATE:
- ntype->draw_buttons = node_composit_buts_translate;
- break;
- case CMP_NODE_MOVIEDISTORTION:
- ntype->draw_buttons = node_composit_buts_moviedistortion;
- break;
- case CMP_NODE_COLORCORRECTION:
- ntype->draw_buttons = node_composit_buts_colorcorrection;
- ntype->draw_buttons_ex = node_composit_buts_colorcorrection_ex;
- break;
- case CMP_NODE_SETALPHA:
- ntype->draw_buttons = node_composit_buts_set_alpha;
- break;
- case CMP_NODE_SWITCH:
- ntype->draw_buttons = node_composit_buts_switch;
- break;
- case CMP_NODE_SWITCH_VIEW:
- ntype->draw_buttons_ex = node_composit_buts_switch_view_ex;
- break;
case CMP_NODE_MASK_BOX:
- ntype->draw_buttons = node_composit_buts_boxmask;
ntype->draw_backdrop = node_composit_backdrop_boxmask;
break;
case CMP_NODE_MASK_ELLIPSE:
- ntype->draw_buttons = node_composit_buts_ellipsemask;
ntype->draw_backdrop = node_composit_backdrop_ellipsemask;
break;
- case CMP_NODE_BOKEHIMAGE:
- ntype->draw_buttons = node_composit_buts_bokehimage;
- break;
- case CMP_NODE_BOKEHBLUR:
- ntype->draw_buttons = node_composit_buts_bokehblur;
- break;
- case CMP_NODE_VIEWER:
- ntype->draw_buttons = node_composit_buts_viewer;
- ntype->draw_buttons_ex = node_composit_buts_viewer_ex;
- ntype->draw_backdrop = node_composit_backdrop_viewer;
- break;
- case CMP_NODE_COMPOSITE:
- ntype->draw_buttons = node_composit_buts_composite;
- break;
- case CMP_NODE_MASK:
- ntype->draw_buttons = node_composit_buts_mask;
- break;
- case CMP_NODE_KEYINGSCREEN:
- ntype->draw_buttons = node_composit_buts_keyingscreen;
- break;
- case CMP_NODE_KEYING:
- ntype->draw_buttons = node_composit_buts_keying;
- break;
- case CMP_NODE_TRACKPOS:
- ntype->draw_buttons = node_composit_buts_trackpos;
- break;
- case CMP_NODE_PLANETRACKDEFORM:
- ntype->draw_buttons = node_composit_buts_planetrackdeform;
- break;
- case CMP_NODE_CORNERPIN:
- ntype->draw_buttons = node_composit_buts_cornerpin;
- break;
- case CMP_NODE_SUNBEAMS:
- ntype->draw_buttons = node_composit_buts_sunbeams;
- break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
break;
@@ -3124,11 +1362,8 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_composit_buts_cryptomatte_legacy;
ntype->draw_buttons_ex = node_composit_buts_cryptomatte_legacy_ex;
break;
- case CMP_NODE_BRIGHTCONTRAST:
- ntype->draw_buttons = node_composit_buts_brightcontrast;
- break;
- case CMP_NODE_DENOISE:
- ntype->draw_buttons = node_composit_buts_denoise;
+ case CMP_NODE_VIEWER:
+ ntype->draw_backdrop = node_composit_backdrop_viewer;
break;
}
}
@@ -3391,20 +1626,14 @@ static void node_socket_undefined_interface_draw_color(bContext *UNUSED(C),
/** \} */
-void ED_node_init_butfuncs(void)
+void ED_node_init_butfuncs()
{
/* Fallback types for undefined tree, nodes, sockets
* Defined in blenkernel, but not registered in type hashes.
*/
- /* default ui functions */
- NodeTypeUndefined.draw_nodetype = node_draw_default;
- NodeTypeUndefined.draw_nodetype_prepare = node_update_default;
- NodeTypeUndefined.select_area_func = node_select_area_default;
- NodeTypeUndefined.tweak_area_func = node_tweak_area_default;
NodeTypeUndefined.draw_buttons = nullptr;
NodeTypeUndefined.draw_buttons_ex = nullptr;
- NodeTypeUndefined.resize_area_func = node_resize_area_default;
NodeSocketTypeUndefined.draw = node_socket_undefined_draw;
NodeSocketTypeUndefined.draw_color = node_socket_undefined_draw_color;
@@ -3413,13 +1642,6 @@ void ED_node_init_butfuncs(void)
/* node type ui functions */
NODE_TYPES_BEGIN (ntype) {
- /* default ui functions */
- ntype->draw_nodetype = node_draw_default;
- ntype->draw_nodetype_prepare = node_update_default;
- ntype->select_area_func = node_select_area_default;
- ntype->tweak_area_func = node_tweak_area_default;
- ntype->resize_area_func = node_resize_area_default;
-
node_common_set_butfunc(ntype);
node_composit_set_butfunc(ntype);
@@ -3438,19 +1660,12 @@ void ED_node_init_butfuncs(void)
ntreeType_Geometry->ui_icon = ICON_NODETREE;
}
-void ED_init_custom_node_type(bNodeType *ntype)
+void ED_init_custom_node_type(bNodeType *UNUSED(ntype))
{
- /* default ui functions */
- ntype->draw_nodetype = node_draw_default;
- ntype->draw_nodetype_prepare = node_update_default;
- ntype->resize_area_func = node_resize_area_default;
- ntype->select_area_func = node_select_area_default;
- ntype->tweak_area_func = node_tweak_area_default;
}
void ED_init_custom_node_socket_type(bNodeSocketType *stype)
{
- /* default ui functions */
stype->draw = node_socket_button_label;
}
@@ -3611,7 +1826,7 @@ static void std_node_socket_draw(
if (socket_needs_attribute_search(*node, *sock)) {
const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id;
- node_geometry_add_attribute_search_button(C, node_tree, node, ptr, row);
+ node_geometry_add_attribute_search_button(*C, *node_tree, *node, *ptr, *row);
}
else {
uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
@@ -3760,23 +1975,23 @@ void ED_init_node_socket_type_virtual(bNodeSocketType *stype)
/* ************** Generic drawing ************** */
-void draw_nodespace_back_pix(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
+void draw_nodespace_back_pix(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
bNodeInstanceKey parent_key)
{
- Main *bmain = CTX_data_main(C);
- bNodeInstanceKey active_viewer_key = (snode->nodetree ? snode->nodetree->active_viewer_key :
- NODE_INSTANCE_KEY_NONE);
+ Main *bmain = CTX_data_main(&C);
+ bNodeInstanceKey active_viewer_key = (snode.nodetree ? snode.nodetree->active_viewer_key :
+ NODE_INSTANCE_KEY_NONE);
GPU_matrix_push_projection();
GPU_matrix_push();
- wmOrtho2_region_pixelspace(region);
+ wmOrtho2_region_pixelspace(&region);
GPU_matrix_identity_set();
- ED_region_draw_cb_draw(C, region, REGION_DRAW_BACKDROP);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_BACKDROP);
GPU_matrix_pop_projection();
GPU_matrix_pop();
- if (!(snode->flag & SNODE_BACKDRAW) || !ED_node_is_compositor(snode)) {
+ if (!(snode.flag & SNODE_BACKDRAW) || !ED_node_is_compositor(&snode)) {
return;
}
@@ -3791,7 +2006,7 @@ void draw_nodespace_back_pix(const bContext *C,
GPUFrameBuffer *old_fb = GPU_framebuffer_active_get();
GPU_framebuffer_restore();
BLI_thread_lock(LOCK_DRAW_IMAGE);
- DRW_draw_view(C);
+ DRW_draw_view(&C);
BLI_thread_unlock(LOCK_DRAW_IMAGE);
GPU_framebuffer_bind_no_srgb(old_fb);
/* Draw manager changes the depth state. Set it back to NONE. Without this the node preview
@@ -3803,31 +2018,31 @@ void draw_nodespace_back_pix(const bContext *C,
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf) {
/* somehow the offset has to be calculated inverse */
- wmOrtho2_region_pixelspace(region);
- const float x = (region->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
- const float y = (region->winy - snode->zoom * ibuf->y) / 2 + snode->yof;
+ wmOrtho2_region_pixelspace(&region);
+ const float x = (region.winx - snode.zoom * ibuf->x) / 2 + snode.xof;
+ const float y = (region.winy - snode.zoom * ibuf->y) / 2 + snode.yof;
/** \note draw selected info on backdrop */
- if (snode->edittree) {
- bNode *node = (bNode *)snode->edittree->nodes.first;
- rctf *viewer_border = &snode->nodetree->viewer_border;
+ if (snode.edittree) {
+ bNode *node = (bNode *)snode.edittree->nodes.first;
+ rctf *viewer_border = &snode.nodetree->viewer_border;
while (node) {
if (node->flag & NODE_SELECT) {
if (node->typeinfo->draw_backdrop) {
- node->typeinfo->draw_backdrop(snode, ibuf, node, x, y);
+ node->typeinfo->draw_backdrop(&snode, ibuf, node, x, y);
}
}
node = node->next;
}
- if ((snode->nodetree->flag & NTREE_VIEWER_BORDER) &&
+ if ((snode.nodetree->flag & NTREE_VIEWER_BORDER) &&
viewer_border->xmin < viewer_border->xmax && viewer_border->ymin < viewer_border->ymax) {
rcti pixel_border;
BLI_rcti_init(&pixel_border,
- x + snode->zoom * viewer_border->xmin * ibuf->x,
- x + snode->zoom * viewer_border->xmax * ibuf->x,
- y + snode->zoom * viewer_border->ymin * ibuf->y,
- y + snode->zoom * viewer_border->ymax * ibuf->y);
+ x + snode.zoom * viewer_border->xmin * ibuf->x,
+ x + snode.zoom * viewer_border->xmax * ibuf->x,
+ y + snode.zoom * viewer_border->ymin * ibuf->y,
+ y + snode.zoom * viewer_border->ymax * ibuf->y);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -3846,10 +2061,9 @@ void draw_nodespace_back_pix(const bContext *C,
GPU_matrix_pop();
}
-/* return quadratic beziers points for a given nodelink and clip if v2d is not nullptr. */
bool node_link_bezier_handles(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &link,
float vec[4][2])
{
float cursor[2] = {0.0f, 0.0f};
@@ -3863,17 +2077,17 @@ bool node_link_bezier_handles(const View2D *v2d,
/* in v0 and v3 we put begin/end points */
int toreroute, fromreroute;
- if (link->fromsock) {
- vec[0][0] = link->fromsock->locx;
- vec[0][1] = link->fromsock->locy;
- if (link->fromsock->flag & SOCK_MULTI_INPUT) {
- node_link_calculate_multi_input_position(link->fromsock->locx,
- link->fromsock->locy,
- link->fromsock->total_inputs - 1,
- link->fromsock->total_inputs,
- vec[0]);
- }
- fromreroute = (link->fromnode && link->fromnode->type == NODE_REROUTE);
+ if (link.fromsock) {
+ vec[0][0] = link.fromsock->locx;
+ vec[0][1] = link.fromsock->locy;
+ if (link.fromsock->flag & SOCK_MULTI_INPUT) {
+ const float2 position = node_link_calculate_multi_input_position(
+ {link.fromsock->locx, link.fromsock->locy},
+ link.fromsock->total_inputs - 1,
+ link.fromsock->total_inputs);
+ copy_v2_v2(vec[0], position);
+ }
+ fromreroute = (link.fromnode && link.fromnode->type == NODE_REROUTE);
}
else {
if (snode == nullptr) {
@@ -3882,17 +2096,17 @@ bool node_link_bezier_handles(const View2D *v2d,
copy_v2_v2(vec[0], cursor);
fromreroute = 0;
}
- if (link->tosock) {
- vec[3][0] = link->tosock->locx;
- vec[3][1] = link->tosock->locy;
- if (!(link->tonode->flag & NODE_HIDDEN) && link->tosock->flag & SOCK_MULTI_INPUT) {
- node_link_calculate_multi_input_position(link->tosock->locx,
- link->tosock->locy,
- link->multi_input_socket_index,
- link->tosock->total_inputs,
- vec[3]);
+ if (link.tosock) {
+ vec[3][0] = link.tosock->locx;
+ vec[3][1] = link.tosock->locy;
+ if (!(link.tonode->flag & NODE_HIDDEN) && link.tosock->flag & SOCK_MULTI_INPUT) {
+ const float2 position = node_link_calculate_multi_input_position(
+ {link.tosock->locx, link.tosock->locy},
+ link.multi_input_socket_index,
+ link.tosock->total_inputs);
+ copy_v2_v2(vec[3], position);
}
- toreroute = (link->tonode && link->tonode->type == NODE_REROUTE);
+ toreroute = (link.tonode && link.tonode->type == NODE_REROUTE);
}
else {
if (snode == nullptr) {
@@ -3955,10 +2169,9 @@ bool node_link_bezier_handles(const View2D *v2d,
return true;
}
-/* if v2d not nullptr, it clips and returns 0 if not visible */
bool node_link_bezier_points(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &link,
float coord_array[][2],
const int resol)
{
@@ -4186,7 +2399,7 @@ static char nodelink_get_color_id(int th_col)
return 0;
}
-static void nodelink_batch_draw(const SpaceNode *snode)
+static void nodelink_batch_draw(const SpaceNode &snode)
{
if (g_batch_link.count == 0) {
return;
@@ -4206,7 +2419,7 @@ static void nodelink_batch_draw(const SpaceNode *snode)
GPU_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST);
GPU_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, colors);
- GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
+ GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode.runtime->aspect * LINK_WIDTH);
GPU_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE);
GPU_batch_draw(g_batch_link.batch);
@@ -4215,22 +2428,22 @@ static void nodelink_batch_draw(const SpaceNode *snode)
GPU_blend(GPU_BLEND_NONE);
}
-void nodelink_batch_start(SpaceNode *UNUSED(snode))
+void nodelink_batch_start(SpaceNode &UNUSED(snode))
{
g_batch_link.enabled = true;
}
-void nodelink_batch_end(SpaceNode *snode)
+void nodelink_batch_end(SpaceNode &snode)
{
nodelink_batch_draw(snode);
g_batch_link.enabled = false;
}
-static void nodelink_batch_add_link(const SpaceNode *snode,
- const float p0[2],
- const float p1[2],
- const float p2[2],
- const float p3[2],
+static void nodelink_batch_add_link(const SpaceNode &snode,
+ const float2 &p0,
+ const float2 &p1,
+ const float2 &p2,
+ const float2 &p3,
int th_col1,
int th_col2,
int th_col3,
@@ -4272,14 +2485,13 @@ static void nodelink_batch_add_link(const SpaceNode *snode,
}
}
-/* don't do shadows if th_col3 is -1. */
-void node_draw_link_bezier(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link,
- int th_col1,
- int th_col2,
- int th_col3)
+void node_draw_link_bezier(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link,
+ const int th_col1,
+ const int th_col2,
+ const int th_col3)
{
const float dim_factor = node_link_dim_factor(v2d, link);
float thickness = 1.5f;
@@ -4288,8 +2500,8 @@ void node_draw_link_bezier(const bContext *C,
bTheme *btheme = UI_GetTheme();
const float dash_alpha = btheme->space_node.dash_alpha;
- if (snode->edittree->type == NTREE_GEOMETRY) {
- if (link->fromsock && link->fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) {
+ if (snode.edittree->type == NTREE_GEOMETRY) {
+ if (link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) {
/* Make field links a bit thinner. */
thickness = 1.0f;
/* Draw field as dashes. */
@@ -4298,11 +2510,11 @@ void node_draw_link_bezier(const bContext *C,
}
float vec[4][2];
- const bool highlighted = link->flag & NODE_LINK_TEMP_HIGHLIGHT;
- if (node_link_bezier_handles(v2d, snode, link, vec)) {
- int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
- (link->fromnode && (link->fromnode->type == NODE_REROUTE)));
- int drawmuted = (link->flag & NODE_LINK_MUTED);
+ const bool highlighted = link.flag & NODE_LINK_TEMP_HIGHLIGHT;
+ if (node_link_bezier_handles(&v2d, &snode, link, vec)) {
+ int drawarrow = ((link.tonode && (link.tonode->type == NODE_REROUTE)) &&
+ (link.fromnode && (link.fromnode->type == NODE_REROUTE)));
+ int drawmuted = (link.flag & NODE_LINK_MUTED);
if (g_batch_link.batch == nullptr) {
nodelink_batch_init();
}
@@ -4312,23 +2524,23 @@ void node_draw_link_bezier(const bContext *C,
UI_GetThemeColor4fv(th_col3, colors[0]);
}
- if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
- snode->overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS &&
+ snode.overlay.flag & SN_OVERLAY_SHOW_WIRE_COLORS) {
PointerRNA from_node_ptr, to_node_ptr;
- RNA_pointer_create((ID *)snode->edittree, &RNA_Node, link->fromnode, &from_node_ptr);
- RNA_pointer_create((ID *)snode->edittree, &RNA_Node, link->tonode, &to_node_ptr);
- if (link->fromsock) {
- node_socket_color_get(C, snode->edittree, &from_node_ptr, link->fromsock, colors[1]);
+ RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.fromnode, &from_node_ptr);
+ RNA_pointer_create((ID *)snode.edittree, &RNA_Node, link.tonode, &to_node_ptr);
+ if (link.fromsock) {
+ node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[1]);
}
else {
- node_socket_color_get(C, snode->edittree, &to_node_ptr, link->tosock, colors[1]);
+ node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[1]);
}
- if (link->tosock) {
- node_socket_color_get(C, snode->edittree, &to_node_ptr, link->tosock, colors[2]);
+ if (link.tosock) {
+ node_socket_color_get(C, *snode.edittree, to_node_ptr, *link.tosock, colors[2]);
}
else {
- node_socket_color_get(C, snode->edittree, &from_node_ptr, link->fromsock, colors[2]);
+ node_socket_color_get(C, *snode.edittree, from_node_ptr, *link.fromsock, colors[2]);
}
}
else {
@@ -4337,8 +2549,8 @@ void node_draw_link_bezier(const bContext *C,
}
/* Highlight links connected to selected nodes. */
- const bool is_fromnode_selected = link->fromnode && link->fromnode->flag & SELECT;
- const bool is_tonode_selected = link->tonode && link->tonode->flag & SELECT;
+ const bool is_fromnode_selected = link.fromnode && link.fromnode->flag & SELECT;
+ const bool is_tonode_selected = link.tonode && link.tonode->flag & SELECT;
if (is_fromnode_selected || is_tonode_selected) {
float color_selected[4];
UI_GetThemeColor4fv(TH_EDGE_SELECT, color_selected);
@@ -4385,7 +2597,7 @@ void node_draw_link_bezier(const bContext *C,
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec);
GPU_batch_uniform_4fv_array(batch, "colors", 3, colors);
- GPU_batch_uniform_1f(batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
+ GPU_batch_uniform_1f(batch, "expandSize", snode.runtime->aspect * LINK_WIDTH);
GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
GPU_batch_uniform_1i(batch, "doMuted", drawmuted);
@@ -4398,37 +2610,36 @@ void node_draw_link_bezier(const bContext *C,
}
}
-/* NOTE: this is used for fake links in groups too. */
-void node_draw_link(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link)
+void node_draw_link(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link)
{
int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE;
- if (link->fromsock == nullptr && link->tosock == nullptr) {
+ if (link.fromsock == nullptr && link.tosock == nullptr) {
return;
}
/* new connection */
- if (!link->fromsock || !link->tosock) {
+ if (!link.fromsock || !link.tosock) {
th_col1 = th_col2 = TH_ACTIVE;
}
else {
/* going to give issues once... */
- if (link->tosock->flag & SOCK_UNAVAIL) {
+ if (link.tosock->flag & SOCK_UNAVAIL) {
return;
}
- if (link->fromsock->flag & SOCK_UNAVAIL) {
+ if (link.fromsock->flag & SOCK_UNAVAIL) {
return;
}
- if (link->flag & NODE_LINK_VALID) {
+ if (link.flag & NODE_LINK_VALID) {
/* special indicated link, on drop-node */
- if (link->flag & NODE_LINKFLAG_HILITE) {
+ if (link.flag & NODE_LINKFLAG_HILITE) {
th_col1 = th_col2 = TH_ACTIVE;
}
- else if (link->flag & NODE_LINK_MUTED) {
+ else if (link.flag & NODE_LINK_MUTED) {
th_col1 = th_col2 = TH_REDALERT;
}
}
@@ -4439,9 +2650,9 @@ void node_draw_link(const bContext *C,
}
}
/* Links from field to non-field sockets are not allowed. */
- if (snode->edittree->type == NTREE_GEOMETRY && !(link->flag & NODE_LINK_DRAGGED)) {
- if ((link->fromsock && link->fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) &&
- (link->tosock && link->tosock->display_shape == SOCK_DISPLAY_SHAPE_CIRCLE)) {
+ if (snode.edittree->type == NTREE_GEOMETRY && !(link.flag & NODE_LINK_DRAGGED)) {
+ if ((link.fromsock && link.fromsock->display_shape == SOCK_DISPLAY_SHAPE_DIAMOND) &&
+ (link.tosock && link.tosock->display_shape == SOCK_DISPLAY_SHAPE_CIRCLE)) {
th_col1 = th_col2 = th_col3 = TH_REDALERT;
}
}
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
new file mode 100644
index 00000000000..e1ba36e81c0
--- /dev/null
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -0,0 +1,291 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string_search.h"
+
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+
+#include "node_intern.hh"
+
+using blender::nodes::SocketLinkOperation;
+
+namespace blender::ed::space_node {
+
+struct LinkDragSearchStorage {
+ bNode &from_node;
+ bNodeSocket &from_socket;
+ float2 cursor;
+ Vector<SocketLinkOperation> search_link_ops;
+ char search[256];
+
+ eNodeSocketInOut in_out() const
+ {
+ return static_cast<eNodeSocketInOut>(from_socket.in_out);
+ }
+};
+
+static void add_reroute_node_fn(nodes::LinkSearchOpParams &params)
+{
+ bNode &reroute = params.add_node("NodeReroute");
+ if (params.socket.in_out == SOCK_IN) {
+ nodeAddLink(&params.node_tree,
+ &reroute,
+ static_cast<bNodeSocket *>(reroute.outputs.first),
+ &params.node,
+ &params.socket);
+ }
+ else {
+ nodeAddLink(&params.node_tree,
+ &params.node,
+ &params.socket,
+ &reroute,
+ static_cast<bNodeSocket *>(reroute.inputs.first));
+ }
+}
+
+static void add_group_input_node_fn(nodes::LinkSearchOpParams &params)
+{
+ /* Add a group input based on the connected socket, and add a new group input node. */
+ bNodeSocket *interface_socket = ntreeAddSocketInterfaceFromSocket(
+ &params.node_tree, &params.node, &params.socket);
+ const int group_input_index = BLI_findindex(&params.node_tree.inputs, interface_socket);
+
+ bNode &group_input = params.add_node("NodeGroupInput");
+
+ /* This is necessary to create the new sockets in the other input nodes. */
+ ntreeUpdateTree(CTX_data_main(&params.C), &params.node_tree);
+
+ /* Hide the new input in all other group input nodes, to avoid making them taller. */
+ LISTBASE_FOREACH (bNode *, node, &params.node_tree.nodes) {
+ if (node->type == NODE_GROUP_INPUT) {
+ bNodeSocket *new_group_input_socket = (bNodeSocket *)BLI_findlink(&node->outputs,
+ group_input_index);
+ new_group_input_socket->flag |= SOCK_HIDDEN;
+ }
+ }
+
+ /* Hide all existing inputs in the new group input node, to only display the new one. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) {
+ socket->flag |= SOCK_HIDDEN;
+ }
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index);
+ if (socket == nullptr) {
+ /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */
+ return;
+ }
+ /* Unhide the socket for the new input in the new node and make a connection to it. */
+ socket->flag &= ~SOCK_HIDDEN;
+ nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
+}
+
+/**
+ * Call the callback to gather compatible socket connections for all node types, and the operations
+ * that will actually make the connections. Also add some custom operations like connecting a group
+ * output node.
+ */
+static void gather_socket_link_operations(bNodeTree &node_tree,
+ const bNodeSocket &socket,
+ Vector<SocketLinkOperation> &search_link_ops)
+{
+ NODE_TYPES_BEGIN (node_type) {
+ if (StringRef(node_type->idname).find("Legacy") != StringRef::not_found) {
+ continue;
+ }
+ const char *disabled_hint;
+ if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) {
+ continue;
+ }
+
+ if (node_type->gather_link_search_ops) {
+ nodes::GatherLinkSearchOpParams params{*node_type, node_tree, socket, search_link_ops};
+ node_type->gather_link_search_ops(params);
+ }
+ }
+ NODE_TYPES_END;
+
+ search_link_ops.append({IFACE_("Reroute"), add_reroute_node_fn});
+
+ const bool is_node_group = !(node_tree.id.flag & LIB_EMBEDDED_DATA);
+
+ if (is_node_group && socket.in_out == SOCK_IN) {
+ search_link_ops.append({IFACE_("Group Input"), add_group_input_node_fn});
+ }
+}
+
+static void link_drag_search_update_fn(const bContext *UNUSED(C),
+ void *arg,
+ const char *str,
+ uiSearchItems *items,
+ const bool is_first)
+{
+ LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg);
+
+ StringSearch *search = BLI_string_search_new();
+
+ for (SocketLinkOperation &op : storage.search_link_ops) {
+ BLI_string_search_add(search, op.name.c_str(), &op, op.weight);
+ }
+
+ /* Don't filter when the menu is first opened, but still run the search
+ * so the items are in the same order they will appear in while searching. */
+ const char *string = is_first ? "" : str;
+ SocketLinkOperation **filtered_items;
+ const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items);
+
+ for (const int i : IndexRange(filtered_amount)) {
+ SocketLinkOperation &item = *filtered_items[i];
+ if (!UI_search_item_add(items, item.name.c_str(), &item, ICON_NONE, 0, 0)) {
+ break;
+ }
+ }
+
+ MEM_freeN(filtered_items);
+ BLI_string_search_free(search);
+}
+
+static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2)
+{
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg1);
+ SocketLinkOperation *item = static_cast<SocketLinkOperation *>(arg2);
+ if (item == nullptr) {
+ return;
+ }
+
+ node_deselect_all(snode);
+
+ Vector<bNode *> new_nodes;
+ nodes::LinkSearchOpParams params{
+ *C, *snode.edittree, storage.from_node, storage.from_socket, new_nodes};
+ item->fn(params);
+ if (new_nodes.is_empty()) {
+ return;
+ }
+
+ /* For now, assume that only one node is created by the callback. */
+ BLI_assert(new_nodes.size() == 1);
+ bNode *new_node = new_nodes.first();
+
+ new_node->locx = storage.cursor.x / UI_DPI_FAC;
+ new_node->locy = storage.cursor.y / UI_DPI_FAC + 20 * UI_DPI_FAC;
+ if (storage.in_out() == SOCK_IN) {
+ new_node->locx -= new_node->width;
+ }
+
+ nodeSetSelected(new_node, true);
+ nodeSetActive(snode.edittree, new_node);
+
+ /* Ideally it would be possible to tag the node tree in some way so it updates only after the
+ * translate operation is finished, but normally moving nodes around doesn't cause updates. */
+ ntreeUpdateTree(&bmain, snode.edittree);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
+
+ /* Start translation operator with the new node. */
+ wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_translate", true);
+ BLI_assert(ot);
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_boolean_set(&ptr, "view2d_edge_pan", true);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_properties_free(&ptr);
+}
+
+static void link_drag_search_free_fn(void *arg)
+{
+ LinkDragSearchStorage *storage = static_cast<LinkDragSearchStorage *>(arg);
+ delete storage;
+}
+
+static uiBlock *create_search_popup_block(bContext *C, ARegion *region, void *arg_op)
+{
+ LinkDragSearchStorage &storage = *(LinkDragSearchStorage *)arg_op;
+
+ bNodeTree *node_tree = CTX_wm_space_node(C)->nodetree;
+ gather_socket_link_operations(*node_tree, storage.from_socket, storage.search_link_ops);
+
+ uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+
+ uiBut *but = uiDefSearchBut(block,
+ storage.search,
+ 0,
+ ICON_VIEWZOOM,
+ sizeof(storage.search),
+ storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(),
+ 10,
+ UI_searchbox_size_x(),
+ UI_UNIT_Y,
+ 0,
+ 0,
+ "");
+ UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
+ UI_but_func_search_set(but,
+ nullptr,
+ link_drag_search_update_fn,
+ &storage,
+ false,
+ link_drag_search_free_fn,
+ link_drag_search_exec_fn,
+ nullptr);
+ UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
+
+ /* Fake button to hold space for the search items. */
+ uiDefBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ "",
+ storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(),
+ 10 - UI_searchbox_size_y(),
+ UI_searchbox_size_x(),
+ UI_searchbox_size_y(),
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+
+ const int offset[2] = {0, -UI_UNIT_Y};
+ UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, offset);
+ return block;
+}
+
+void invoke_node_link_drag_add_menu(bContext &C,
+ bNode &node,
+ bNodeSocket &socket,
+ const float2 &cursor)
+{
+ LinkDragSearchStorage *storage = new LinkDragSearchStorage{node, socket, cursor};
+ /* Use the "_ex" variant with `can_refresh` false to avoid a double free when closing Blender. */
+ UI_popup_block_invoke_ex(&C, create_search_popup_block, storage, nullptr, false);
+}
+
+} // namespace blender::ed::space_node \ No newline at end of file
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 2e3579caaa1..c6a5e8e68c0 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -28,7 +28,6 @@
#include "DNA_texture_types.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLT_translation.h"
@@ -62,24 +61,19 @@
/** \name Utilities
* \{ */
-/**
- * XXX Does some additional initialization on top of #nodeAddNode
- * Can be used with both custom and static nodes,
- * if `idname == nullptr` the static int type will be used instead.
- */
-bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy)
+bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- Main *bmain = CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ Main &bmain = *CTX_data_main(&C);
bNode *node = nullptr;
node_deselect_all(snode);
if (idname) {
- node = nodeAddNode(C, snode->edittree, idname);
+ node = nodeAddNode(&C, snode.edittree, idname);
}
else {
- node = nodeAddStaticNode(C, snode->edittree, type);
+ node = nodeAddStaticNode(&C, snode.edittree, type);
}
BLI_assert(node && node->typeinfo);
@@ -89,13 +83,13 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
nodeSetSelected(node, true);
- ntreeUpdateTree(bmain, snode->edittree);
- ED_node_set_active(bmain, snode, snode->edittree, node, nullptr);
+ ntreeUpdateTree(&bmain, snode.edittree);
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
snode_update(snode, node);
- if (snode->nodetree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(snode->edittree);
+ if (snode.nodetree->type == NTREE_TEXTURE) {
+ ntreeTexCheckCyclics(snode.edittree);
}
return node;
@@ -107,7 +101,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
/** \name Add Reroute Operator
* \{ */
-static bool add_reroute_intersect_check(bNodeLink *link,
+static bool add_reroute_intersect_check(const bNodeLink &link,
float mcoords[][2],
int tot,
float result[2])
@@ -224,9 +218,9 @@ static bNodeSocketLink *add_reroute_do_socket_section(bContext *C,
static int add_reroute_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
+ bNodeTree &ntree = *snode.edittree;
float mcoords[256][2];
int i = 0;
@@ -236,7 +230,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -246,7 +240,6 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
if (i > 1) {
ListBase output_links, input_links;
- bNodeLink *link;
bNodeSocketLink *socklink;
float insert_point[2];
@@ -259,11 +252,11 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_listbase_clear(&output_links);
BLI_listbase_clear(&input_links);
- for (link = (bNodeLink *)ntree->links.first; link; link = link->next) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
- if (add_reroute_intersect_check(link, mcoords, i, insert_point)) {
+ if (add_reroute_intersect_check(*link, mcoords, i, insert_point)) {
add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point);
add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point);
@@ -288,9 +281,9 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_freelistN(&input_links);
/* always last */
- ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ntreeUpdateTree(CTX_data_main(C), &ntree);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
return OPERATOR_FINISHED;
}
@@ -377,7 +370,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *group_node = node_add_node(C,
+ bNode *group_node = node_add_node(*C,
node_group_idname(C),
(node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP :
NODE_GROUP,
@@ -395,8 +388,8 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(bmain, node_group);
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -469,7 +462,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *object_node = node_add_node(
- C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
if (!object_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node object");
return OPERATOR_CANCELLED;
@@ -488,8 +481,8 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, object_node);
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
ED_node_tag_update_nodetree(bmain, ntree, object_node);
DEG_relations_tag_update(bmain);
@@ -580,7 +573,7 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *texture_node = node_add_node(C,
+ bNode *texture_node = node_add_node(*C,
nullptr,
GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
snode->runtime->cursor[0],
@@ -596,8 +589,8 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, texture_node);
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
DEG_relations_tag_update(bmain);
ED_node_tag_update_nodetree(bmain, ntree, texture_node);
@@ -680,8 +673,8 @@ static Collection *node_add_collection_get_and_poll_collection_node_tree(Main *b
static int node_add_collection_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree *ntree = snode.edittree;
Collection *collection;
if (!(collection = node_add_collection_get_and_poll_collection_node_tree(bmain, op))) {
@@ -691,7 +684,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *collection_node = node_add_node(
- C, nullptr, GEO_NODE_COLLECTION_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!collection_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node collection");
return OPERATOR_CANCELLED;
@@ -710,8 +703,8 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, collection_node);
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
DEG_relations_tag_update(bmain);
ED_node_tag_update_nodetree(bmain, ntree, collection_node);
@@ -788,7 +781,7 @@ static bool node_add_file_poll(bContext *C)
static int node_add_file_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
bNode *node;
Image *ima;
int type = 0;
@@ -798,7 +791,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- switch (snode->nodetree->type) {
+ switch (snode.nodetree->type) {
case NTREE_SHADER:
type = SH_NODE_TEX_IMAGE;
break;
@@ -817,7 +810,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(C, nullptr, type, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ node = node_add_node(*C, nullptr, type, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
@@ -841,8 +834,8 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -923,7 +916,7 @@ static bool node_add_mask_poll(bContext *C)
static int node_add_mask_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
bNode *node;
ID *mask = node_add_mask_get_and_poll_mask(bmain, op);
@@ -934,7 +927,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
node = node_add_node(
- C, nullptr, CMP_NODE_MASK, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ *C, nullptr, CMP_NODE_MASK, snode.runtime->cursor[0], snode.runtime->cursor[1]);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");
@@ -944,8 +937,8 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
node->id = mask;
id_us_plus(mask);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index bf3a9ba0c52..d68f16f6197 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -22,21 +22,22 @@
* \brief higher level node drawing for the node editor.
*/
+#include <iomanip>
+
#include "MEM_guardedalloc.h"
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
-#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_text_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
+#include "BLI_array.hh"
#include "BLI_map.hh"
-#include "BLI_math.h"
#include "BLI_set.hh"
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
@@ -87,10 +88,8 @@
#include "node_intern.hh" /* own include */
-#ifdef WITH_COMPOSITOR
-# include "COM_compositor.h"
-#endif
-
+using blender::Array;
+using blender::float2;
using blender::Map;
using blender::Set;
using blender::Span;
@@ -109,7 +108,7 @@ extern void ui_draw_dropshadow(
const rctf *rct, float radius, float aspect, float alpha, int select);
}
-float ED_node_grid_size(void)
+float ED_node_grid_size()
{
return U.widget_unit;
}
@@ -118,7 +117,7 @@ void ED_node_tree_update(const bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
if (snode) {
- snode_set_context(C);
+ snode_set_context(*C);
id_us_ensure_real(&snode->nodetree->id);
}
@@ -185,7 +184,7 @@ void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
bool do_tag_update = true;
if (node != nullptr) {
- if (!node_connected_to_output(bmain, ntree, node)) {
+ if (!node_connected_to_output(*bmain, *ntree, *node)) {
do_tag_update = false;
}
}
@@ -262,10 +261,6 @@ static bool compare_nodes(const bNode *a, const bNode *b)
return false;
}
-/**
- * Sort nodes by selection: unselected nodes first, then selected,
- * then the active node at the very end. Relative order is kept intact.
- */
void ED_node_sort(bNodeTree *ntree)
{
/* Merge sort is the algorithm of choice here. */
@@ -321,67 +316,68 @@ void ED_node_sort(bNodeTree *ntree)
}
}
-static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
+static Array<uiBlock *> node_uiblocks_init(const bContext &C, Span<bNode *> nodes)
{
+ Array<uiBlock *> blocks(nodes.size());
/* Add node uiBlocks in drawing order - prevents events going to overlapping nodes. */
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* ui block */
- char uiblockstr[32];
- BLI_snprintf(uiblockstr, sizeof(uiblockstr), "node buttons %p", (void *)node);
- node->block = UI_block_begin(C, CTX_wm_region(C), uiblockstr, UI_EMBOSS);
-
+ for (const int i : nodes.index_range()) {
+ const std::string block_name = "node_" + std::string(nodes[i]->name);
+ blocks[i] = UI_block_begin(&C, CTX_wm_region(&C), block_name.c_str(), UI_EMBOSS);
/* this cancels events for background nodes */
- UI_block_flag_enable(node->block, UI_BLOCK_CLIP_EVENTS);
+ UI_block_flag_enable(blocks[i], UI_BLOCK_CLIP_EVENTS);
}
+
+ return blocks;
}
-void node_to_view(const bNode *node, float x, float y, float *rx, float *ry)
+float2 node_to_view(const bNode &node, const float2 &co)
{
- nodeToView(node, x, y, rx, ry);
- *rx *= UI_DPI_FAC;
- *ry *= UI_DPI_FAC;
+ float2 result;
+ nodeToView(&node, co.x, co.y, &result.x, &result.y);
+ return result * UI_DPI_FAC;
}
-void node_to_updated_rect(const bNode *node, rctf *r_rect)
+void node_to_updated_rect(const bNode &node, rctf &r_rect)
{
- node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax);
- node_to_view(node,
- node->offsetx + node->width,
- node->offsety - node->height,
- &r_rect->xmax,
- &r_rect->ymin);
+ const float2 xmin_ymax = node_to_view(node, {node.offsetx, node.offsety});
+ r_rect.xmin = xmin_ymax.x;
+ r_rect.ymax = xmin_ymax.y;
+ const float2 xmax_ymin = node_to_view(node,
+ {node.offsetx + node.width, node.offsety - node.height});
+ r_rect.xmax = xmax_ymin.x;
+ r_rect.ymin = xmax_ymin.y;
}
-void node_from_view(const bNode *node, float x, float y, float *rx, float *ry)
+float2 node_from_view(const bNode &node, const float2 &co)
{
- x /= UI_DPI_FAC;
- y /= UI_DPI_FAC;
- nodeFromView(node, x, y, rx, ry);
+ const float x = co.x / UI_DPI_FAC;
+ const float y = co.y / UI_DPI_FAC;
+ float2 result;
+ nodeFromView(&node, x, y, &result.x, &result.y);
+ return result;
}
/**
* Based on settings and sockets in node, set drawing rect info.
*/
-static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
+static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, uiBlock &block)
{
PointerRNA nodeptr;
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
+ RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
/* Get "global" coordinates. */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
+ float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
- locx = round(locx);
- locy = round(locy);
+ loc.x = round(loc.x);
+ loc.y = round(loc.y);
- int dy = locy;
+ int dy = loc.y;
/* Header. */
dy -= NODE_DY;
- /* Little bit of space in top. */
- if (node->outputs.first) {
+ /* Add a little bit of padding above the top socket. */
+ if (node.outputs.first || node.inputs.first) {
dy -= NODE_DYS / 2;
}
@@ -389,25 +385,25 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
bool add_output_space = false;
int buty;
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (nodeSocketIsHidden(nsock)) {
continue;
}
PointerRNA sockptr;
- RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
NODE_WIDTH(node) - NODE_DY,
NODE_DY,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
@@ -419,16 +415,16 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
uiLayout *row = uiLayoutRow(layout, true);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
const char *socket_label = nodeSocketLabel(nsock);
- nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
/* Ensure minimum socket height in case layout is empty. */
buty = min_ii(buty, dy - NODE_DY);
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(locx + NODE_WIDTH(node));
+ nsock->locx = round(loc.x + NODE_WIDTH(node));
nsock->locy = round(0.5f * (dy + buty));
dy = buty;
@@ -443,86 +439,80 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
dy -= NODE_DY / 4;
}
- node->prvr.xmin = locx + NODE_DYS;
- node->prvr.xmax = locx + NODE_WIDTH(node) - NODE_DYS;
+ node.prvr.xmin = loc.x + NODE_DYS;
+ node.prvr.xmax = loc.x + NODE_WIDTH(node) - NODE_DYS;
/* preview rect? */
- if (node->flag & NODE_PREVIEW) {
+ if (node.flag & NODE_PREVIEW) {
float aspect = 1.0f;
- if (node->preview_xsize && node->preview_ysize) {
- aspect = (float)node->preview_ysize / (float)node->preview_xsize;
+ if (node.preview_xsize && node.preview_ysize) {
+ aspect = (float)node.preview_ysize / (float)node.preview_xsize;
}
dy -= NODE_DYS / 2;
- node->prvr.ymax = dy;
+ node.prvr.ymax = dy;
if (aspect <= 1.0f) {
- node->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
+ node.prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
}
else {
/* Width correction of image. XXX huh? (ton) */
float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect;
- node->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
+ node.prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
- node->prvr.xmin += 0.5f * dx;
- node->prvr.xmax -= 0.5f * dx;
+ node.prvr.xmin += 0.5f * dx;
+ node.prvr.xmax -= 0.5f * dx;
}
- dy = node->prvr.ymin - NODE_DYS / 2;
+ dy = node.prvr.ymin - NODE_DYS / 2;
/* Make sure that maximums are bigger or equal to minimums. */
- if (node->prvr.xmax < node->prvr.xmin) {
- SWAP(float, node->prvr.xmax, node->prvr.xmin);
+ if (node.prvr.xmax < node.prvr.xmin) {
+ SWAP(float, node.prvr.xmax, node.prvr.xmin);
}
- if (node->prvr.ymax < node->prvr.ymin) {
- SWAP(float, node->prvr.ymax, node->prvr.ymin);
+ if (node.prvr.ymax < node.prvr.ymin) {
+ SWAP(float, node.prvr.ymax, node.prvr.ymin);
}
}
/* Buttons rect? */
- if (node->typeinfo->draw_buttons && (node->flag & NODE_OPTIONS)) {
+ if (node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS)) {
dy -= NODE_DYS / 2;
- /* Set this for `uifunc()` that don't use layout engine yet. */
- node->butr.xmin = 0;
- node->butr.xmax = NODE_WIDTH(node) - 2 * NODE_DYS;
- node->butr.ymin = 0;
- node->butr.ymax = 0;
-
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
- node->butr.xmax,
+ NODE_WIDTH(node) - NODE_DY,
0,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
uiLayoutSetContextPointer(layout, "node", &nodeptr);
- node->typeinfo->draw_buttons(layout, (bContext *)C, &nodeptr);
+ node.typeinfo->draw_buttons(layout, (bContext *)&C, &nodeptr);
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
dy = buty - NODE_DYS / 2;
}
/* Input sockets. */
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (nodeSocketIsHidden(nsock)) {
continue;
}
PointerRNA sockptr;
- RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
+ RNA_pointer_create(&ntree.id, &RNA_NodeSocket, nsock, &sockptr);
/* Add the half the height of a multi-input socket to cursor Y
* to account for the increased height of the taller sockets. */
@@ -534,17 +524,17 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
}
dy -= multi_input_socket_offset * 0.5f;
- uiLayout *layout = UI_block_layout(node->block,
+ uiLayout *layout = UI_block_layout(&block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
- locx + NODE_DYS,
+ loc.x + NODE_DYS,
dy,
NODE_WIDTH(node) - NODE_DY,
NODE_DY,
0,
UI_style_get_dpi());
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
uiLayoutSetActive(layout, false);
}
@@ -555,15 +545,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
uiLayout *row = uiLayoutRow(layout, true);
const char *socket_label = nodeSocketLabel(nsock);
- nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label));
+ nsock->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
- UI_block_align_end(node->block);
- UI_block_layout_resolve(node->block, nullptr, &buty);
+ UI_block_align_end(&block);
+ UI_block_layout_resolve(&block, nullptr, &buty);
/* Ensure minimum socket height in case layout is empty. */
buty = min_ii(buty, dy - NODE_DY);
- nsock->locx = locx;
+ nsock->locx = loc.x;
/* Round the socket vertical position to stop it from jiggling. */
nsock->locy = round(0.5f * (dy + buty));
@@ -574,45 +564,44 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
}
/* Little bit of space in end. */
- if (node->inputs.first || (node->flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
+ if (node.inputs.first || (node.flag & (NODE_OPTIONS | NODE_PREVIEW)) == 0) {
dy -= NODE_DYS / 2;
}
- node->totr.xmin = locx;
- node->totr.xmax = locx + NODE_WIDTH(node);
- node->totr.ymax = locy;
- node->totr.ymin = min_ff(dy, locy - 2 * NODE_DY);
+ node.totr.xmin = loc.x;
+ node.totr.xmax = loc.x + NODE_WIDTH(node);
+ node.totr.ymax = loc.y;
+ node.totr.ymin = min_ff(dy, loc.y - 2 * NODE_DY);
/* Set the block bounds to clip mouse events from underlying nodes.
* Add a margin for sockets on each side. */
- UI_block_bounds_set_explicit(node->block,
- node->totr.xmin - NODE_SOCKSIZE,
- node->totr.ymin,
- node->totr.xmax + NODE_SOCKSIZE,
- node->totr.ymax);
+ UI_block_bounds_set_explicit(&block,
+ node.totr.xmin - NODE_SOCKSIZE,
+ node.totr.ymin,
+ node.totr.xmax + NODE_SOCKSIZE,
+ node.totr.ymax);
}
/**
* Based on settings in node, sets drawing rect info.
*/
-static void node_update_hidden(bNode *node)
+static void node_update_hidden(bNode &node, uiBlock &block)
{
int totin = 0, totout = 0;
- /* Get "global" coords. */
- float locx, locy;
- node_to_view(node, 0.0f, 0.0f, &locx, &locy);
+ /* Get "global" coordinates. */
+ float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
- locx = round(locx);
- locy = round(locy);
+ loc.x = round(loc.x);
+ loc.y = round(loc.y);
/* Calculate minimal radius. */
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (!nodeSocketIsHidden(nsock)) {
totin++;
}
}
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (!nodeSocketIsHidden(nsock)) {
totout++;
}
@@ -624,20 +613,20 @@ static void node_update_hidden(bNode *node)
hiddenrad += 5.0f * (float)(tot - 4);
}
- node->totr.xmin = locx;
- node->totr.xmax = locx + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
- node->totr.ymax = locy + (hiddenrad - 0.5f * NODE_DY);
- node->totr.ymin = node->totr.ymax - 2 * hiddenrad;
+ node.totr.xmin = loc.x;
+ node.totr.xmax = loc.x + max_ff(NODE_WIDTH(node), 2 * hiddenrad);
+ node.totr.ymax = loc.y + (hiddenrad - 0.5f * NODE_DY);
+ node.totr.ymin = node.totr.ymax - 2 * hiddenrad;
/* Output sockets. */
float rad = (float)M_PI / (1.0f + (float)totout);
float drad = rad;
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.outputs) {
if (!nodeSocketIsHidden(nsock)) {
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(node->totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
- nsock->locy = round(node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
+ nsock->locx = round(node.totr.xmax - hiddenrad + sinf(rad) * hiddenrad);
+ nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
rad += drad;
}
}
@@ -645,51 +634,31 @@ static void node_update_hidden(bNode *node)
/* Input sockets. */
rad = drad = -(float)M_PI / (1.0f + (float)totin);
- LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node.inputs) {
if (!nodeSocketIsHidden(nsock)) {
/* Round the socket location to stop it from jiggling. */
- nsock->locx = round(node->totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
- nsock->locy = round(node->totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
+ nsock->locx = round(node.totr.xmin + hiddenrad + sinf(rad) * hiddenrad);
+ nsock->locy = round(node.totr.ymin + hiddenrad + cosf(rad) * hiddenrad);
rad += drad;
}
}
/* Set the block bounds to clip mouse events from underlying nodes.
* Add a margin for sockets on each side. */
- UI_block_bounds_set_explicit(node->block,
- node->totr.xmin - NODE_SOCKSIZE,
- node->totr.ymin,
- node->totr.xmax + NODE_SOCKSIZE,
- node->totr.ymax);
+ UI_block_bounds_set_explicit(&block,
+ node.totr.xmin - NODE_SOCKSIZE,
+ node.totr.ymin,
+ node.totr.xmax + NODE_SOCKSIZE,
+ node.totr.ymax);
}
-void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node)
+static int node_get_colorid(const bNode &node)
{
- if (node->flag & NODE_HIDDEN) {
- node_update_hidden(node);
- }
- else {
- node_update_basis(C, ntree, node);
- }
-}
-
-int node_select_area_default(bNode *node, int x, int y)
-{
- return BLI_rctf_isect_pt(&node->totr, x, y);
-}
-
-int node_tweak_area_default(bNode *node, int x, int y)
-{
- return BLI_rctf_isect_pt(&node->totr, x, y);
-}
-
-int node_get_colorid(bNode *node)
-{
- switch (node->typeinfo->nclass) {
+ switch (node.typeinfo->nclass) {
case NODE_CLASS_INPUT:
return TH_NODE_INPUT;
case NODE_CLASS_OUTPUT:
- return (node->flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
+ return (node.flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
case NODE_CLASS_CONVERTER:
return TH_NODE_CONVERTER;
case NODE_CLASS_OP_COLOR:
@@ -725,21 +694,21 @@ int node_get_colorid(bNode *node)
}
}
-static void node_draw_mute_line(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNode *node)
+static void node_draw_mute_line(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNode &node)
{
GPU_blend(GPU_BLEND_ALPHA);
- LISTBASE_FOREACH (const bNodeLink *, link, &node->internal_links) {
- node_draw_link_bezier(C, v2d, snode, link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE);
+ LISTBASE_FOREACH (const bNodeLink *, link, &node.internal_links) {
+ node_draw_link_bezier(C, v2d, snode, *link, TH_WIRE_INNER, TH_WIRE_INNER, TH_WIRE);
}
GPU_blend(GPU_BLEND_NONE);
}
-static void node_socket_draw(const bNodeSocket *sock,
+static void node_socket_draw(const bNodeSocket &sock,
const float color[4],
const float color_outline[4],
float size,
@@ -754,7 +723,7 @@ static void node_socket_draw(const bNodeSocket *sock,
int flags;
/* Set shape flags. */
- switch (sock->display_shape) {
+ switch (sock.display_shape) {
case SOCK_DISPLAY_SHAPE_DIAMOND:
case SOCK_DISPLAY_SHAPE_DIAMOND_DOT:
flags = GPU_KEYFRAME_SHAPE_DIAMOND;
@@ -770,7 +739,7 @@ static void node_socket_draw(const bNodeSocket *sock,
break;
}
- if (ELEM(sock->display_shape,
+ if (ELEM(sock.display_shape,
SOCK_DISPLAY_SHAPE_DIAMOND_DOT,
SOCK_DISPLAY_SHAPE_SQUARE_DOT,
SOCK_DISPLAY_SHAPE_CIRCLE_DOT)) {
@@ -825,16 +794,17 @@ static void node_socket_outline_color_get(const bool selected,
}
}
-/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a
- * color property socket). */
-void node_socket_color_get(
- const bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
+void node_socket_color_get(const bContext &C,
+ const bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ const bNodeSocket &sock,
+ float r_color[4])
{
PointerRNA ptr;
- BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node));
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ BLI_assert(RNA_struct_is_a(node_ptr.type, &RNA_Node));
+ RNA_pointer_create((ID *)&ntree, &RNA_NodeSocket, &const_cast<bNodeSocket &>(sock), &ptr);
- sock->typeinfo->draw_color((bContext *)C, &ptr, node_ptr, r_color);
+ sock.typeinfo->draw_color((bContext *)&C, &ptr, &node_ptr, r_color);
}
struct SocketTooltipData {
@@ -843,29 +813,43 @@ struct SocketTooltipData {
bNodeSocket *socket;
};
-static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log,
- std::stringstream &ss)
+static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss)
{
auto id_to_inspection_string = [&](ID *id, short idcode) {
ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(idcode) << ")";
};
- const GPointer value = value_log.value();
const CPPType &type = *value.type();
+ const void *buffer = value.get();
if (type.is<Object *>()) {
- id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB);
+ id_to_inspection_string((ID *)buffer, ID_OB);
}
else if (type.is<Material *>()) {
- id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA);
+ id_to_inspection_string((ID *)buffer, ID_MA);
}
else if (type.is<Tex *>()) {
- id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE);
+ id_to_inspection_string((ID *)buffer, ID_TE);
}
else if (type.is<Image *>()) {
- id_to_inspection_string((ID *)*value.get<Image *>(), ID_IM);
+ id_to_inspection_string((ID *)buffer, ID_IM);
}
else if (type.is<Collection *>()) {
- id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR);
+ id_to_inspection_string((ID *)buffer, ID_GR);
+ }
+ else if (type.is<int>()) {
+ ss << *(int *)buffer << TIP_(" (Integer)");
+ }
+ else if (type.is<float>()) {
+ ss << *(float *)buffer << TIP_(" (Float)");
+ }
+ else if (type.is<blender::float3>()) {
+ ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
+ }
+ else if (type.is<bool>()) {
+ ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+ }
+ else if (type.is<std::string>()) {
+ ss << *(std::string *)buffer << TIP_(" (String)");
}
}
@@ -880,21 +864,7 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v
if (field) {
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
blender::fn::evaluate_constant_field(field, buffer);
- if (type.is<int>()) {
- ss << *(int *)buffer << TIP_(" (Integer)");
- }
- else if (type.is<float>()) {
- ss << *(float *)buffer << TIP_(" (Float)");
- }
- else if (type.is<blender::float3>()) {
- ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
- }
- else if (type.is<bool>()) {
- ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
- }
- else if (type.is<std::string>()) {
- ss << *(std::string *)buffer << TIP_(" (String)");
- }
+ create_inspection_string_for_generic_value({type, buffer}, ss);
type.destruct(buffer);
}
else {
@@ -1005,7 +975,6 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
}
static std::optional<std::string> create_socket_inspection_string(bContext *C,
- bNodeTree &UNUSED(ntree),
bNode &node,
bNodeSocket &socket)
{
@@ -1023,7 +992,7 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
std::stringstream ss;
if (const geo_log::GenericValueLog *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
- create_inspection_string_for_generic_value(*generic_value_log, ss);
+ create_inspection_string_for_generic_value(generic_value_log->value(), ss);
}
if (const geo_log::GFieldValueLog *gfield_value_log =
dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
@@ -1037,54 +1006,52 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
return ss.str();
}
-static void node_socket_draw_nested(const bContext *C,
- bNodeTree *ntree,
- PointerRNA *node_ptr,
- bNodeSocket *sock,
- uint pos_id,
- uint col_id,
- uint shape_id,
- uint size_id,
- uint outline_col_id,
- float size,
- bool selected)
+static void node_socket_draw_nested(const bContext &C,
+ bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ uiBlock &block,
+ bNodeSocket &sock,
+ const uint pos_id,
+ const uint col_id,
+ const uint shape_id,
+ const uint size_id,
+ const uint outline_col_id,
+ const float size,
+ const bool selected)
{
float color[4];
float outline_color[4];
node_socket_color_get(C, ntree, node_ptr, sock, color);
- node_socket_outline_color_get(selected, sock->type, outline_color);
+ node_socket_outline_color_get(selected, sock.type, outline_color);
node_socket_draw(sock,
color,
outline_color,
size,
- sock->locx,
- sock->locy,
+ sock.locx,
+ sock.locy,
pos_id,
col_id,
shape_id,
size_id,
outline_col_id);
- if (ntree->type != NTREE_GEOMETRY) {
+ if (ntree.type != NTREE_GEOMETRY) {
/* Only geometry nodes has socket value tooltips currently. */
return;
}
- bNode *node = (bNode *)node_ptr->data;
- uiBlock *block = node->block;
-
/* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
* button on top of them for the tooltip. */
- const eUIEmbossType old_emboss = UI_block_emboss_get(block);
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(block,
+ const eUIEmbossType old_emboss = UI_block_emboss_get(&block);
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
ICON_NONE,
- sock->locx - size / 2,
- sock->locy - size / 2,
+ sock.locx - size / 2,
+ sock.locy - size / 2,
size,
size,
nullptr,
@@ -1095,16 +1062,16 @@ static void node_socket_draw_nested(const bContext *C,
nullptr);
SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__);
- data->ntree = ntree;
- data->node = (bNode *)node_ptr->data;
- data->socket = sock;
+ data->ntree = &ntree;
+ data->node = (bNode *)node_ptr.data;
+ data->socket = &sock;
UI_but_func_tooltip_set(
but,
[](bContext *C, void *argN, const char *UNUSED(tip)) {
SocketTooltipData *data = (SocketTooltipData *)argN;
std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
- C, *data->ntree, *data->node, *data->socket);
+ C, *data->node, *data->socket);
std::stringstream output;
if (data->socket->declaration != nullptr) {
@@ -1126,14 +1093,9 @@ static void node_socket_draw_nested(const bContext *C,
MEM_freeN);
/* Disable the button so that clicks on it are ignored the the link operator still works. */
UI_but_flag_enable(but, UI_BUT_DISABLED);
- UI_block_emboss_set(block, old_emboss);
+ UI_block_emboss_set(&block, old_emboss);
}
-/**
- * Draw a single node socket at default size.
- * \note this is only called from external code, internally #node_socket_draw_nested() is used for
- * optimized drawing of multiple/all sockets of a node.
- */
void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
{
const float size = 2.25f * NODE_SOCKSIZE * scale;
@@ -1162,7 +1124,7 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[
/* Single point. */
immBegin(GPU_PRIM_POINTS, 1);
- node_socket_draw(sock,
+ node_socket_draw(*sock,
color,
outline_color,
BLI_rcti_size_y(&draw_rect),
@@ -1260,34 +1222,38 @@ static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_
const char *opname = (const char *)op_argv;
/* Select & activate only the button's node. */
- node_select_single(C, node);
+ node_select_single(*C, *node);
WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, nullptr);
}
-void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha)
+static void node_draw_shadow(const SpaceNode &snode,
+ const bNode &node,
+ const float radius,
+ const float alpha)
{
- const rctf *rct = &node->totr;
+ const rctf &rct = node.totr;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- ui_draw_dropshadow(rct, radius, snode->runtime->aspect, alpha, node->flag & SELECT);
+ ui_draw_dropshadow(&rct, radius, snode.runtime->aspect, alpha, node.flag & SELECT);
}
-void node_draw_sockets(const View2D *v2d,
- const bContext *C,
- bNodeTree *ntree,
- bNode *node,
- bool draw_outputs,
- bool select_all)
+static void node_draw_sockets(const View2D &v2d,
+ const bContext &C,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
+ const bool draw_outputs,
+ const bool select_all)
{
- const uint total_input_len = BLI_listbase_count(&node->inputs);
- const uint total_output_len = BLI_listbase_count(&node->outputs);
+ const uint total_input_len = BLI_listbase_count(&node.inputs);
+ const uint total_output_len = BLI_listbase_count(&node.outputs);
if (total_input_len + total_output_len == 0) {
return;
}
PointerRNA node_ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
+ RNA_pointer_create((ID *)&ntree, &RNA_Node, &node, &node_ptr);
bool selected = false;
@@ -1307,7 +1273,7 @@ void node_draw_sockets(const View2D *v2d,
/* Set handle size. */
float scale;
- UI_view2d_scale_get(v2d, &scale, nullptr);
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
scale *= 2.25f * NODE_SOCKSIZE;
if (!select_all) {
@@ -1316,7 +1282,7 @@ void node_draw_sockets(const View2D *v2d,
/* Socket inputs. */
short selected_input_len = 0;
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
@@ -1331,8 +1297,9 @@ void node_draw_sockets(const View2D *v2d,
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1345,7 +1312,7 @@ void node_draw_sockets(const View2D *v2d,
/* Socket outputs. */
short selected_output_len = 0;
if (draw_outputs) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
@@ -1356,8 +1323,9 @@ void node_draw_sockets(const View2D *v2d,
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1382,15 +1350,16 @@ void node_draw_sockets(const View2D *v2d,
if (selected_input_len) {
/* Socket inputs. */
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.inputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
if (select_all || (sock->flag & SELECT)) {
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1407,15 +1376,16 @@ void node_draw_sockets(const View2D *v2d,
if (selected_output_len) {
/* Socket outputs. */
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node.outputs) {
if (nodeSocketIsHidden(sock)) {
continue;
}
if (select_all || (sock->flag & SELECT)) {
node_socket_draw_nested(C,
ntree,
- &node_ptr,
- sock,
+ node_ptr,
+ block,
+ *sock,
pos_id,
col_id,
shape_id,
@@ -1440,7 +1410,7 @@ void node_draw_sockets(const View2D *v2d,
/* Draw multi-input sockets after the others because they are drawn with `UI_draw_roundbox`
* rather than with `GL_POINT`. */
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (nodeSocketIsHidden(socket)) {
continue;
}
@@ -1448,13 +1418,13 @@ void node_draw_sockets(const View2D *v2d,
continue;
}
- const bool is_node_hidden = (node->flag & NODE_HIDDEN);
+ const bool is_node_hidden = (node.flag & NODE_HIDDEN);
const float width = NODE_SOCKSIZE;
- float height = is_node_hidden ? width : node_socket_calculate_height(socket) - width;
+ float height = is_node_hidden ? width : node_socket_calculate_height(*socket) - width;
float color[4];
float outline_color[4];
- node_socket_color_get(C, ntree, &node_ptr, socket, color);
+ node_socket_color_get(C, ntree, node_ptr, *socket, color);
node_socket_outline_color_get(selected, socket->type, outline_color);
node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy);
@@ -1536,9 +1506,9 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char
#define NODE_HEADER_ICON_SIZE (0.8f * U.widget_unit)
static void node_add_error_message_button(
- const bContext *C, bNodeTree &UNUSED(ntree), bNode &node, const rctf &rect, float &icon_offset)
+ const bContext &C, bNode &node, uiBlock &block, const rctf &rect, float &icon_offset)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(*snode,
node);
if (node_log == nullptr) {
@@ -1558,8 +1528,8 @@ static void node_add_error_message_button(
const geo_log::NodeWarningType display_type = node_error_highest_priority(warnings);
icon_offset -= NODE_HEADER_ICON_SIZE;
- UI_block_emboss_set(node.block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node.block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
node_error_type_to_icon(display_type),
@@ -1574,47 +1544,288 @@ static void node_add_error_message_button(
0,
nullptr);
UI_but_func_tooltip_set(but, node_errors_tooltip_fn, tooltip_data, MEM_freeN);
- UI_block_emboss_set(node.block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
+}
+
+static void get_exec_time_other_nodes(const bNode &node,
+ const SpaceNode &snode,
+ std::chrono::microseconds &exec_time,
+ int &node_count)
+{
+ if (node.type == NODE_GROUP) {
+ const geo_log::TreeLog *root_tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context(
+ snode);
+ if (root_tree_log == nullptr) {
+ return;
+ }
+ const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node.name);
+ if (tree_log == nullptr) {
+ return;
+ }
+ tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
+ exec_time += node_log.execution_time();
+ node_count++;
+ });
+ }
+ else {
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(
+ snode, node);
+ if (node_log) {
+ exec_time += node_log->execution_time();
+ node_count++;
+ }
+ }
+}
+
+static std::chrono::microseconds node_get_execution_time(const bNodeTree &ntree,
+ const bNode &node,
+ const SpaceNode &snode,
+ int &node_count)
+{
+ std::chrono::microseconds exec_time = std::chrono::microseconds::zero();
+ if (node.type == NODE_GROUP_OUTPUT) {
+ const geo_log::TreeLog *tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context(
+ snode);
+
+ if (tree_log == nullptr) {
+ return exec_time;
+ }
+ tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
+ exec_time += node_log.execution_time();
+ node_count++;
+ });
+ }
+ else if (node.type == NODE_FRAME) {
+ /* Could be cached in the future if this recursive code turns out to be slow. */
+ LISTBASE_FOREACH (bNode *, tnode, &ntree.nodes) {
+ if (tnode->parent != &node) {
+ continue;
+ }
+
+ if (tnode->type == NODE_FRAME) {
+ exec_time += node_get_execution_time(ntree, *tnode, snode, node_count);
+ }
+ else {
+ get_exec_time_other_nodes(*tnode, snode, exec_time, node_count);
+ }
+ }
+ }
+ else {
+ get_exec_time_other_nodes(node, snode, exec_time, node_count);
+ }
+ return exec_time;
+}
+
+static std::string node_get_execution_time_label(const SpaceNode &snode, const bNode &node)
+{
+ int node_count = 0;
+ std::chrono::microseconds exec_time = node_get_execution_time(
+ *snode.nodetree, node, snode, node_count);
+
+ if (node_count == 0) {
+ return std::string("");
+ }
+
+ uint64_t exec_time_us = exec_time.count();
+
+ /* Don't show time if execution time is 0 microseconds. */
+ if (exec_time_us == 0) {
+ return std::string("-");
+ }
+ if (exec_time_us < 100) {
+ return std::string("< 0.1 ms");
+ }
+
+ int precision = 0;
+ /* Show decimal if value is below 1ms */
+ if (exec_time_us < 1000) {
+ precision = 2;
+ }
+ else if (exec_time_us < 10000) {
+ precision = 1;
+ }
+
+ std::stringstream stream;
+ stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f);
+ return stream.str() + " ms";
+}
+
+struct NodeExtraInfoRow {
+ std::string text;
+ const char *tooltip;
+ int icon;
+};
+
+static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode &snode, const bNode &node)
+{
+ Vector<NodeExtraInfoRow> rows;
+ if (!(snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) {
+ return rows;
+ }
+
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode.edittree->type == NTREE_GEOMETRY &&
+ (ELEM(node.typeinfo->nclass, NODE_CLASS_GEOMETRY, NODE_CLASS_GROUP, NODE_CLASS_ATTRIBUTE) ||
+ ELEM(node.type, NODE_FRAME, NODE_GROUP_OUTPUT))) {
+ NodeExtraInfoRow row;
+ row.text = node_get_execution_time_label(snode, node);
+ if (!row.text.empty()) {
+ row.tooltip = TIP_(
+ "The execution time from the node tree's latest evaluation. For frame and group nodes, "
+ "the time for all sub-nodes");
+ row.icon = ICON_PREVIEW_RANGE;
+ rows.append(std::move(row));
+ }
+ }
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(snode,
+ node);
+ if (node_log != nullptr) {
+ for (const std::string &message : node_log->debug_messages()) {
+ NodeExtraInfoRow row;
+ row.text = message;
+ row.icon = ICON_INFO;
+ rows.append(std::move(row));
+ }
+ }
+ return rows;
+}
+
+static void node_draw_extra_info_row(const bNode &node,
+ uiBlock &block,
+ const rctf &rect,
+ const int row,
+ const NodeExtraInfoRow &extra_info_row)
+{
+ uiBut *but_timing = uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ extra_info_row.text.c_str(),
+ (int)(rect.xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f),
+ (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
+ (short)(rect.xmax - rect.xmin),
+ (short)NODE_DY,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but_icon = uiDefIconBut(&block,
+ UI_BTYPE_BUT,
+ 0,
+ extra_info_row.icon,
+ (int)(rect.xmin + 6.0f * U.dpi_fac),
+ (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
+ NODE_HEADER_ICON_SIZE * 0.8f,
+ UI_UNIT_Y,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ extra_info_row.tooltip);
+ UI_block_emboss_set(&block, UI_EMBOSS);
+ if (node.flag & NODE_MUTED) {
+ UI_but_flag_enable(but_timing, UI_BUT_INACTIVE);
+ UI_but_flag_enable(but_icon, UI_BUT_INACTIVE);
+ }
+}
+
+static void node_draw_extra_info_panel(const SpaceNode &snode, const bNode &node, uiBlock &block)
+{
+ Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node);
+
+ if (extra_info_rows.size() == 0) {
+ return;
+ }
+
+ const rctf &rct = node.totr;
+ float color[4];
+ rctf extra_info_rect;
+
+ if (node.type == NODE_FRAME) {
+ extra_info_rect.xmin = rct.xmin;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac;
+ extra_info_rect.ymin = rct.ymin + 2.0f * U.dpi_fac;
+ extra_info_rect.ymax = rct.ymin + 2.0f * U.dpi_fac;
+ }
+ else {
+ extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac;
+ extra_info_rect.ymin = rct.ymax;
+ extra_info_rect.ymax = rct.ymax + extra_info_rows.size() * (20.0f * U.dpi_fac);
+
+ if (node.flag & NODE_MUTED) {
+ UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color);
+ }
+ else {
+ UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.75f, color);
+ }
+ color[3] -= 0.35f;
+ UI_draw_roundbox_corner_set(
+ UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT &
+ ((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
+ UI_draw_roundbox_4fv(&extra_info_rect, true, BASIS_RAD, color);
+
+ /* Draw outline. */
+ const float outline_width = 1.0f;
+ extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac - outline_width;
+ extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac + outline_width;
+ extra_info_rect.ymin = rct.ymax - outline_width;
+ extra_info_rect.ymax = rct.ymax + outline_width + extra_info_rows.size() * (20.0f * U.dpi_fac);
+
+ UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color);
+ UI_draw_roundbox_corner_set(
+ UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT &
+ ((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
+ UI_draw_roundbox_4fv(&extra_info_rect, false, BASIS_RAD, color);
+ }
+
+ for (int row : extra_info_rows.index_range()) {
+ node_draw_extra_info_row(node, block, extra_info_rect, row, extra_info_rows[row]);
+ }
}
-static void node_draw_basis(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
+static void node_draw_basis(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
bNodeInstanceKey key)
{
const float iconbutw = NODE_HEADER_ICON_SIZE;
/* Skip if out of view. */
- if (BLI_rctf_isect(&node->totr, &v2d->cur, nullptr) == false) {
- UI_block_end(C, node->block);
- node->block = nullptr;
+ if (BLI_rctf_isect(&node.totr, &v2d.cur, nullptr) == false) {
+ UI_block_end(&C, &block);
return;
}
/* Shadow. */
node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
- rctf *rct = &node->totr;
+ const rctf &rct = node.totr;
float color[4];
int color_id = node_get_colorid(node);
GPU_line_width(1.0f);
+ node_draw_extra_info_panel(snode, node, block);
+
/* Header. */
{
const rctf rect = {
- rct->xmin,
- rct->xmax,
- rct->ymax - NODE_DY,
- rct->ymax,
+ rct.xmin,
+ rct.xmax,
+ rct.ymax - NODE_DY,
+ rct.ymax,
};
float color_header[4];
/* Muted nodes get a mix of the background with the node color. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_GetThemeColorBlend4f(TH_BACK, color_id, 0.1f, color_header);
}
else {
@@ -1626,18 +1837,18 @@ static void node_draw_basis(const bContext *C,
}
/* Show/hide icons. */
- float iconofs = rct->xmax - 0.35f * U.widget_unit;
+ float iconofs = rct.xmax - 0.35f * U.widget_unit;
/* Preview. */
- if (node->typeinfo->flag & NODE_PREVIEW) {
+ if (node.typeinfo->flag & NODE_PREVIEW) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_MATERIAL,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1646,24 +1857,24 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_preview_toggle");
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_preview_toggle");
/* XXX this does not work when node is activated and the operator called right afterwards,
* since active ID is not updated yet (needs to process the notifier).
* This can only work as visual indicator! */
- // if (!(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
+ // if (!(node.flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT)))
// UI_but_flag_enable(but, UI_BUT_DISABLED);
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
/* Group edit. */
- if (node->type == NODE_GROUP) {
+ if (node.type == NODE_GROUP) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_NODETREE,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1672,18 +1883,18 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_group_edit");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_group_edit");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
- if (node->type == NODE_CUSTOM && node->typeinfo->ui_icon != ICON_NONE) {
+ if (node.type == NODE_CUSTOM && node.typeinfo->ui_icon != ICON_NONE) {
iconofs -= iconbutw;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
- uiDefIconBut(node->block,
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiDefIconBut(&block,
UI_BTYPE_BUT,
0,
- node->typeinfo->ui_icon,
+ node.typeinfo->ui_icon,
iconofs,
- rct->ymax - NODE_DY,
+ rct.ymax - NODE_DY,
iconbutw,
UI_UNIT_Y,
nullptr,
@@ -1692,13 +1903,13 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
- node_add_error_message_button(C, *ntree, *node, *rct, iconofs);
+ node_add_error_message_button(C, node, block, rct, iconofs);
/* Title. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
UI_GetThemeColor4fv(TH_SELECT, color);
}
else {
@@ -1708,14 +1919,14 @@ static void node_draw_basis(const bContext *C,
/* Collapse/expand icon. */
{
const int but_size = U.widget_unit * 0.8f;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_DOWNARROW_HLT,
- rct->xmin + (NODE_MARGIN_X / 3),
- rct->ymax - NODE_DY / 2.2f - but_size / 2,
+ rct.xmin + (NODE_MARGIN_X / 3),
+ rct.ymax - NODE_DY / 2.2f - but_size / 2,
but_size,
but_size,
nullptr,
@@ -1725,20 +1936,20 @@ static void node_draw_basis(const bContext *C,
0.0f,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
char showname[128];
- nodeLabel(ntree, node, showname, sizeof(showname));
+ nodeLabel(&ntree, &node, showname, sizeof(showname));
- uiBut *but = uiDefBut(node->block,
+ uiBut *but = uiDefBut(&block,
UI_BTYPE_LABEL,
0,
showname,
- (int)(rct->xmin + NODE_MARGIN_X + 0.4f),
- (int)(rct->ymax - NODE_DY),
- (short)(iconofs - rct->xmin - (18.0f * U.dpi_fac)),
+ (int)(rct.xmin + NODE_MARGIN_X + 0.4f),
+ (int)(rct.ymax - NODE_DY),
+ (short)(iconofs - rct.xmin - (18.0f * U.dpi_fac)),
(short)NODE_DY,
nullptr,
0,
@@ -1746,12 +1957,12 @@ static void node_draw_basis(const bContext *C,
0,
0,
"");
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
/* Wire across the node when muted/disabled. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
node_draw_mute_line(C, v2d, snode, node);
}
@@ -1759,35 +1970,35 @@ static void node_draw_basis(const bContext *C,
const float outline_width = 1.0f;
{
/* Use warning color to indicate undefined types. */
- if (nodeTypeUndefined(node)) {
+ if (nodeTypeUndefined(&node)) {
UI_GetThemeColorBlend4f(TH_REDALERT, TH_NODE, 0.4f, color);
}
/* Muted nodes get a mix of the background with the node color. */
- else if (node->flag & NODE_MUTED) {
+ else if (node.flag & NODE_MUTED) {
UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color);
}
- else if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
+ else if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], 1.0f);
}
else {
UI_GetThemeColor4fv(TH_NODE, color);
}
/* Draw selected nodes fully opaque. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
color[3] = 1.0f;
}
/* Draw muted nodes slightly transparent so the wires inside are visible. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
color[3] -= 0.2f;
}
const rctf rect = {
- rct->xmin,
- rct->xmax,
- rct->ymin,
- rct->ymax - (NODE_DY + outline_width),
+ rct.xmin,
+ rct.xmax,
+ rct.ymin,
+ rct.ymax - (NODE_DY + outline_width),
};
UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
@@ -1798,7 +2009,7 @@ static void node_draw_basis(const bContext *C,
{
float color_underline[4];
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_GetThemeColor4fv(TH_WIRE, color_underline);
}
else {
@@ -1806,10 +2017,10 @@ static void node_draw_basis(const bContext *C,
}
const rctf rect = {
- rct->xmin,
- rct->xmax,
- rct->ymax - (NODE_DY + outline_width),
- rct->ymax - NODE_DY,
+ rct.xmin,
+ rct.xmax,
+ rct.ymax - (NODE_DY + outline_width),
+ rct.ymax - NODE_DY,
};
UI_draw_roundbox_corner_set(UI_CNR_NONE);
@@ -1819,19 +2030,19 @@ static void node_draw_basis(const bContext *C,
/* Outline. */
{
const rctf rect = {
- rct->xmin - outline_width,
- rct->xmax + outline_width,
- rct->ymin - outline_width,
- rct->ymax + outline_width,
+ rct.xmin - outline_width,
+ rct.xmax + outline_width,
+ rct.ymin - outline_width,
+ rct.ymax + outline_width,
};
/* Color the outline according to active, selected, or undefined status. */
float color_outline[4];
- if (node->flag & SELECT) {
- UI_GetThemeColor4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
+ if (node.flag & SELECT) {
+ UI_GetThemeColor4fv((node.flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
}
- else if (nodeTypeUndefined(node)) {
+ else if (nodeTypeUndefined(&node)) {
UI_GetThemeColor4fv(TH_REDALERT, color_outline);
}
else {
@@ -1843,42 +2054,42 @@ static void node_draw_basis(const bContext *C,
}
float scale;
- UI_view2d_scale_get(v2d, &scale, nullptr);
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
/* Skip slow socket drawing if zoom is small. */
if (scale > 0.2f) {
- node_draw_sockets(v2d, C, ntree, node, true, false);
+ node_draw_sockets(v2d, C, ntree, node, block, true, false);
}
/* Preview. */
- bNodeInstanceHash *previews = (bNodeInstanceHash *)CTX_data_pointer_get(C, "node_previews").data;
- if (node->flag & NODE_PREVIEW && previews) {
+ bNodeInstanceHash *previews =
+ (bNodeInstanceHash *)CTX_data_pointer_get(&C, "node_previews").data;
+ if (node.flag & NODE_PREVIEW && previews) {
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
if (preview && (preview->xsize && preview->ysize)) {
- if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) {
- node_draw_preview(preview, &node->prvr);
+ if (preview->rect && !BLI_rctf_is_empty(&node.prvr)) {
+ node_draw_preview(preview, &node.prvr);
}
}
}
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
}
-static void node_draw_hidden(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey UNUSED(key))
+static void node_draw_hidden(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block)
{
- rctf *rct = &node->totr;
- float centy = BLI_rctf_cent_y(rct);
- float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
+ const rctf &rct = node.totr;
+ float centy = BLI_rctf_cent_y(&rct);
+ float hiddenrad = BLI_rctf_size_y(&rct) / 2.0f;
float scale;
- UI_view2d_scale_get(v2d, &scale, nullptr);
+ UI_view2d_scale_get(&v2d, &scale, nullptr);
const int color_id = node_get_colorid(node);
@@ -1886,43 +2097,43 @@ static void node_draw_hidden(const bContext *C,
node_draw_shadow(snode, node, hiddenrad, 1.0f);
/* Wire across the node when muted/disabled. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
node_draw_mute_line(C, v2d, snode, node);
}
/* Body. */
float color[4];
{
- if (nodeTypeUndefined(node)) {
+ if (nodeTypeUndefined(&node)) {
/* Use warning color to indicate undefined types. */
UI_GetThemeColorBlend4f(TH_REDALERT, TH_NODE, 0.4f, color);
}
- else if (node->flag & NODE_MUTED) {
+ else if (node.flag & NODE_MUTED) {
/* Muted nodes get a mix of the background with the node color. */
UI_GetThemeColorBlendShade4fv(TH_BACK, color_id, 0.1f, 0, color);
}
- else if (node->flag & NODE_CUSTOM_COLOR) {
- rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
+ else if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], 1.0f);
}
else {
UI_GetThemeColorBlend4f(TH_NODE, color_id, 0.4f, color);
}
/* Draw selected nodes fully opaque. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
color[3] = 1.0f;
}
/* Draw muted nodes slightly transparent so the wires inside are visible. */
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
color[3] -= 0.2f;
}
- UI_draw_roundbox_4fv(rct, true, hiddenrad, color);
+ UI_draw_roundbox_4fv(&rct, true, hiddenrad, color);
}
/* Title. */
- if (node->flag & SELECT) {
+ if (node.flag & SELECT) {
UI_GetThemeColor4fv(TH_SELECT, color);
}
else {
@@ -1932,13 +2143,13 @@ static void node_draw_hidden(const bContext *C,
/* Collapse/expand icon. */
{
const int but_size = U.widget_unit * 1.0f;
- UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
- uiBut *but = uiDefIconBut(node->block,
+ uiBut *but = uiDefIconBut(&block,
UI_BTYPE_BUT_TOGGLE,
0,
ICON_RIGHTARROW,
- rct->xmin + (NODE_MARGIN_X / 3),
+ rct.xmin + (NODE_MARGIN_X / 3),
centy - but_size / 2,
but_size,
but_size,
@@ -1949,20 +2160,20 @@ static void node_draw_hidden(const bContext *C,
0.0f,
"");
- UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
- UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)"NODE_OT_hide_toggle");
+ UI_block_emboss_set(&block, UI_EMBOSS);
}
char showname[128];
- nodeLabel(ntree, node, showname, sizeof(showname));
+ nodeLabel(&ntree, &node, showname, sizeof(showname));
- uiBut *but = uiDefBut(node->block,
+ uiBut *but = uiDefBut(&block,
UI_BTYPE_LABEL,
0,
showname,
- round_fl_to_int(rct->xmin + NODE_MARGIN_X),
+ round_fl_to_int(rct.xmin + NODE_MARGIN_X),
round_fl_to_int(centy - NODE_DY * 0.5f),
- (short)(BLI_rctf_size_x(rct) - ((18.0f + 12.0f) * U.dpi_fac)),
+ (short)(BLI_rctf_size_x(&rct) - ((18.0f + 12.0f) * U.dpi_fac)),
(short)NODE_DY,
nullptr,
0,
@@ -1975,19 +2186,19 @@ static void node_draw_hidden(const bContext *C,
{
const float outline_width = 1.0f;
const rctf rect = {
- rct->xmin - outline_width,
- rct->xmax + outline_width,
- rct->ymin - outline_width,
- rct->ymax + outline_width,
+ rct.xmin - outline_width,
+ rct.xmax + outline_width,
+ rct.ymin - outline_width,
+ rct.ymax + outline_width,
};
/* Color the outline according to active, selected, or undefined status. */
float color_outline[4];
- if (node->flag & SELECT) {
- UI_GetThemeColor4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
+ if (node.flag & SELECT) {
+ UI_GetThemeColor4fv((node.flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, color_outline);
}
- else if (nodeTypeUndefined(node)) {
+ else if (nodeTypeUndefined(&node)) {
UI_GetThemeColor4fv(TH_REDALERT, color_outline);
}
else {
@@ -1998,7 +2209,7 @@ static void node_draw_hidden(const bContext *C,
UI_draw_roundbox_4fv(&rect, false, hiddenrad, color_outline);
}
- if (node->flag & NODE_MUTED) {
+ if (node.flag & NODE_MUTED) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
@@ -2009,39 +2220,38 @@ static void node_draw_hidden(const bContext *C,
immUniformThemeColorShadeAlpha(TH_TEXT, -40, -180);
float dx = 0.5f * U.widget_unit;
- const float dx2 = 0.15f * U.widget_unit * snode->runtime->aspect;
+ const float dx2 = 0.15f * U.widget_unit * snode.runtime->aspect;
const float dy = 0.2f * U.widget_unit;
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, rct->xmax - dx, centy - dy);
- immVertex2f(pos, rct->xmax - dx, centy + dy);
+ immVertex2f(pos, rct.xmax - dx, centy - dy);
+ immVertex2f(pos, rct.xmax - dx, centy + dy);
- immVertex2f(pos, rct->xmax - dx - dx2, centy - dy);
- immVertex2f(pos, rct->xmax - dx - dx2, centy + dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy - dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy + dy);
immEnd();
immUniformThemeColorShadeAlpha(TH_TEXT, 0, -180);
- dx -= snode->runtime->aspect;
+ dx -= snode.runtime->aspect;
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, rct->xmax - dx, centy - dy);
- immVertex2f(pos, rct->xmax - dx, centy + dy);
+ immVertex2f(pos, rct.xmax - dx, centy - dy);
+ immVertex2f(pos, rct.xmax - dx, centy + dy);
- immVertex2f(pos, rct->xmax - dx - dx2, centy - dy);
- immVertex2f(pos, rct->xmax - dx - dx2, centy + dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy - dy);
+ immVertex2f(pos, rct.xmax - dx - dx2, centy + dy);
immEnd();
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
- node_draw_sockets(v2d, C, ntree, node, true, false);
+ node_draw_sockets(v2d, C, ntree, node, block, true, false);
- UI_block_end(C, node->block);
- UI_block_draw(C, node->block);
- node->block = nullptr;
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
}
-int node_get_resize_cursor(int directions)
+int node_get_resize_cursor(NodeResizeDirection directions)
{
if (directions == 0) {
return WM_CURSOR_DEFAULT;
@@ -2055,77 +2265,58 @@ int node_get_resize_cursor(int directions)
return WM_CURSOR_EDIT;
}
-void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
+void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor)
{
- bNodeTree *ntree = snode->edittree;
+ const bNodeTree *ntree = snode.edittree;
+ if (ntree == nullptr) {
+ WM_cursor_set(&win, WM_CURSOR_DEFAULT);
+ return;
+ }
+
bNode *node;
bNodeSocket *sock;
int wmcursor = WM_CURSOR_DEFAULT;
- if (ntree) {
- if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
- /* Pass. */
- }
- else {
- /* Check nodes front to back. */
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
- break; /* First hit on node stops. */
- }
- }
- if (node) {
- int dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
- wmcursor = node_get_resize_cursor(dir);
- }
- }
+ if (node_find_indicated_socket(
+ snode, &node, &sock, cursor, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
+ WM_cursor_set(&win, WM_CURSOR_DEFAULT);
+ return;
}
- WM_cursor_set(win, wmcursor);
-}
-
-void node_draw_default(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey key)
-{
- const View2D *v2d = &region->v2d;
- if (node->flag & NODE_HIDDEN) {
- node_draw_hidden(C, v2d, snode, ntree, node, key);
+ /* Check nodes front to back. */
+ for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
+ if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) {
+ break; /* First hit on node stops. */
+ }
}
- else {
- node_draw_basis(C, v2d, snode, ntree, node, key);
+ if (node) {
+ NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
+ wmcursor = node_get_resize_cursor(dir);
}
-}
-static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
-{
- if (node->typeinfo->draw_nodetype_prepare) {
- node->typeinfo->draw_nodetype_prepare(C, ntree, node);
- }
+ WM_cursor_set(&win, wmcursor);
}
-static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
+static void count_multi_input_socket_links(bNodeTree &ntree, SpaceNode &snode)
{
Map<bNodeSocket *, int> counts;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (link->tosock->flag & SOCK_MULTI_INPUT) {
int &count = counts.lookup_or_add(link->tosock, 0);
count++;
}
}
/* Count temporary links going into this socket. */
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
+ if (snode.runtime->linkdrag) {
+ for (const bNodeLink *link : snode.runtime->linkdrag->links) {
if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) {
int &count = counts.lookup_or_add(link->tosock, 0);
count++;
}
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
if (socket->flag & SOCK_MULTI_INPUT) {
socket->total_inputs = counts.lookup_default(socket, 0);
@@ -2134,86 +2325,367 @@ static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
}
}
-void node_update_nodetree(const bContext *C, bNodeTree *ntree)
+/* XXX Does a bounding box update by iterating over all children.
+ * Not ideal to do this in every draw call, but doing as transform callback doesn't work,
+ * since the child node totr rects are not updated properly at that point. */
+static void frame_node_prepare_for_draw(bNode &node, Span<bNode *> nodes)
+{
+ const float margin = 1.5f * U.widget_unit;
+ NodeFrame *data = (NodeFrame *)node.storage;
+
+ /* init rect from current frame size */
+ rctf rect;
+ node_to_updated_rect(node, rect);
+
+ /* frame can be resized manually only if shrinking is disabled or no children are attached */
+ data->flag |= NODE_FRAME_RESIZEABLE;
+ /* for shrinking bbox, initialize the rect from first child node */
+ bool bbinit = (data->flag & NODE_FRAME_SHRINK);
+ /* fit bounding box to all children */
+ for (const bNode *tnode : nodes) {
+ if (tnode->parent != &node) {
+ continue;
+ }
+
+ /* add margin to node rect */
+ rctf noderect = tnode->totr;
+ noderect.xmin -= margin;
+ noderect.xmax += margin;
+ noderect.ymin -= margin;
+ noderect.ymax += margin;
+
+ /* first child initializes frame */
+ if (bbinit) {
+ bbinit = false;
+ rect = noderect;
+ data->flag &= ~NODE_FRAME_RESIZEABLE;
+ }
+ else {
+ BLI_rctf_union(&rect, &noderect);
+ }
+ }
+
+ /* now adjust the frame size from view-space bounding box */
+ const float2 offset = node_from_view(node, {rect.xmin, rect.ymax});
+ node.offsetx = offset.x;
+ node.offsety = offset.y;
+ const float2 max = node_from_view(node, {rect.xmax, rect.ymin});
+ node.width = max.x - node.offsetx;
+ node.height = -max.y + node.offsety;
+
+ node.totr = rect;
+}
+
+static void reroute_node_prepare_for_draw(bNode &node)
+{
+ /* get "global" coords */
+ const float2 loc = node_to_view(node, float2(0));
+
+ /* reroute node has exactly one input and one output, both in the same place */
+ bNodeSocket *nsock = (bNodeSocket *)node.outputs.first;
+ nsock->locx = loc.x;
+ nsock->locy = loc.y;
+
+ nsock = (bNodeSocket *)node.inputs.first;
+ nsock->locx = loc.x;
+ nsock->locy = loc.y;
+
+ const float size = 8.0f;
+ node.width = size * 2;
+ node.totr.xmin = loc.x - size;
+ node.totr.xmax = loc.x + size;
+ node.totr.ymax = loc.y + size;
+ node.totr.ymin = loc.y - size;
+}
+
+static void node_update_nodetree(const bContext &C,
+ bNodeTree &ntree,
+ Span<bNode *> nodes,
+ Span<uiBlock *> blocks)
{
/* Make sure socket "used" tags are correct, for displaying value buttons. */
- SpaceNode *snode = CTX_wm_space_node(C);
- ntreeTagUsedSockets(ntree);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ ntreeTagUsedSockets(&ntree);
- count_multi_input_socket_links(ntree, snode);
+ count_multi_input_socket_links(ntree, *snode);
/* Update nodes front to back, so children sizes get updated before parents. */
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
- node_update(C, ntree, node);
+ for (const int i : nodes.index_range()) {
+ bNode &node = *nodes[i];
+ uiBlock &block = *blocks[i];
+ if (node.type == NODE_FRAME) {
+ frame_node_prepare_for_draw(node, nodes);
+ }
+ else if (node.type == NODE_REROUTE) {
+ reroute_node_prepare_for_draw(node);
+ }
+ else {
+ if (node.flag & NODE_HIDDEN) {
+ node_update_hidden(node, block);
+ }
+ else {
+ node_update_basis(C, ntree, node, block);
+ }
+ }
}
}
-static void node_draw(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey key)
+static void frame_node_draw_label(const bNodeTree &ntree,
+ const bNode &node,
+ const SpaceNode &snode)
{
- if (node->typeinfo->draw_nodetype) {
- node->typeinfo->draw_nodetype(C, region, snode, ntree, node, key);
+ const float aspect = snode.runtime->aspect;
+ /* XXX font id is crap design */
+ const int fontid = UI_style_get()->widgetlabel.uifont_id;
+ const NodeFrame *data = (const NodeFrame *)node.storage;
+ const float font_size = data->label_size / aspect;
+
+ char label[MAX_NAME];
+ nodeLabel(&ntree, &node, label, sizeof(label));
+
+ BLF_enable(fontid, BLF_ASPECT);
+ BLF_aspect(fontid, aspect, aspect, 1.0f);
+ /* clamp otherwise it can suck up a LOT of memory */
+ BLF_size(fontid, MIN2(24.0f, font_size), U.dpi);
+
+ /* title color */
+ int color_id = node_get_colorid(node);
+ uchar color[3];
+ UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
+ BLF_color3ubv(fontid, color);
+
+ const float margin = (float)(NODE_DY / 4);
+ const float width = BLF_width(fontid, label, sizeof(label));
+ const float ascender = BLF_ascender(fontid);
+ const int label_height = ((margin / aspect) + (ascender * aspect));
+
+ /* 'x' doesn't need aspect correction */
+ const rctf &rct = node.totr;
+ /* XXX a bit hacky, should use separate align values for x and y */
+ float x = BLI_rctf_cent_x(&rct) - (0.5f * width);
+ float y = rct.ymax - label_height;
+
+ /* label */
+ const bool has_label = node.label[0] != '\0';
+ if (has_label) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+ }
+
+ /* draw text body */
+ if (node.id) {
+ const Text *text = (const Text *)node.id;
+ const int line_height_max = BLF_height_max(fontid);
+ const float line_spacing = (line_height_max * aspect);
+ const float line_width = (BLI_rctf_size_x(&rct) - margin) / aspect;
+
+ /* 'x' doesn't need aspect correction */
+ x = rct.xmin + margin;
+ y = rct.ymax - label_height - (has_label ? line_spacing : 0);
+
+ /* early exit */
+ int y_min = y + ((margin * 2) - (y - rct.ymin));
+
+ BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
+ BLF_clipping(fontid,
+ rct.xmin,
+ /* round to avoid clipping half-way through a line */
+ y - (floorf(((y - rct.ymin) - (margin * 2)) / line_spacing) * line_spacing),
+ rct.xmin + line_width,
+ rct.ymax);
+
+ BLF_wordwrap(fontid, line_width);
+
+ LISTBASE_FOREACH (const TextLine *, line, &text->lines) {
+ struct ResultBLF info;
+ if (line->line[0]) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw_ex(fontid, line->line, line->len, &info);
+ y -= line_spacing * info.lines;
+ }
+ else {
+ y -= line_spacing;
+ }
+ if (y < y_min) {
+ break;
+ }
+ }
+
+ BLF_disable(fontid, BLF_CLIPPING | BLF_WORD_WRAP);
}
+
+ BLF_disable(fontid, BLF_ASPECT);
}
-#define USE_DRAW_TOT_UPDATE
+static void frame_node_draw(const bContext &C,
+ const ARegion &region,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block)
+{
+ /* skip if out of view */
+ if (BLI_rctf_isect(&node.totr, &region.v2d.cur, nullptr) == false) {
+ UI_block_end(&C, &block);
+ return;
+ }
+
+ float color[4];
+ UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+ const float alpha = color[3];
-void node_draw_nodetree(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNodeInstanceKey parent_key)
+ /* shadow */
+ node_draw_shadow(snode, node, BASIS_RAD, alpha);
+
+ /* body */
+ if (node.flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node.color[0], node.color[1], node.color[2], alpha);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+ }
+
+ const rctf &rct = node.totr;
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_4fv(&rct, true, BASIS_RAD, color);
+
+ /* outline active and selected emphasis */
+ if (node.flag & SELECT) {
+ if (node.flag & NODE_ACTIVE) {
+ UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color);
+ }
+ else {
+ UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
+ }
+
+ UI_draw_roundbox_aa(&rct, false, BASIS_RAD, color);
+ }
+
+ /* label and text */
+ frame_node_draw_label(ntree, node, snode);
+
+ node_draw_extra_info_panel(snode, node, block);
+
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
+}
+
+static void reroute_node_draw(
+ const bContext &C, ARegion &region, bNodeTree &ntree, bNode &node, uiBlock &block)
{
- if (ntree == nullptr) {
- return; /* Groups. */
+ char showname[128]; /* 128 used below */
+ const rctf &rct = node.totr;
+
+ /* skip if out of view */
+ if (rct.xmax < region.v2d.cur.xmin || rct.xmin > region.v2d.cur.xmax ||
+ rct.ymax < region.v2d.cur.ymin || node.totr.ymin > region.v2d.cur.ymax) {
+ UI_block_end(&C, &block);
+ return;
}
-#ifdef USE_DRAW_TOT_UPDATE
- if (ntree->nodes.first) {
- BLI_rctf_init_minmax(&region->v2d.tot);
+ if (node.label[0] != '\0') {
+ /* draw title (node label) */
+ BLI_strncpy(showname, node.label, sizeof(showname));
+ uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ showname,
+ (int)(rct.xmin - NODE_DYS),
+ (int)(rct.ymax),
+ (short)512,
+ (short)NODE_DY,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ }
+
+ /* only draw input socket. as they all are placed on the same position.
+ * highlight also if node itself is selected, since we don't display the node body separately!
+ */
+ node_draw_sockets(region.v2d, C, ntree, node, block, false, node.flag & SELECT);
+
+ UI_block_end(&C, &block);
+ UI_block_draw(&C, &block);
+}
+
+static void node_draw(const bContext &C,
+ ARegion &region,
+ const SpaceNode &snode,
+ bNodeTree &ntree,
+ bNode &node,
+ uiBlock &block,
+ bNodeInstanceKey key)
+{
+ if (node.type == NODE_FRAME) {
+ frame_node_draw(C, region, snode, ntree, node, block);
+ }
+ else if (node.type == NODE_REROUTE) {
+ reroute_node_draw(C, region, ntree, node, block);
+ }
+ else {
+ const View2D &v2d = region.v2d;
+ if (node.flag & NODE_HIDDEN) {
+ node_draw_hidden(C, v2d, snode, ntree, node, block);
+ }
+ else {
+ node_draw_basis(C, v2d, snode, ntree, node, block, key);
+ }
}
+}
+
+#define USE_DRAW_TOT_UPDATE
+
+static void node_draw_nodetree(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
+ bNodeTree &ntree,
+ Span<bNode *> nodes,
+ Span<uiBlock *> blocks,
+ bNodeInstanceKey parent_key)
+{
+#ifdef USE_DRAW_TOT_UPDATE
+ BLI_rctf_init_minmax(&region.v2d.tot);
#endif
/* Draw background nodes, last nodes in front. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ for (const int i : nodes.index_range()) {
#ifdef USE_DRAW_TOT_UPDATE
/* Unrelated to background nodes, update the v2d->tot,
* can be anywhere before we draw the scroll bars. */
- BLI_rctf_union(&region->v2d.tot, &node->totr);
+ BLI_rctf_union(&region.v2d.tot, &nodes[i]->totr);
#endif
- if (!(node->flag & NODE_BACKGROUND)) {
+ if (!(nodes[i]->flag & NODE_BACKGROUND)) {
continue;
}
- bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
- node_draw(C, region, snode, ntree, node, key);
+ bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
+ node_draw(C, region, snode, ntree, *nodes[i], *blocks[i], key);
}
/* Node lines. */
GPU_blend(GPU_BLEND_ALPHA);
nodelink_batch_start(snode);
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (!nodeLinkIsHidden(link)) {
- node_draw_link(C, &region->v2d, snode, link);
+ node_draw_link(C, region.v2d, snode, *link);
}
}
nodelink_batch_end(snode);
GPU_blend(GPU_BLEND_NONE);
/* Draw foreground nodes, last nodes in front. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->flag & NODE_BACKGROUND) {
+ for (const int i : nodes.index_range()) {
+ if (nodes[i]->flag & NODE_BACKGROUND) {
continue;
}
- bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
- node_draw(C, region, snode, ntree, node, key);
+ bNodeInstanceKey key = BKE_node_instance_key(parent_key, &ntree, nodes[i]);
+ node_draw(C, region, snode, ntree, *nodes[i], *blocks[i], key);
}
}
@@ -2247,36 +2719,38 @@ static void draw_tree_path(const bContext &C, ARegion &region)
GPU_matrix_pop_projection();
}
-static void snode_setup_v2d(SpaceNode *snode, ARegion *region, const float center[2])
+static void snode_setup_v2d(SpaceNode &snode, ARegion &region, const float2 &center)
{
- View2D *v2d = &region->v2d;
+ View2D &v2d = region.v2d;
/* Shift view to node tree center. */
- UI_view2d_center_set(v2d, center[0], center[1]);
- UI_view2d_view_ortho(v2d);
+ UI_view2d_center_set(&v2d, center[0], center[1]);
+ UI_view2d_view_ortho(&v2d);
/* Aspect + font, set each time. */
- snode->runtime->aspect = BLI_rctf_size_x(&v2d->cur) / (float)region->winx;
+ snode.runtime->aspect = BLI_rctf_size_x(&v2d.cur) / (float)region.winx;
// XXX snode->curfont = uiSetCurFont_ext(snode->aspect);
}
-static void draw_nodetree(const bContext *C,
- ARegion *region,
- bNodeTree *ntree,
+static void draw_nodetree(const bContext &C,
+ ARegion &region,
+ bNodeTree &ntree,
bNodeInstanceKey parent_key)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+
+ Vector<bNode *> nodes = ntree.nodes;
- node_uiblocks_init(C, ntree);
+ Array<uiBlock *> blocks = node_uiblocks_init(C, nodes);
- node_update_nodetree(C, ntree);
- node_draw_nodetree(C, region, snode, ntree, parent_key);
+ node_update_nodetree(C, ntree, nodes, blocks);
+ node_draw_nodetree(C, region, *snode, ntree, nodes, blocks, parent_key);
}
/**
* Make the background slightly brighter to indicate that users are inside a node-group.
*/
-static void draw_background_color(const SpaceNode *snode)
+static void draw_background_color(const SpaceNode &snode)
{
const int max_tree_length = 3;
const float bright_factor = 0.25f;
@@ -2284,7 +2758,7 @@ static void draw_background_color(const SpaceNode *snode)
/* We ignore the first element of the path since it is the top-most tree and it doesn't need to
* be brighter. We also set a cap to how many levels we want to set apart, to avoid the
* background from getting too bright. */
- const int clamped_tree_path_length = BLI_listbase_count_at_most(&snode->treepath,
+ const int clamped_tree_path_length = BLI_listbase_count_at_most(&snode.treepath,
max_tree_length);
const int depth = max_ii(0, clamped_tree_path_length - 1);
@@ -2294,34 +2768,34 @@ static void draw_background_color(const SpaceNode *snode)
GPU_clear_color(color[0], color[1], color[2], 1.0);
}
-void node_draw_space(const bContext *C, ARegion *region)
+void node_draw_space(const bContext &C, ARegion &region)
{
- wmWindow *win = CTX_wm_window(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- View2D *v2d = &region->v2d;
+ wmWindow *win = CTX_wm_window(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ View2D &v2d = region.v2d;
/* Setup off-screen buffers. */
- GPUViewport *viewport = WM_draw_region_get_viewport(region);
+ GPUViewport *viewport = WM_draw_region_get_viewport(&region);
GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport);
GPU_framebuffer_bind_no_srgb(framebuffer_overlay);
- UI_view2d_view_ortho(v2d);
+ UI_view2d_view_ortho(&v2d);
draw_background_color(snode);
GPU_depth_test(GPU_DEPTH_NONE);
GPU_scissor_test(true);
/* XXX `snode->runtime->cursor` set in coordinate-space for placing new nodes,
* used for drawing noodles too. */
- UI_view2d_region_to_view(&region->v2d,
- win->eventstate->xy[0] - region->winrct.xmin,
- win->eventstate->xy[1] - region->winrct.ymin,
- &snode->runtime->cursor[0],
- &snode->runtime->cursor[1]);
- snode->runtime->cursor[0] /= UI_DPI_FAC;
- snode->runtime->cursor[1] /= UI_DPI_FAC;
+ UI_view2d_region_to_view(&region.v2d,
+ win->eventstate->xy[0] - region.winrct.xmin,
+ win->eventstate->xy[1] - region.winrct.ymin,
+ &snode.runtime->cursor[0],
+ &snode.runtime->cursor[1]);
+ snode.runtime->cursor[0] /= UI_DPI_FAC;
+ snode.runtime->cursor[1] /= UI_DPI_FAC;
- ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_PRE_VIEW);
/* Only set once. */
GPU_blend(GPU_BLEND_ALPHA);
@@ -2330,15 +2804,15 @@ void node_draw_space(const bContext *C, ARegion *region)
snode_set_context(C);
const int grid_levels = UI_GetThemeValueType(TH_NODE_GRID_LEVELS, SPACE_NODE);
- UI_view2d_dot_grid_draw(v2d, TH_GRID, NODE_GRID_STEP_SIZE, grid_levels);
+ UI_view2d_dot_grid_draw(&v2d, TH_GRID, NODE_GRID_STEP_SIZE, grid_levels);
/* Draw parent node trees. */
- if (snode->treepath.last) {
- bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
+ if (snode.treepath.last) {
+ bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
/* Update tree path name (drawn in the bottom left). */
- ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id :
- snode->id;
+ ID *name_id = (path->nodetree && path->nodetree != snode.nodetree) ? &path->nodetree->id :
+ snode.id;
if (name_id && UNLIKELY(!STREQ(path->display_name, name_id->name + 2))) {
BLI_strncpy(path->display_name, name_id->name + 2, sizeof(path->display_name));
@@ -2346,12 +2820,12 @@ void node_draw_space(const bContext *C, ARegion *region)
/* Current View2D center, will be set temporarily for parent node trees. */
float center[2];
- UI_view2d_center_get(v2d, &center[0], &center[1]);
+ UI_view2d_center_get(&v2d, &center[0], &center[1]);
/* Store new view center in path and current edit tree. */
copy_v2_v2(path->view_center, center);
- if (snode->edittree) {
- copy_v2_v2(snode->edittree->view_center, center);
+ if (snode.edittree) {
+ copy_v2_v2(snode.edittree->view_center, center);
}
/* Top-level edit tree. */
@@ -2369,31 +2843,31 @@ void node_draw_space(const bContext *C, ARegion *region)
GPU_matrix_push();
GPU_matrix_identity_set();
- wmOrtho2_pixelspace(region->winx, region->winy);
+ wmOrtho2_pixelspace(region.winx, region.winy);
- WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
+ WM_gizmomap_draw(region.gizmo_map, &C, WM_GIZMOMAP_DRAWSTEP_2D);
GPU_matrix_pop();
GPU_matrix_projection_set(original_proj);
}
- draw_nodetree(C, region, ntree, path->parent_key);
+ draw_nodetree(C, region, *ntree, path->parent_key);
}
/* Temporary links. */
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
- LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- node_draw_link(C, v2d, snode, (bNodeLink *)linkdata->data);
+ if (snode.runtime->linkdrag) {
+ for (const bNodeLink *link : snode.runtime->linkdrag->links) {
+ node_draw_link(C, v2d, snode, *link);
}
}
GPU_line_smooth(false);
GPU_blend(GPU_BLEND_NONE);
- if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode->flag & SNODE_SHOW_GPENCIL) {
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode.flag & SNODE_SHOW_GPENCIL) {
/* Draw grease-pencil annotations. */
- ED_annotation_draw_view2d(C, true);
+ ED_annotation_draw_view2d(&C, true);
}
}
else {
@@ -2402,23 +2876,23 @@ void node_draw_space(const bContext *C, ARegion *region)
draw_nodespace_back_pix(C, region, snode, NODE_INSTANCE_KEY_NONE);
}
- ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
+ ED_region_draw_cb_draw(&C, &region, REGION_DRAW_POST_VIEW);
/* Reset view matrix. */
- UI_view2d_view_restore(C);
+ UI_view2d_view_restore(&C);
- if (snode->treepath.last) {
- if (snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS && snode->flag & SNODE_SHOW_GPENCIL) {
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_OVERLAYS) {
+ if (snode.flag & SNODE_SHOW_GPENCIL && snode.treepath.last) {
/* Draw grease-pencil (screen strokes, and also paint-buffer). */
- ED_annotation_draw_view2d(C, false);
+ ED_annotation_draw_view2d(&C, false);
}
- }
- /* Draw context path. */
- if (snode->edittree) {
- draw_tree_path(*C, *region);
+ /* Draw context path. */
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_PATH && snode.edittree) {
+ draw_tree_path(C, region);
+ }
}
/* Scrollers. */
- UI_view2d_scrollers_draw(v2d, nullptr);
+ UI_view2d_scrollers_draw(&v2d, nullptr);
}
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 30c9f7ea56b..fb90e2bfe50 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -31,9 +31,6 @@
#include "DNA_text_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -80,6 +77,8 @@
#define USE_ESC_COMPO
+using blender::float2;
+
/* ***************** composite job manager ********************** */
enum {
@@ -103,24 +102,23 @@ struct CompoJob {
float *progress;
};
-float node_socket_calculate_height(const bNodeSocket *socket)
+float node_socket_calculate_height(const bNodeSocket &socket)
{
float sock_height = NODE_SOCKSIZE * 2.0f;
- if (socket->flag & SOCK_MULTI_INPUT) {
- sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket->total_inputs, NODE_SOCKSIZE);
+ if (socket.flag & SOCK_MULTI_INPUT) {
+ sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket.total_inputs, NODE_SOCKSIZE);
}
return sock_height;
}
-void node_link_calculate_multi_input_position(const float socket_x,
- const float socket_y,
- const int index,
- const int total_inputs,
- float r[2])
+float2 node_link_calculate_multi_input_position(const float2 &socket_position,
+ const int index,
+ const int total_inputs)
{
- float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) * 0.5;
- r[0] = socket_x - NODE_SOCKSIZE * 0.5f;
- r[1] = socket_y - offset + (index * NODE_MULTI_INPUT_LINK_GAP);
+ const float offset = (total_inputs * NODE_MULTI_INPUT_LINK_GAP - NODE_MULTI_INPUT_LINK_GAP) *
+ 0.5f;
+ return {socket_position.x - NODE_SOCKSIZE * 0.5f,
+ socket_position.y - offset + index * NODE_MULTI_INPUT_LINK_GAP};
}
static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
@@ -320,13 +318,6 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
-/**
- * \param scene_owner: is the owner of the job,
- * we don't use it for anything else currently so could also be a void pointer,
- * but for now keep it an 'Scene' for consistency.
- *
- * \note only call from spaces `refresh` callbacks, not direct! - use with care.
- */
void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
{
Main *bmain = CTX_data_main(C);
@@ -370,7 +361,6 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
/* ***************************************** */
-/* operator poll callback */
bool composite_node_active(bContext *C)
{
if (ED_operator_node_active(C)) {
@@ -382,7 +372,6 @@ bool composite_node_active(bContext *C)
return false;
}
-/* operator poll callback */
bool composite_node_editable(bContext *C)
{
if (ED_operator_node_editable(C)) {
@@ -394,31 +383,31 @@ bool composite_node_editable(bContext *C)
return false;
}
-void snode_dag_update(bContext *C, SpaceNode *snode)
+void snode_dag_update(bContext &C, SpaceNode &snode)
{
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(&C);
/* for groups, update all ID's using this */
- if ((snode->edittree->id.flag & LIB_EMBEDDED_DATA) == 0) {
+ if ((snode.edittree->id.flag & LIB_EMBEDDED_DATA) == 0) {
FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- if (ntreeHasTree(tntree, snode->edittree)) {
+ if (ntreeHasTree(tntree, snode.edittree)) {
DEG_id_tag_update(id, 0);
}
}
FOREACH_NODETREE_END;
}
- DEG_id_tag_update(snode->id, 0);
- DEG_id_tag_update(&snode->nodetree->id, 0);
+ DEG_id_tag_update(snode.id, 0);
+ DEG_id_tag_update(&snode.nodetree->id, 0);
}
-void snode_notify(bContext *C, SpaceNode *snode)
+void snode_notify(bContext &C, SpaceNode &snode)
{
- ID *id = snode->id;
+ ID *id = snode.id;
- WM_event_add_notifier(C, NC_NODE | NA_EDITED, nullptr);
+ WM_event_add_notifier(&C, NC_NODE | NA_EDITED, nullptr);
- if (ED_node_is_shader(snode)) {
+ if (ED_node_is_shader(&snode)) {
if (GS(id->name) == ID_MA) {
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
}
@@ -429,13 +418,13 @@ void snode_notify(bContext *C, SpaceNode *snode)
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
}
}
- else if (ED_node_is_compositor(snode)) {
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, id);
+ else if (ED_node_is_compositor(&snode)) {
+ WM_event_add_notifier(&C, NC_SCENE | ND_NODES, id);
}
- else if (ED_node_is_texture(snode)) {
- WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
+ else if (ED_node_is_texture(&snode)) {
+ WM_event_add_notifier(&C, NC_TEXTURE | ND_NODES, id);
}
- else if (ED_node_is_geometry(snode)) {
+ else if (ED_node_is_geometry(&snode)) {
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
}
}
@@ -470,8 +459,6 @@ bool ED_node_is_geometry(struct SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Geometry->idname);
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_shader_default(const bContext *C, ID *id)
{
Main *bmain = CTX_data_main(C);
@@ -538,8 +525,6 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_composit_default(const bContext *C, struct Scene *sce)
{
/* but lets check it anyway */
@@ -573,8 +558,6 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
}
-/* assumes nothing being done in ntree yet, sets the default in/out node */
-/* called from shading buttons or header */
void ED_node_texture_default(const bContext *C, Tex *tex)
{
/* but lets check it anyway */
@@ -603,16 +586,18 @@ void ED_node_texture_default(const bContext *C, Tex *tex)
ntreeUpdateTree(CTX_data_main(C), tex->nodetree);
}
-/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
-void snode_set_context(const bContext *C)
+/**
+ * Here we set the active tree(s), even called for each redraw now, so keep it fast :)
+ */
+void snode_set_context(const bContext &C)
{
- SpaceNode *snode = CTX_wm_space_node(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
bNodeTreeType *treetype = ntreeTypeFind(snode->tree_idname);
bNodeTree *ntree = snode->nodetree;
ID *id = snode->id, *from = snode->from;
/* check the tree type */
- if (!treetype || (treetype->poll && !treetype->poll(C, treetype))) {
+ if (!treetype || (treetype->poll && !treetype->poll(&C, treetype))) {
/* invalid tree type, skip
* NOTE: not resetting the node path here, invalid #bNodeTreeType
* may still be registered at a later point. */
@@ -633,7 +618,7 @@ void snode_set_context(const bContext *C)
id = nullptr;
from = nullptr;
- treetype->get_from_context(C, treetype, &ntree, &id, &from);
+ treetype->get_from_context(&C, treetype, &ntree, &id, &from);
}
}
@@ -643,7 +628,7 @@ void snode_set_context(const bContext *C)
}
}
-void snode_update(SpaceNode *snode, bNode *node)
+void snode_update(SpaceNode &snode, bNode *node)
{
/* XXX this only updates nodes in the current node space tree path.
* The function supposedly should update any potential group node linking to changed tree,
@@ -651,7 +636,7 @@ void snode_update(SpaceNode *snode, bNode *node)
*/
/* update all edited group nodes */
- bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
+ bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
if (path) {
bNodeTree *ngroup = path->nodetree;
for (path = path->prev; path; path = path->prev) {
@@ -661,7 +646,7 @@ void snode_update(SpaceNode *snode, bNode *node)
}
if (node) {
- nodeUpdate(snode->edittree, node);
+ nodeUpdate(snode.edittree, node);
}
}
@@ -918,10 +903,10 @@ static void edit_node_properties_get(
/* ************************** Node generic ************** */
/* is rct in visible part of node? */
-static bNode *visible_node(SpaceNode *snode, const rctf *rct)
+static bNode *visible_node(SpaceNode &snode, const rctf &rct)
{
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) {
- if (BLI_rctf_isect(&node->totr, rct, nullptr)) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode.edittree->nodes) {
+ if (BLI_rctf_isect(&node->totr, &rct, nullptr)) {
return node;
}
}
@@ -938,13 +923,15 @@ struct NodeSizeWidget {
int directions;
};
-static void node_resize_init(
- bContext *C, wmOperator *op, const wmEvent *UNUSED(event), bNode *node, int dir)
+static void node_resize_init(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event),
+ const bNode *node,
+ NodeResizeDirection dir)
{
SpaceNode *snode = CTX_wm_space_node(C);
- NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget),
- "size widget op data");
+ NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget), __func__);
op->customdata = nsw;
nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC;
@@ -1089,21 +1076,22 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- bNode *node = nodeGetActive(snode->edittree);
- int dir;
+ const bNode *node = nodeGetActive(snode->edittree);
- if (node) {
- float cursor[2];
+ if (node == nullptr) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
- /* convert mouse coordinates to v2d space */
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
- dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]);
- if (dir != 0) {
- node_resize_init(C, op, event, node, dir);
- return OPERATOR_RUNNING_MODAL;
- }
+ /* convert mouse coordinates to v2d space */
+ float cursor[2];
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ const NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
+ if (dir == NODE_RESIZE_NONE) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
- return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+
+ node_resize_init(C, op, event, node, dir);
+ return OPERATOR_RUNNING_MODAL;
}
static void node_resize_cancel(bContext *C, wmOperator *op)
@@ -1171,7 +1159,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
}
/* checks snode->mouse position, and returns found node/socket */
-static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket *socket)
+static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSocket &socket)
{
const float node_socket_height = node_socket_calculate_height(socket);
rctf multi_socket_rect;
@@ -1181,19 +1169,21 @@ static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSo
* sometimes want to drag the link to the other side, if you may
* accidentally pick the wrong link otherwise. */
BLI_rctf_init(&multi_socket_rect,
- socket->locx - NODE_SOCKSIZE * 4.0f,
- socket->locx + NODE_SOCKSIZE * 2.0f,
- socket->locy - node_socket_height,
- socket->locy + node_socket_height);
+ socket.locx - NODE_SOCKSIZE * 4.0f,
+ socket.locx + NODE_SOCKSIZE * 2.0f,
+ socket.locy - node_socket_height,
+ socket.locy + node_socket_height);
if (BLI_rctf_isect_pt(&multi_socket_rect, cursor[0], cursor[1])) {
return true;
}
return false;
}
-/* type is SOCK_IN and/or SOCK_OUT */
-bool node_find_indicated_socket(
- SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out)
+bool node_find_indicated_socket(SpaceNode &snode,
+ bNode **nodep,
+ bNodeSocket **sockp,
+ const float2 &cursor,
+ const eNodeSocketInOut in_out)
{
rctf rect;
@@ -1201,7 +1191,7 @@ bool node_find_indicated_socket(
*sockp = nullptr;
/* check if we click in a socket */
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4);
if (!(node->flag & NODE_HIDDEN)) {
@@ -1220,8 +1210,8 @@ bool node_find_indicated_socket(
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (!nodeSocketIsHidden(sock)) {
if (sock->flag & SOCK_MULTI_INPUT && !(node->flag & NODE_HIDDEN)) {
- if (cursor_isect_multi_input_socket(cursor, sock)) {
- if (node == visible_node(snode, &rect)) {
+ if (cursor_isect_multi_input_socket(cursor, *sock)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
return true;
@@ -1229,7 +1219,7 @@ bool node_find_indicated_socket(
}
}
else if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
- if (node == visible_node(snode, &rect)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
return true;
@@ -1242,7 +1232,7 @@ bool node_find_indicated_socket(
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
if (!nodeSocketIsHidden(sock)) {
if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
- if (node == visible_node(snode, &rect)) {
+ if (node == visible_node(snode, rect)) {
*nodep = node;
*sockp = sock;
return true;
@@ -1258,28 +1248,28 @@ bool node_find_indicated_socket(
/* ****************** Link Dimming *********************** */
-float node_link_dim_factor(const View2D *v2d, const bNodeLink *link)
+float node_link_dim_factor(const View2D &v2d, const bNodeLink &link)
{
- if (link->fromsock == nullptr || link->tosock == nullptr) {
+ if (link.fromsock == nullptr || link.tosock == nullptr) {
return 1.0f;
}
const float min_endpoint_distance = std::min(
- std::max(BLI_rctf_length_x(&v2d->cur, link->fromsock->locx),
- BLI_rctf_length_y(&v2d->cur, link->fromsock->locy)),
- std::max(BLI_rctf_length_x(&v2d->cur, link->tosock->locx),
- BLI_rctf_length_y(&v2d->cur, link->tosock->locy)));
+ std::max(BLI_rctf_length_x(&v2d.cur, link.fromsock->locx),
+ BLI_rctf_length_y(&v2d.cur, link.fromsock->locy)),
+ std::max(BLI_rctf_length_x(&v2d.cur, link.tosock->locx),
+ BLI_rctf_length_y(&v2d.cur, link.tosock->locy)));
if (min_endpoint_distance == 0.0f) {
return 1.0f;
}
- const float viewport_width = BLI_rctf_size_x(&v2d->cur);
+ const float viewport_width = BLI_rctf_size_x(&v2d.cur);
return std::clamp(1.0f - min_endpoint_distance / viewport_width * 10.0f, 0.05f, 1.0f);
}
-bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link)
+bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
{
- return nodeLinkIsHidden(link) || node_link_dim_factor(v2d, link) < 0.5f;
+ return nodeLinkIsHidden(&link) || node_link_dim_factor(v2d, link) < 0.5f;
}
/* ****************** Duplicate *********************** */
@@ -1389,7 +1379,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
+ do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, *ntree, *newnode));
}
/* make sure we don't copy new nodes again! */
@@ -1400,9 +1390,9 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, *snode);
}
return OPERATOR_FINISHED;
@@ -1495,8 +1485,8 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -1663,7 +1653,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
node_flag_toggle_exec(snode, NODE_PREVIEW);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -1777,14 +1767,15 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if ((node->flag & SELECT) && !node->typeinfo->no_muting) {
node->flag ^= NODE_MUTED;
- snode_update(snode, node);
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
+ snode_update(*snode, node);
+ do_tag_update |= (do_tag_update ||
+ node_connected_to_output(*bmain, *snode->edittree, *node));
}
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, *snode);
}
return OPERATOR_FINISHED;
@@ -1817,16 +1808,17 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
if (node->flag & SELECT) {
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
+ do_tag_update |= (do_tag_update ||
+ node_connected_to_output(*bmain, *snode->edittree, *node));
nodeRemoveNode(bmain, snode->edittree, node, true);
}
}
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, *snode);
}
return OPERATOR_FINISHED;
@@ -1873,8 +1865,8 @@ static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -1911,8 +1903,8 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -1959,7 +1951,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "file_path", file_path);
ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -2008,7 +2000,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -2075,7 +2067,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
nimf->active_input++;
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -2285,7 +2277,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
/* deselect old nodes */
- node_deselect_all(snode);
+ node_deselect_all(*snode);
/* calculate "barycenter" for placing on mouse cursor */
float center[2] = {0.0f, 0.0f};
@@ -2323,8 +2315,8 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
ntreeUpdateTree(bmain, snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
/* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */
DEG_relations_tag_update(bmain);
@@ -2394,8 +2386,8 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2444,8 +2436,8 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2507,8 +2499,8 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(main, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2622,8 +2614,8 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op)
ntree->update |= NTREE_UPDATE_GROUP;
ntreeUpdateTree(CTX_data_main(C), ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2854,7 +2846,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
btree->flag |= NTREE_VIEWER_BORDER;
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
}
else {
@@ -2894,7 +2886,7 @@ static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
bNodeTree *btree = snode->nodetree;
btree->flag &= ~NTREE_VIEWER_BORDER;
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2939,7 +2931,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
ntreeCompositCryptomatteAddSocket(ntree, node);
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -2985,7 +2977,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ snode_notify(*C, *snode);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 79ba9b8d2d9..4890c3e39cf 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -100,13 +100,13 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
ED_undo_push(C, "Assign Attribute Name");
}
-void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
- const bNodeTree *node_tree,
- const bNode *node,
- PointerRNA *socket_ptr,
- uiLayout *layout)
+void node_geometry_add_attribute_search_button(const bContext &UNUSED(C),
+ const bNodeTree &node_tree,
+ const bNode &node,
+ PointerRNA &socket_ptr,
+ uiLayout &layout)
{
- uiBlock *block = uiLayoutGetBlock(layout);
+ uiBlock *block = uiLayoutGetBlock(&layout);
uiBut *but = uiDefIconTextButR(block,
UI_BTYPE_SEARCH_MENU,
0,
@@ -116,7 +116,7 @@ void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
0,
10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
UI_UNIT_Y,
- socket_ptr,
+ &socket_ptr,
"default_value",
0,
0.0f,
@@ -126,7 +126,7 @@ void node_geometry_add_attribute_search_button(const bContext *UNUSED(C),
"");
AttributeSearchData *data = OBJECT_GUARDED_NEW(
- AttributeSearchData, {node_tree, node, (bNodeSocket *)socket_ptr->data});
+ AttributeSearchData, {&node_tree, &node, (bNodeSocket *)socket_ptr.data});
UI_but_func_search_set_results_are_suggestions(but, true);
UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index d9fbbc81a8f..704ffe1e478 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -28,9 +28,9 @@
#include "DNA_anim_types.h"
#include "DNA_node_types.h"
+#include "BLI_float2.hh"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_string.h"
#include "BLT_translation.h"
@@ -60,6 +60,8 @@
#include "NOD_socket.h"
#include "node_intern.hh" /* own include */
+using blender::float2;
+
/* -------------------------------------------------------------------- */
/** \name Local Utilities
* \{ */
@@ -417,8 +419,8 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -444,24 +446,26 @@ void NODE_OT_group_ungroup(wmOperatorType *ot)
/** \name Separate Operator
* \{ */
-/* returns 1 if its OK */
-static int node_group_separate_selected(
- Main *bmain, bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy)
+/**
+ * \return True if successful.
+ */
+static bool node_group_separate_selected(
+ Main &bmain, bNodeTree &ntree, bNodeTree &ngroup, const float2 &offset, const bool make_copy)
{
/* deselect all nodes in the target tree */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
nodeSetSelected(node, false);
}
/* clear new pointers, set in BKE_node_copy_ex(). */
- LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ngroup.nodes) {
node->new_node = nullptr;
}
ListBase anim_basepaths = {nullptr, nullptr};
/* add selected nodes into the ntree */
- LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup->nodes) {
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) {
if (!(node->flag & NODE_SELECT)) {
continue;
}
@@ -475,7 +479,7 @@ static int node_group_separate_selected(
bNode *newnode;
if (make_copy) {
/* make a copy */
- newnode = BKE_node_copy_store_new_pointers(ngroup, node, LIB_ID_COPY_DEFAULT);
+ newnode = BKE_node_copy_store_new_pointers(&ngroup, node, LIB_ID_COPY_DEFAULT);
}
else {
/* use the existing node */
@@ -485,11 +489,11 @@ static int node_group_separate_selected(
/* keep track of this node's RNA "base" path (the part of the path identifying the node)
* if the old nodetree has animation data which potentially covers this node
*/
- if (ngroup->adt) {
+ if (ngroup.adt) {
PointerRNA ptr;
char *path;
- RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr);
+ RNA_pointer_create(&ngroup.id, &RNA_Node, newnode, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
if (path) {
@@ -503,27 +507,27 @@ static int node_group_separate_selected(
}
/* migrate node */
- BLI_remlink(&ngroup->nodes, newnode);
- BLI_addtail(&ntree->nodes, newnode);
+ BLI_remlink(&ngroup.nodes, newnode);
+ BLI_addtail(&ntree.nodes, newnode);
/* ensure unique node name in the node tree */
- nodeUniqueName(ntree, newnode);
+ nodeUniqueName(&ntree, newnode);
if (!newnode->parent) {
- newnode->locx += offx;
- newnode->locy += offy;
+ newnode->locx += offset.x;
+ newnode->locy += offset.y;
}
}
/* add internal links to the ntree */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup.links) {
const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
if (make_copy) {
/* make a copy of internal links */
if (fromselect && toselect) {
- nodeAddLink(ntree,
+ nodeAddLink(&ntree,
link->fromnode->new_node,
link->fromsock->new_sock,
link->tonode->new_node,
@@ -533,20 +537,20 @@ static int node_group_separate_selected(
else {
/* move valid links over, delete broken links */
if (fromselect && toselect) {
- BLI_remlink(&ngroup->links, link);
- BLI_addtail(&ntree->links, link);
+ BLI_remlink(&ngroup.links, link);
+ BLI_addtail(&ntree.links, link);
}
else if (fromselect || toselect) {
- nodeRemLink(ngroup, link);
+ nodeRemLink(&ngroup, link);
}
}
}
/* and copy across the animation,
* note that the animation data's action can be nullptr here */
- if (ngroup->adt) {
+ if (ngroup.adt) {
/* now perform the moving */
- BKE_animdata_transfer_by_basepath(bmain, &ngroup->id, &ntree->id, &anim_basepaths);
+ BKE_animdata_transfer_by_basepath(&bmain, &ngroup.id, &ntree.id, &anim_basepaths);
/* paths + their wrappers need to be freed */
LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
@@ -554,12 +558,12 @@ static int node_group_separate_selected(
}
}
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
if (!make_copy) {
- ngroup->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ ngroup.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
- return 1;
+ return true;
}
enum eNodeGroupSeparateType {
@@ -590,18 +594,17 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* get node tree offset */
- float offx, offy;
- space_node_group_offset(snode, &offx, &offy);
+ const float2 offset = space_node_group_offset(*snode);
switch (type) {
case NODE_GS_COPY:
- if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, true)) {
+ if (!node_group_separate_selected(*bmain, *nparent, *ngroup, offset, true)) {
BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes");
return OPERATOR_CANCELLED;
}
break;
case NODE_GS_MOVE:
- if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, false)) {
+ if (!node_group_separate_selected(*bmain, *nparent, *ngroup, offset, false)) {
BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes");
return OPERATOR_CANCELLED;
}
@@ -613,8 +616,8 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), snode->nodetree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
@@ -660,16 +663,16 @@ void NODE_OT_group_separate(wmOperatorType *ot)
/** \name Make Group Operator
* \{ */
-static bool node_group_make_use_node(bNode *node, bNode *gnode)
+static bool node_group_make_use_node(bNode &node, bNode *gnode)
{
- return (node != gnode && !ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
- (node->flag & NODE_SELECT));
+ return (&node != gnode && !ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
+ (node.flag & NODE_SELECT));
}
-static bool node_group_make_test_selected(bNodeTree *ntree,
+static bool node_group_make_test_selected(bNodeTree &ntree,
bNode *gnode,
const char *ntree_idname,
- struct ReportList *reports)
+ struct ReportList &reports)
{
int ok = true;
@@ -677,20 +680,20 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
bNodeTree *ngroup = ntreeAddTree(nullptr, "Pseudo Node Group", ntree_idname);
/* check poll functions for selected nodes */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
const char *disabled_hint = nullptr;
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, ngroup, &disabled_hint)) {
if (disabled_hint) {
- BKE_reportf(reports,
+ BKE_reportf(&reports,
RPT_WARNING,
"Can not add node '%s' in a group:\n %s",
node->name,
disabled_hint);
}
else {
- BKE_reportf(reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
+ BKE_reportf(&reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
}
ok = false;
break;
@@ -709,15 +712,15 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
/* check if all connections are OK, no unselected node has both
* inputs and outputs to a selection */
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (node_group_make_use_node(link->fromnode, gnode)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_group_make_use_node(*link->fromnode, gnode)) {
link->tonode->done |= 1;
}
- if (node_group_make_use_node(link->tonode, gnode)) {
+ if (node_group_make_use_node(*link->tonode, gnode)) {
link->fromnode->done |= 2;
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->flag & NODE_SELECT) && node != gnode && node->done == 3) {
return false;
}
@@ -726,13 +729,13 @@ static bool node_group_make_test_selected(bNodeTree *ntree,
}
static int node_get_selected_minmax(
- bNodeTree *ntree, bNode *gnode, float *min, float *max, bool use_size)
+ bNodeTree &ntree, bNode *gnode, float2 &min, float2 &max, bool use_size)
{
int totselect = 0;
INIT_MINMAX2(min, max);
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
float loc[2];
nodeToView(node, node->offsetx, node->offsety, &loc[0], &loc[1]);
minmax_v2v2_v2(min, max, loc);
@@ -753,9 +756,9 @@ static int node_get_selected_minmax(
return totselect;
}
-static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, bNode *gnode)
+static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, bNode *gnode)
{
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(&C);
bNodeTree *ngroup = (bNodeTree *)gnode->id;
bool expose_visible = false;
@@ -768,12 +771,12 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
nodeSetSelected(node, false);
}
- float center[2], min[2], max[2];
+ float2 center, min, max;
const int totselect = node_get_selected_minmax(ntree, gnode, min, max, false);
add_v2_v2v2(center, min, max);
mul_v2_fl(center, 0.5f);
- float real_min[2], real_max[2];
+ float2 real_min, real_max;
node_get_selected_minmax(ntree, gnode, real_min, real_max, true);
/* auto-add interface for "solo" nodes */
@@ -784,16 +787,16 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ListBase anim_basepaths = {nullptr, nullptr};
/* move nodes over */
- LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
+ if (node_group_make_use_node(*node, gnode)) {
/* keep track of this node's RNA "base" path (the part of the pat identifying the node)
* if the old nodetree has animation data which potentially covers this node
*/
- if (ntree->adt) {
+ if (ntree.adt) {
PointerRNA ptr;
char *path;
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
+ RNA_pointer_create(&ntree.id, &RNA_Node, node, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
if (path) {
@@ -807,7 +810,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* change node-collection membership */
- BLI_remlink(&ntree->nodes, node);
+ BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
/* ensure unique node name in the ngroup */
@@ -816,8 +819,8 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* move animation data over */
- if (ntree->adt) {
- BKE_animdata_transfer_by_basepath(bmain, &ntree->id, &ngroup->id, &anim_basepaths);
+ if (ntree.adt) {
+ BKE_animdata_transfer_by_basepath(bmain, &ntree.id, &ngroup->id, &anim_basepaths);
/* paths + their wrappers need to be freed */
LISTBASE_FOREACH_MUTABLE (AnimationBasePathChange *, basepath_change, &anim_basepaths) {
@@ -829,36 +832,36 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ntreeFreeCache(ngroup);
/* create input node */
- bNode *input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT);
+ bNode *input_node = nodeAddStaticNode(&C, ngroup, NODE_GROUP_INPUT);
input_node->locx = real_min[0] - center[0] - offsetx;
input_node->locy = -offsety;
/* create output node */
- bNode *output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT);
+ bNode *output_node = nodeAddStaticNode(&C, ngroup, NODE_GROUP_OUTPUT);
output_node->locx = real_max[0] - center[0] + offsetx * 0.25f;
output_node->locy = -offsety;
/* relink external sockets */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
- int fromselect = node_group_make_use_node(link->fromnode, gnode);
- int toselect = node_group_make_use_node(link->tonode, gnode);
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
+ int fromselect = node_group_make_use_node(*link->fromnode, gnode);
+ int toselect = node_group_make_use_node(*link->tonode, gnode);
if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) {
/* remove all links to/from the gnode.
* this can remove link information, but there's no general way to preserve it.
*/
- nodeRemLink(ntree, link);
+ nodeRemLink(&ntree, link);
}
else if (toselect && !fromselect) {
bNodeSocket *link_sock;
bNode *link_node;
- node_socket_skip_reroutes(&ntree->links, link->tonode, link->tosock, &link_node, &link_sock);
+ node_socket_skip_reroutes(&ntree.links, link->tonode, link->tosock, &link_node, &link_sock);
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link_node, link_sock);
/* update the group node and interface node sockets,
* so the new interface socket can be linked.
*/
- node_group_update(ntree, gnode);
+ node_group_update(&ntree, gnode);
node_group_input_update(ngroup, input_node);
/* create new internal link */
@@ -887,13 +890,13 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
bNodeSocket *link_sock;
bNode *link_node;
node_socket_skip_reroutes(
- &ntree->links, link->fromnode, link->fromsock, &link_node, &link_sock);
+ &ntree.links, link->fromnode, link->fromsock, &link_node, &link_sock);
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link_node, link_sock);
/* update the group node and interface node sockets,
* so the new interface socket can be linked.
*/
- node_group_update(ntree, gnode);
+ node_group_update(&ntree, gnode);
node_group_output_update(ngroup, output_node);
/* create new internal link */
@@ -908,19 +911,19 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
/* move internal links */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
- int fromselect = node_group_make_use_node(link->fromnode, gnode);
- int toselect = node_group_make_use_node(link->tonode, gnode);
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
+ int fromselect = node_group_make_use_node(*link->fromnode, gnode);
+ int toselect = node_group_make_use_node(*link->tonode, gnode);
if (fromselect && toselect) {
- BLI_remlink(&ntree->links, link);
+ BLI_remlink(&ntree.links, link);
BLI_addtail(&ngroup->links, link);
}
}
/* move nodes in the group to the center */
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- if (node_group_make_use_node(node, gnode) && !node->parent) {
+ if (node_group_make_use_node(*node, gnode) && !node->parent) {
node->locx -= center[0];
node->locy -= center[1];
}
@@ -929,7 +932,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* Expose all unlinked sockets too but only the visible ones. */
if (expose_visible) {
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- if (node_group_make_use_node(node, gnode)) {
+ if (node_group_make_use_node(*node, gnode)) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
@@ -984,17 +987,17 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* update of the group tree */
ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS;
/* update of the tree containing the group instance node */
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
-static bNode *node_group_make_from_selected(const bContext *C,
- bNodeTree *ntree,
+static bNode *node_group_make_from_selected(const bContext &C,
+ bNodeTree &ntree,
const char *ntype,
const char *ntreetype)
{
- Main *bmain = CTX_data_main(C);
+ Main *bmain = CTX_data_main(&C);
- float min[2], max[2];
+ float2 min, max;
const int totselect = node_get_selected_minmax(ntree, nullptr, min, max, false);
/* don't make empty group */
if (totselect == 0) {
@@ -1005,7 +1008,7 @@ static bNode *node_group_make_from_selected(const bContext *C,
bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
/* make group node */
- bNode *gnode = nodeAddNode(C, ntree, ntype);
+ bNode *gnode = nodeAddNode(&C, &ntree, ntype);
gnode->id = (ID *)ngroup;
gnode->locx = 0.5f * (min[0] + max[0]);
@@ -1014,44 +1017,44 @@ static bNode *node_group_make_from_selected(const bContext *C,
node_group_make_insert_selected(C, ntree, gnode);
/* update of the tree containing the group instance node */
- ntree->update |= NTREE_UPDATE_NODES;
+ ntree.update |= NTREE_UPDATE_NODES;
return gnode;
}
static int node_group_make_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
const char *ntree_idname = group_ntree_idname(C);
const char *node_idname = node_group_idname(C);
Main *bmain = CTX_data_main(C);
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (!node_group_make_test_selected(ntree, nullptr, ntree_idname, op->reports)) {
+ if (!node_group_make_test_selected(ntree, nullptr, ntree_idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
- bNode *gnode = node_group_make_from_selected(C, ntree, node_idname, ntree_idname);
+ bNode *gnode = node_group_make_from_selected(*C, ntree, node_idname, ntree_idname);
if (gnode) {
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- nodeSetActive(ntree, gnode);
+ nodeSetActive(&ntree, gnode);
if (ngroup) {
- ED_node_tree_push(snode, ngroup, gnode);
+ ED_node_tree_push(&snode, ngroup, gnode);
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
- sort_multi_input_socket_links(snode, node, nullptr, nullptr);
+ sort_multi_input_socket_links(snode, *node, nullptr, nullptr);
}
ntreeUpdateTree(bmain, ngroup);
}
}
- ntreeUpdateTree(bmain, ntree);
+ ntreeUpdateTree(bmain, &ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
/* We broke relations in node tree, need to rebuild them in the graphs. */
DEG_relations_tag_update(bmain);
@@ -1096,11 +1099,11 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
}
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- if (!node_group_make_test_selected(ntree, gnode, ngroup->idname, op->reports)) {
+ if (!node_group_make_test_selected(*ntree, gnode, ngroup->idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
- node_group_make_insert_selected(C, ntree, gnode);
+ node_group_make_insert_selected(*C, *ntree, gnode);
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);
@@ -1108,8 +1111,8 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(bmain, ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, *snode);
+ snode_dag_update(*C, *snode);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 436df70429b..2e55bb0cb28 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -23,16 +23,14 @@
#pragma once
-#include "BKE_node.h"
-#include "UI_interface.h"
-#include "UI_view2d.h"
-
+#include "BLI_float2.hh"
#include "BLI_vector.hh"
-#include "UI_interface.hh"
-#include <stddef.h> /* for size_t */
+#include "BKE_node.h"
-/* internal exports only */
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_view2d.h"
struct ARegion;
struct ARegionType;
@@ -45,26 +43,39 @@ struct bNodeLink;
struct bNodeSocket;
struct wmGizmoGroupType;
struct wmKeyConfig;
+namespace blender {
+struct float2;
+}
struct wmWindow;
-/* temp data to pass on to modal */
+/** Temporary data used in node link drag modal operator. */
struct bNodeLinkDrag {
- struct bNodeLinkDrag *next, *prev;
-
- /* List of links dragged by the operator.
- * NOTE: This is a list of LinkData structs on top of the actual bNodeLinks.
- * This way the links can be added to the node tree while being stored in this list.
- */
- ListBase links;
+ /** Links dragged by the operator. */
+ blender::Vector<bNodeLink *> links;
bool from_multi_input_socket;
- int in_out;
+ eNodeSocketInOut in_out;
+
+ /** Draw handler for the "+" icon when dragging a link in empty space. */
+ void *draw_handle;
/** Temporarily stores the last picked link from multi-input socket operator. */
- struct bNodeLink *last_picked_multi_input_socket_link;
+ bNodeLink *last_picked_multi_input_socket_link;
+
+ /**
+ * Temporarily stores the last hovered socket for multi-input socket operator.
+ * Store it to recalculate sorting after it is no longer hovered.
+ */
+ bNode *last_node_hovered_while_dragging_a_link;
+
+ /* The cursor position, used for drawing a + icon when dragging a node link. */
+ std::array<int, 2> cursor;
- /** Temporarily stores the last hovered socket for multi-input socket operator.
- * Store it to recalculate sorting after it is no longer hovered. */
- struct bNode *last_node_hovered_while_dragging_a_link;
+ /** The node the drag started at. */
+ bNode *start_node;
+ /** The socket the drag started at. */
+ bNodeSocket *start_socket;
+ /** The number of links connected to the #start_socket when the drag started. */
+ int start_link_count;
/* Data for edge panning */
View2DEdgePanData pan_data;
@@ -74,83 +85,68 @@ struct SpaceNode_Runtime {
float aspect;
/** Mouse position for drawing socket-less links and adding nodes. */
- float cursor[2];
+ blender::float2 cursor;
/** For auto compositing. */
bool recalc;
/** Temporary data for modal linking operator. */
- struct ListBase linkdrag;
+ std::unique_ptr<bNodeLinkDrag> linkdrag;
/* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */
/** Temporary data for node insert offset (in UI called Auto-offset). */
struct NodeInsertOfsData *iofsd;
};
-/* space_node.c */
-
-/* transform between View2Ds in the tree path */
-void space_node_group_offset(SpaceNode *snode, float *x, float *y);
-
-/* node_draw.cc */
-float node_socket_calculate_height(const bNodeSocket *socket);
-void node_link_calculate_multi_input_position(const float socket_x,
- const float socket_y,
- const int index,
- const int total_inputs,
- float r[2]);
-
-int node_get_colorid(bNode *node);
-int node_get_resize_cursor(int directions);
-void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha);
-void node_draw_default(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNode *node,
- bNodeInstanceKey key);
-void node_draw_sockets(const View2D *v2d,
- const bContext *C,
- bNodeTree *ntree,
- bNode *node,
- bool draw_outputs,
- bool select_all);
-void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node);
-int node_select_area_default(bNode *node, int x, int y);
-int node_tweak_area_default(bNode *node, int x, int y);
-void node_socket_color_get(const bContext *C,
- bNodeTree *ntree,
- PointerRNA *node_ptr,
- bNodeSocket *sock,
+enum NodeResizeDirection {
+ NODE_RESIZE_NONE = 0,
+ NODE_RESIZE_TOP = (1 << 0),
+ NODE_RESIZE_BOTTOM = (1 << 1),
+ NODE_RESIZE_RIGHT = (1 << 2),
+ NODE_RESIZE_LEFT = (1 << 3),
+};
+ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT);
+
+/**
+ * Transform between View2Ds in the tree path.
+ */
+blender::float2 space_node_group_offset(const SpaceNode &snode);
+
+float node_socket_calculate_height(const bNodeSocket &socket);
+blender::float2 node_link_calculate_multi_input_position(const blender::float2 &socket_position,
+ int index,
+ int total_inputs);
+
+int node_get_resize_cursor(NodeResizeDirection directions);
+NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y);
+/**
+ * Usual convention here would be #node_socket_get_color(),
+ * but that's already used (for setting a color property socket).
+ */
+void node_socket_color_get(const bContext &C,
+ const bNodeTree &ntree,
+ PointerRNA &node_ptr,
+ const bNodeSocket &sock,
float r_color[4]);
-void node_update_nodetree(const bContext *C, bNodeTree *ntree);
-void node_draw_nodetree(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
- bNodeTree *ntree,
- bNodeInstanceKey parent_key);
-void node_draw_space(const bContext *C, ARegion *region);
-
-void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]);
+void node_draw_space(const bContext &C, ARegion &region);
+
+void node_set_cursor(wmWindow &win, SpaceNode &snode, const blender::float2 &cursor);
/* DPI scaled coords */
-void node_to_view(const bNode *node, float x, float y, float *rx, float *ry);
-void node_to_updated_rect(const bNode *node, rctf *r_rect);
-void node_from_view(const bNode *node, float x, float y, float *rx, float *ry);
+blender::float2 node_to_view(const bNode &node, const blender::float2 &co);
+void node_to_updated_rect(const bNode &node, rctf &r_rect);
+blender::float2 node_from_view(const bNode &node, const blender::float2 &co);
-/* node_toolbar.c */
void node_toolbar_register(ARegionType *art);
-/* node_ops.c */
void node_operatortypes(void);
void node_keymap(wmKeyConfig *keyconf);
-/* node_select.c */
-void node_deselect_all(SpaceNode *snode);
-void node_socket_select(bNode *node, bNodeSocket *sock);
-void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_node);
-void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes);
-void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_nodes);
-void node_select_single(bContext *C, bNode *node);
+void node_deselect_all(SpaceNode &snode);
+void node_socket_select(bNode *node, bNodeSocket &sock);
+void node_socket_deselect(bNode *node, bNodeSocket &sock, const bool deselect_node);
+void node_deselect_all_input_sockets(SpaceNode &snode, const bool deselect_nodes);
+void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_nodes);
+void node_select_single(bContext &C, bNode &node);
void NODE_OT_select(wmOperatorType *ot);
void NODE_OT_select_all(wmOperatorType *ot);
@@ -163,9 +159,8 @@ void NODE_OT_select_grouped(wmOperatorType *ot);
void NODE_OT_select_same_type_step(wmOperatorType *ot);
void NODE_OT_find_node(wmOperatorType *ot);
-/* node_view.c */
-int space_node_view_flag(
- bContext *C, SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx);
+bool space_node_view_flag(
+ bContext &C, SpaceNode &snode, ARegion &region, int node_flag, int smooth_viewtx);
void NODE_OT_view_all(wmOperatorType *ot);
void NODE_OT_view_selected(wmOperatorType *ot);
@@ -176,37 +171,50 @@ void NODE_OT_backimage_zoom(wmOperatorType *ot);
void NODE_OT_backimage_fit(wmOperatorType *ot);
void NODE_OT_backimage_sample(wmOperatorType *ot);
-/* drawnode.c */
-void nodelink_batch_start(SpaceNode *snode);
-void nodelink_batch_end(SpaceNode *snode);
-
-void node_draw_link(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link);
-void node_draw_link_bezier(const bContext *C,
- const View2D *v2d,
- const SpaceNode *snode,
- const bNodeLink *link,
+void nodelink_batch_start(SpaceNode &snode);
+void nodelink_batch_end(SpaceNode &snode);
+
+/**
+ * \note this is used for fake links in groups too.
+ */
+void node_draw_link(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link);
+/**
+ * Don't do shadows if th_col3 is -1.
+ */
+void node_draw_link_bezier(const bContext &C,
+ const View2D &v2d,
+ const SpaceNode &snode,
+ const bNodeLink &link,
int th_col1,
int th_col2,
int th_col3);
+/** If v2d not nullptr, it clips and returns 0 if not visible. */
bool node_link_bezier_points(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &link,
float coord_array[][2],
const int resol);
+/**
+ * Return quadratic beziers points for a given nodelink and clip if v2d is not nullptr.
+ */
bool node_link_bezier_handles(const View2D *v2d,
const SpaceNode *snode,
- const bNodeLink *link,
+ const bNodeLink &ink,
float vec[4][2]);
-void draw_nodespace_back_pix(const bContext *C,
- ARegion *region,
- SpaceNode *snode,
+void draw_nodespace_back_pix(const bContext &C,
+ ARegion &region,
+ SpaceNode &snode,
bNodeInstanceKey parent_key);
-/* node_add.c */
-bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy);
+/**
+ * XXX Does some additional initialization on top of #nodeAddNode
+ * Can be used with both custom and static nodes,
+ * if `idname == nullptr` the static int type will be used instead.
+ */
+bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy);
void NODE_OT_add_reroute(wmOperatorType *ot);
void NODE_OT_add_group(wmOperatorType *ot);
void NODE_OT_add_object(wmOperatorType *ot);
@@ -216,7 +224,6 @@ void NODE_OT_add_file(wmOperatorType *ot);
void NODE_OT_add_mask(wmOperatorType *ot);
void NODE_OT_new_node_tree(wmOperatorType *ot);
-/* node_group.c */
const char *node_group_idname(bContext *C);
void NODE_OT_group_make(wmOperatorType *ot);
void NODE_OT_group_insert(wmOperatorType *ot);
@@ -224,12 +231,11 @@ void NODE_OT_group_ungroup(wmOperatorType *ot);
void NODE_OT_group_separate(wmOperatorType *ot);
void NODE_OT_group_edit(wmOperatorType *ot);
-/* node_relationships.c */
-void sort_multi_input_socket_links(SpaceNode *snode,
- bNode *node,
+void sort_multi_input_socket_links(SpaceNode &snode,
+ bNode &node,
bNodeLink *drag_link,
- float cursor[2]);
-bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node);
+ const blender::float2 *cursor);
+bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node);
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
@@ -246,22 +252,27 @@ void NODE_OT_link_viewer(wmOperatorType *ot);
void NODE_OT_insert_offset(wmOperatorType *ot);
-/* node_edit.c */
-void snode_notify(bContext *C, SpaceNode *snode);
-void snode_dag_update(bContext *C, SpaceNode *snode);
-void snode_set_context(const bContext *C);
+void snode_notify(bContext &C, SpaceNode &snode);
+void snode_dag_update(bContext &C, SpaceNode &snode);
+void snode_set_context(const bContext &C);
-void snode_update(SpaceNode *snode, bNode *node);
+void snode_update(SpaceNode &snode, bNode *node);
+/** Operator poll callback. */
bool composite_node_active(bContext *C);
+/** Operator poll callback. */
bool composite_node_editable(bContext *C);
bool node_has_hidden_sockets(bNode *node);
void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set);
int node_render_changed_exec(bContext *, wmOperator *);
-bool node_find_indicated_socket(
- SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out);
-float node_link_dim_factor(const View2D *v2d, const bNodeLink *link);
-bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link);
+/** Type is #SOCK_IN and/or #SOCK_OUT. */
+bool node_find_indicated_socket(SpaceNode &snode,
+ bNode **nodep,
+ bNodeSocket **sockp,
+ const blender::float2 &cursor,
+ eNodeSocketInOut in_out);
+float node_link_dim_factor(const View2D &v2d, const bNodeLink &link);
+bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link);
void NODE_OT_duplicate(wmOperatorType *ot);
void NODE_OT_delete(wmOperatorType *ot);
@@ -284,7 +295,9 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot);
void NODE_OT_switch_view_update(wmOperatorType *ot);
-/* NOTE: clipboard_cut is a simple macro of copy + delete. */
+/**
+ * \note clipboard_cut is a simple macro of copy + delete.
+ */
void NODE_OT_clipboard_copy(wmOperatorType *ot);
void NODE_OT_clipboard_paste(wmOperatorType *ot);
@@ -298,7 +311,6 @@ void NODE_OT_shader_script_update(wmOperatorType *ot);
void NODE_OT_viewer_border(wmOperatorType *ot);
void NODE_OT_clear_viewer_border(wmOperatorType *ot);
-/* node_widgets.c */
void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt);
@@ -307,25 +319,22 @@ void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt);
void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot);
void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot);
-/* node_geometry_attribute_search.cc */
-void node_geometry_add_attribute_search_button(const bContext *C,
- const bNodeTree *node_tree,
- const bNode *node,
- PointerRNA *socket_ptr,
- uiLayout *layout);
+void node_geometry_add_attribute_search_button(const bContext &C,
+ const bNodeTree &node_tree,
+ const bNode &node,
+ PointerRNA &socket_ptr,
+ uiLayout &layout);
extern const char *node_context_dir[];
-/* XXXXXX */
-
/* Nodes draw without dpi - the view zoom is flexible. */
#define HIDDEN_RAD (0.75f * U.widget_unit)
#define BASIS_RAD (0.2f * U.widget_unit)
#define NODE_DYS (U.widget_unit / 2)
#define NODE_DY U.widget_unit
#define NODE_SOCKDY (0.1f * U.widget_unit)
-#define NODE_WIDTH(node) (node->width * UI_DPI_FAC)
-#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC)
+#define NODE_WIDTH(node) (node.width * UI_DPI_FAC)
+#define NODE_HEIGHT(node) (node.height * UI_DPI_FAC)
#define NODE_MARGIN_X (1.2f * U.widget_unit)
#define NODE_SOCKSIZE (0.25f * U.widget_unit)
#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit)
@@ -333,5 +342,12 @@ extern const char *node_context_dir[];
#define NODE_LINK_RESOL 12
namespace blender::ed::space_node {
+
Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C);
-}
+
+void invoke_node_link_drag_add_menu(bContext &C,
+ bNode &node,
+ bNodeSocket &socket,
+ const float2 &cursor);
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc
index 4c08f4d7b47..a6264f151e4 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -127,7 +127,7 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_cryptomatte_layer_remove);
}
-void ED_operatormacros_node(void)
+void ED_operatormacros_node()
{
wmOperatorType *ot;
wmOperatorTypeMacro *mot;
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index ab20eaf131f..90b53258d5e 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -26,9 +26,7 @@
#include "DNA_anim_types.h"
#include "DNA_node_types.h"
-#include "BLI_blenlib.h"
#include "BLI_easing.h"
-#include "BLI_math.h"
#include "BKE_anim_data.h"
#include "BKE_context.h"
@@ -41,6 +39,7 @@
#include "ED_node.h" /* own include */
#include "ED_render.h"
#include "ED_screen.h"
+#include "ED_space_api.h"
#include "ED_spreadsheet.h"
#include "ED_util.h"
@@ -52,6 +51,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_state.h"
+
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -59,37 +61,43 @@
#include "NOD_node_declaration.hh"
#include "NOD_node_tree_ref.hh"
+#include "NOD_socket_declarations.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "node_intern.hh" /* own include */
using namespace blender::nodes::node_tree_ref_types;
+using blender::float2;
+using blender::StringRef;
+using blender::StringRefNull;
+using blender::Vector;
/* -------------------------------------------------------------------- */
/** \name Relations Helpers
* \{ */
-static bool ntree_has_drivers(bNodeTree *ntree)
+static bool ntree_has_drivers(bNodeTree &ntree)
{
- const AnimData *adt = BKE_animdata_from_id(&ntree->id);
+ const AnimData *adt = BKE_animdata_from_id(&ntree.id);
if (adt == nullptr) {
return false;
}
return !BLI_listbase_is_empty(&adt->drivers);
}
-static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode *to)
+static bool ntree_check_nodes_connected_dfs(bNodeTree &ntree, bNode &from, bNode &to)
{
- if (from->flag & NODE_TEST) {
+ if (from.flag & NODE_TEST) {
return false;
}
- from->flag |= NODE_TEST;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (link->fromnode == from) {
- if (link->tonode == to) {
+ from.flag |= NODE_TEST;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (link->fromnode == &from) {
+ if (link->tonode == &to) {
return true;
}
- if (ntree_check_nodes_connected_dfs(ntree, link->tonode, to)) {
+ if (ntree_check_nodes_connected_dfs(ntree, *link->tonode, to)) {
return true;
}
}
@@ -97,26 +105,25 @@ static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode
return false;
}
-static bool ntree_check_nodes_connected(bNodeTree *ntree, bNode *from, bNode *to)
+static bool ntree_check_nodes_connected(bNodeTree &ntree, bNode &from, bNode &to)
{
- if (from == to) {
+ if (&from == &to) {
return true;
}
- ntreeNodeFlagSet(ntree, NODE_TEST, false);
+ ntreeNodeFlagSet(&ntree, NODE_TEST, false);
return ntree_check_nodes_connected_dfs(ntree, from, to);
}
-static bool node_group_has_output_dfs(bNode *node)
+static bool node_group_has_output_dfs(bNode &node)
{
- bNodeTree *ntree = (bNodeTree *)node->id;
+ bNodeTree *ntree = (bNodeTree *)node.id;
if (ntree->id.tag & LIB_TAG_DOIT) {
return false;
}
ntree->id.tag |= LIB_TAG_DOIT;
- for (bNode *current_node = (bNode *)ntree->nodes.first; current_node != nullptr;
- current_node = current_node->next) {
+ LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
if (current_node->type == NODE_GROUP) {
- if (current_node->id && node_group_has_output_dfs(current_node)) {
+ if (current_node->id && node_group_has_output_dfs(*current_node)) {
return true;
}
}
@@ -127,18 +134,18 @@ static bool node_group_has_output_dfs(bNode *node)
return false;
}
-static bool node_group_has_output(Main *bmain, bNode *node)
+static bool node_group_has_output(Main &bmain, bNode &node)
{
- BLI_assert(ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP));
- bNodeTree *ntree = (bNodeTree *)node->id;
+ BLI_assert(ELEM(node.type, NODE_GROUP, NODE_CUSTOM_GROUP));
+ bNodeTree *ntree = (bNodeTree *)node.id;
if (ntree == nullptr) {
return false;
}
- BKE_main_id_tag_listbase(&bmain->nodetrees, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_listbase(&bmain.nodetrees, LIB_TAG_DOIT, false);
return node_group_has_output_dfs(node);
}
-bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node)
+bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node)
{
/* Special case for drivers: if node tree has any drivers we assume it is
* always to be tagged for update when node changes. Otherwise we will be
@@ -148,7 +155,7 @@ bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node)
if (ntree_has_drivers(ntree)) {
return true;
}
- LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, current_node, &ntree.nodes) {
/* Special case for group nodes -- if modified node connected to a group
* with active output inside we consider refresh is needed.
*
@@ -156,21 +163,21 @@ bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node)
* is connected to and so eventually.
*/
if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- if (current_node->id != nullptr && ntree_has_drivers((bNodeTree *)current_node->id)) {
+ if (current_node->id != nullptr && ntree_has_drivers((bNodeTree &)current_node->id)) {
return true;
}
- if (ntree_check_nodes_connected(ntree, node, current_node) &&
- node_group_has_output(bmain, current_node)) {
+ if (ntree_check_nodes_connected(ntree, node, *current_node) &&
+ node_group_has_output(bmain, *current_node)) {
return true;
}
}
if (current_node->flag & NODE_DO_OUTPUT) {
- if (ntree_check_nodes_connected(ntree, node, current_node)) {
+ if (ntree_check_nodes_connected(ntree, node, *current_node)) {
return true;
}
}
if (current_node->type == GEO_NODE_VIEWER) {
- if (ntree_check_nodes_connected(ntree, node, current_node)) {
+ if (ntree_check_nodes_connected(ntree, node, *current_node)) {
return true;
}
}
@@ -207,49 +214,47 @@ static void clear_picking_highlight(ListBase *links)
}
}
-static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock)
+static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, bNodeSocket &sock)
{
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
- if (sock->in_out == SOCK_OUT) {
- oplink->fromnode = node;
- oplink->fromsock = sock;
+ bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__);
+ if (sock.in_out == SOCK_OUT) {
+ oplink->fromnode = &node;
+ oplink->fromsock = &sock;
}
else {
- oplink->tonode = node;
- oplink->tosock = sock;
+ oplink->tonode = &node;
+ oplink->tosock = &sock;
}
oplink->flag |= NODE_LINK_VALID;
oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, node)) {
+ if (node_connected_to_output(bmain, *snode.edittree, node)) {
oplink->flag |= NODE_LINK_TEST;
}
oplink->flag |= NODE_LINK_DRAGGED;
- return linkdata;
+ return oplink;
}
-static void pick_link(const bContext *C,
- wmOperator *op,
- bNodeLinkDrag *nldrag,
- SpaceNode *snode,
+static void pick_link(const bContext &C,
+ wmOperator &op,
+ bNodeLinkDrag &nldrag,
+ SpaceNode &snode,
bNode *node,
- bNodeLink *link_to_pick)
+ bNodeLink &link_to_pick)
{
- clear_picking_highlight(&snode->edittree->links);
- RNA_boolean_set(op->ptr, "has_link_picked", true);
+ clear_picking_highlight(&snode.edittree->links);
+ RNA_boolean_set(op.ptr, "has_link_picked", true);
- Main *bmain = CTX_data_main(C);
- LinkData *linkdata = create_drag_link(
- bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock);
+ Main *bmain = CTX_data_main(&C);
+ bNodeLink *link = create_drag_link(
+ *bmain, snode, *link_to_pick.fromnode, *link_to_pick.fromsock);
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link_to_pick);
+ nldrag.links.append(link);
+ nodeRemLink(snode.edittree, &link_to_pick);
- BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != nullptr);
+ BLI_assert(nldrag.last_node_hovered_while_dragging_a_link != nullptr);
sort_multi_input_socket_links(
- snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, nullptr);
+ snode, *nldrag.last_node_hovered_while_dragging_a_link, nullptr, nullptr);
/* Send changed event to original link->tonode. */
if (node) {
@@ -257,20 +262,20 @@ static void pick_link(const bContext *C,
}
}
-static void pick_input_link_by_link_intersect(const bContext *C,
- wmOperator *op,
- bNodeLinkDrag *nldrag,
- const float *cursor)
+static void pick_input_link_by_link_intersect(const bContext &C,
+ wmOperator &op,
+ bNodeLinkDrag &nldrag,
+ const float2 &cursor)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- const ARegion *region = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ const ARegion *region = CTX_wm_region(&C);
const View2D *v2d = &region->v2d;
float drag_start[2];
- RNA_float_get_array(op->ptr, "drag_start", drag_start);
+ RNA_float_get_array(op.ptr, "drag_start", drag_start);
bNode *node;
bNodeSocket *socket;
- node_find_indicated_socket(snode, &node, &socket, drag_start, SOCK_IN);
+ node_find_indicated_socket(*snode, &node, &socket, drag_start, SOCK_IN);
/* Distance to test overlapping of cursor on link. */
const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC;
@@ -283,7 +288,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
if (link->tosock == socket) {
/* Test if the cursor is near a link. */
float vec[4][2];
- node_link_bezier_handles(v2d, snode, link, vec);
+ node_link_bezier_handles(v2d, snode, *link, vec);
float data[NODE_LINK_RESOL * 2 + 2];
BKE_curve_forward_diff_bezier(
@@ -297,7 +302,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
float distance = dist_squared_to_line_segment_v2(cursor, l1, l2);
if (distance < cursor_link_touch_distance) {
link_to_pick = link;
- nldrag->last_picked_multi_input_socket_link = link_to_pick;
+ nldrag.last_picked_multi_input_socket_link = link_to_pick;
}
}
}
@@ -307,7 +312,7 @@ static void pick_input_link_by_link_intersect(const bContext *C,
* Not essential for the basic behavior, but can make interaction feel a bit better if
* the mouse moves to the right and loses the "selection." */
if (!link_to_pick) {
- bNodeLink *last_picked_link = nldrag->last_picked_multi_input_socket_link;
+ bNodeLink *last_picked_link = nldrag.last_picked_multi_input_socket_link;
if (last_picked_link) {
link_to_pick = last_picked_link;
}
@@ -316,27 +321,14 @@ static void pick_input_link_by_link_intersect(const bContext *C,
if (link_to_pick) {
/* Highlight is set here and cleared in the next iteration or if the operation finishes. */
link_to_pick->flag |= NODE_LINK_TEMP_HIGHLIGHT;
- ED_area_tag_redraw(CTX_wm_area(C));
+ ED_area_tag_redraw(CTX_wm_area(&C));
- if (!node_find_indicated_socket(snode, &node, &socket, cursor, SOCK_IN)) {
- pick_link(C, op, nldrag, snode, node, link_to_pick);
+ if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) {
+ pick_link(C, op, nldrag, *snode, node, *link_to_pick);
}
}
}
-static int sort_nodes_locx(const void *a, const void *b)
-{
- const bNodeListItem *nli1 = (const bNodeListItem *)a;
- const bNodeListItem *nli2 = (const bNodeListItem *)b;
- const bNode *node1 = nli1->node;
- const bNode *node2 = nli2->node;
-
- if (node1->locx > node2->locx) {
- return 1;
- }
- return 0;
-}
-
static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used)
{
if (nodeSocketIsHidden(sock)) {
@@ -433,14 +425,14 @@ static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, in
return nullptr;
}
-static bool snode_autoconnect_input(SpaceNode *snode,
+static bool snode_autoconnect_input(SpaceNode &snode,
bNode *node_fr,
bNodeSocket *sock_fr,
bNode *node_to,
bNodeSocket *sock_to,
int replace)
{
- bNodeTree *ntree = snode->edittree;
+ bNodeTree *ntree = snode.edittree;
/* then we can connect */
if (replace) {
@@ -452,105 +444,75 @@ static bool snode_autoconnect_input(SpaceNode *snode,
}
struct LinkAndPosition {
- struct bNodeLink *link;
- float multi_socket_position[2];
+ bNodeLink *link;
+ float2 multi_socket_position;
};
-static int compare_link_by_y_position(const void *a, const void *b)
-{
- const LinkAndPosition *link_and_position_a = *(const LinkAndPosition **)a;
- const LinkAndPosition *link_and_position_b = *(const LinkAndPosition **)b;
-
- BLI_assert(link_and_position_a->link->tosock == link_and_position_b->link->tosock);
- const float link_a_y = link_and_position_a->multi_socket_position[1];
- const float link_b_y = link_and_position_b->multi_socket_position[1];
- return link_a_y > link_b_y ? 1 : -1;
-}
-
-void sort_multi_input_socket_links(SpaceNode *snode,
- bNode *node,
+void sort_multi_input_socket_links(SpaceNode &snode,
+ bNode &node,
bNodeLink *drag_link,
- float cursor[2])
+ const float2 *cursor)
{
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (!(socket->flag & SOCK_MULTI_INPUT)) {
continue;
}
- /* The total is calculated in #node_update_nodetree, which runs before this draw step. */
- int total_inputs = socket->total_inputs + 1;
- struct LinkAndPosition **input_links = (LinkAndPosition **)MEM_malloc_arrayN(
- total_inputs, sizeof(LinkAndPosition *), __func__);
+ Vector<LinkAndPosition, 8> links;
- int index = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
if (link->tosock == socket) {
- struct LinkAndPosition *link_and_position = (LinkAndPosition *)MEM_callocN(
- sizeof(struct LinkAndPosition), __func__);
- link_and_position->link = link;
- node_link_calculate_multi_input_position(link->tosock->locx,
- link->tosock->locy,
- link->multi_input_socket_index,
- link->tosock->total_inputs,
- link_and_position->multi_socket_position);
- input_links[index] = link_and_position;
- index++;
+ links.append(
+ {link,
+ node_link_calculate_multi_input_position({link->tosock->locx, link->tosock->locy},
+ link->multi_input_socket_index,
+ link->tosock->total_inputs)});
}
}
if (drag_link) {
- LinkAndPosition *link_and_position = (LinkAndPosition *)MEM_callocN(sizeof(LinkAndPosition),
- __func__);
- link_and_position->link = drag_link;
- copy_v2_v2(link_and_position->multi_socket_position, cursor);
- input_links[index] = link_and_position;
- index++;
+ LinkAndPosition link_and_position{};
+ link_and_position.link = drag_link;
+ if (cursor) {
+ link_and_position.multi_socket_position = *cursor;
+ }
+ links.append(link_and_position);
}
- qsort(input_links, index, sizeof(bNodeLink *), compare_link_by_y_position);
+ std::sort(links.begin(), links.end(), [](const LinkAndPosition a, const LinkAndPosition b) {
+ return a.multi_socket_position.y < b.multi_socket_position.y;
+ });
- for (int i = 0; i < index; i++) {
- input_links[i]->link->multi_input_socket_index = i;
+ for (const int i : links.index_range()) {
+ links[i].link->multi_input_socket_index = i;
}
-
- for (int i = 0; i < index; i++) {
- if (input_links[i]) {
- MEM_freeN(input_links[i]);
- }
- }
- MEM_freeN(input_links);
}
}
-static void snode_autoconnect(Main *bmain,
- SpaceNode *snode,
+static void snode_autoconnect(Main &bmain,
+ SpaceNode &snode,
const bool allow_multiple,
const bool replace)
{
- bNodeTree *ntree = snode->edittree;
- ListBase *nodelist = (ListBase *)MEM_callocN(sizeof(ListBase), "items_list");
+ bNodeTree *ntree = snode.edittree;
+ Vector<bNode *> sorted_nodes;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_SELECT) {
- bNodeListItem *nli = (bNodeListItem *)MEM_mallocN(sizeof(bNodeListItem),
- "temporary node list item");
- nli->node = node;
- BLI_addtail(nodelist, nli);
+ sorted_nodes.append(node);
}
}
- /* sort nodes left to right */
- BLI_listbase_sort(nodelist, sort_nodes_locx);
+ /* Sort nodes left to right. */
+ std::sort(sorted_nodes.begin(), sorted_nodes.end(), [](const bNode *a, const bNode *b) {
+ return a->locx < b->locx;
+ });
int numlinks = 0;
- LISTBASE_FOREACH (bNodeListItem *, nli, nodelist) {
+ for (const int i : sorted_nodes.as_mutable_span().drop_back(1).index_range()) {
bool has_selected_inputs = false;
- if (nli->next == nullptr) {
- break;
- }
-
- bNode *node_fr = nli->node;
- bNode *node_to = nli->next->node;
+ bNode *node_fr = sorted_nodes[i];
+ bNode *node_to = sorted_nodes[i + 1];
/* corner case: input/output node aligned the wrong way around (T47729) */
if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) {
SWAP(bNode *, node_fr, node_to);
@@ -604,11 +566,8 @@ static void snode_autoconnect(Main *bmain,
}
if (numlinks > 0) {
- ntreeUpdateTree(bmain, ntree);
+ ntreeUpdateTree(&bmain, ntree);
}
-
- BLI_freelistN(nodelist);
- MEM_freeN(nodelist);
}
/** \} */
@@ -662,26 +621,26 @@ static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype
/**
* Find the socket to link to in a viewer node.
*/
-static bNodeSocket *node_link_viewer_get_socket(bNodeTree *ntree,
- bNode *viewer_node,
- bNodeSocket *src_socket)
+static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
+ bNode &viewer_node,
+ bNodeSocket &src_socket)
{
- if (viewer_node->type != GEO_NODE_VIEWER) {
+ if (viewer_node.type != GEO_NODE_VIEWER) {
/* In viewer nodes in the compositor, only the first input should be linked to. */
- return (bNodeSocket *)viewer_node->inputs.first;
+ return (bNodeSocket *)viewer_node.inputs.first;
}
/* For the geometry nodes viewer, find the socket with the correct type. */
- LISTBASE_FOREACH (bNodeSocket *, viewer_socket, &viewer_node->inputs) {
- if (viewer_socket->type == src_socket->type) {
+ LISTBASE_FOREACH (bNodeSocket *, viewer_socket, &viewer_node.inputs) {
+ if (viewer_socket->type == src_socket.type) {
if (viewer_socket->type == SOCK_GEOMETRY) {
return viewer_socket;
}
- NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node->storage;
+ NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node.storage;
const CustomDataType data_type = socket_type_to_custom_data_type(
- (eNodeSocketDatatype)src_socket->type);
+ (eNodeSocketDatatype)src_socket.type);
BLI_assert(data_type != CD_AUTO_FROM_NAME);
storage->data_type = data_type;
- nodeUpdate(ntree, viewer_node);
+ nodeUpdate(&ntree, &viewer_node);
return viewer_socket;
}
}
@@ -814,31 +773,31 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act
return nullptr;
}
-static int link_socket_to_viewer(const bContext *C,
+static int link_socket_to_viewer(const bContext &C,
bNode *viewer_bnode,
- bNode *bnode_to_view,
- bNodeSocket *bsocket_to_view)
+ bNode &bnode_to_view,
+ bNodeSocket &bsocket_to_view)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *btree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &btree = *snode.edittree;
if (viewer_bnode == nullptr) {
/* Create a new viewer node if none exists. */
- const int viewer_type = get_default_viewer_type(C);
+ const int viewer_type = get_default_viewer_type(&C);
viewer_bnode = node_add_node(
- C, nullptr, viewer_type, bsocket_to_view->locx + 100, bsocket_to_view->locy);
+ C, nullptr, viewer_type, bsocket_to_view.locx + 100, bsocket_to_view.locy);
if (viewer_bnode == nullptr) {
return OPERATOR_CANCELLED;
}
}
- bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, viewer_bnode, bsocket_to_view);
+ bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, *viewer_bnode, bsocket_to_view);
if (viewer_bsocket == nullptr) {
return OPERATOR_CANCELLED;
}
bNodeLink *link_to_change = nullptr;
- LISTBASE_FOREACH (bNodeLink *, link, &btree->links) {
+ LISTBASE_FOREACH (bNodeLink *, link, &btree.links) {
if (link->tosock == viewer_bsocket) {
link_to_change = link;
break;
@@ -846,38 +805,34 @@ static int link_socket_to_viewer(const bContext *C,
}
if (link_to_change == nullptr) {
- nodeAddLink(btree, bnode_to_view, bsocket_to_view, viewer_bnode, viewer_bsocket);
+ nodeAddLink(&btree, &bnode_to_view, &bsocket_to_view, viewer_bnode, viewer_bsocket);
}
else {
- link_to_change->fromnode = bnode_to_view;
- link_to_change->fromsock = bsocket_to_view;
- btree->update |= NTREE_UPDATE_LINKS;
+ link_to_change->fromnode = &bnode_to_view;
+ link_to_change->fromsock = &bsocket_to_view;
+ btree.update |= NTREE_UPDATE_LINKS;
}
- remove_links_to_unavailable_viewer_sockets(*btree, *viewer_bnode);
+ remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode);
- if (btree->type == NTREE_GEOMETRY) {
- ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(C), snode, viewer_bnode);
+ if (btree.type == NTREE_GEOMETRY) {
+ ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode);
}
- ntreeUpdateTree(CTX_data_main(C), btree);
+ ntreeUpdateTree(CTX_data_main(&C), &btree);
snode_update(snode, viewer_bnode);
- DEG_id_tag_update(&btree->id, 0);
+ DEG_id_tag_update(&btree.id, 0);
return OPERATOR_FINISHED;
}
-static int node_link_viewer(const bContext *C, bNode *bnode_to_view)
+static int node_link_viewer(const bContext &C, bNode &bnode_to_view)
{
- if (bnode_to_view == nullptr) {
- return OPERATOR_CANCELLED;
- }
-
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *btree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree *btree = snode.edittree;
const NodeTreeRef tree{btree};
- const NodeRef &node_to_view = *tree.find_node(*bnode_to_view);
+ const NodeRef &node_to_view = *tree.find_node(bnode_to_view);
const NodeRef *active_viewer_node = get_existing_viewer(tree);
const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node,
@@ -886,7 +841,7 @@ static int node_link_viewer(const bContext *C, bNode *bnode_to_view)
return OPERATOR_FINISHED;
}
- bNodeSocket *bsocket_to_view = socket_to_view->bsocket();
+ bNodeSocket &bsocket_to_view = *socket_to_view->bsocket();
bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr;
return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
}
@@ -895,8 +850,8 @@ static int node_link_viewer(const bContext *C, bNode *bnode_to_view)
static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNode *node = nodeGetActive(snode->edittree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNode *node = nodeGetActive(snode.edittree);
if (!node) {
return OPERATOR_CANCELLED;
@@ -904,11 +859,11 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (blender::ed::nodes::viewer_linking::node_link_viewer(C, node) == OPERATOR_CANCELLED) {
+ if (blender::ed::nodes::viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) {
return OPERATOR_CANCELLED;
}
- snode_notify(C, snode);
+ snode_notify(*C, snode);
return OPERATOR_FINISHED;
}
@@ -943,6 +898,83 @@ void NODE_OT_link_viewer(wmOperatorType *ot)
/** \name Add Link Operator
* \{ */
+/**
+ * Check if any of the dragged links are connected to a socket on the side that they are dragged
+ * from.
+ */
+static bool dragged_links_are_detached(const bNodeLinkDrag &nldrag)
+{
+ if (nldrag.in_out == SOCK_OUT) {
+ for (const bNodeLink *link : nldrag.links) {
+ if (link->tonode && link->tosock) {
+ return false;
+ }
+ }
+ }
+ else {
+ for (const bNodeLink *link : nldrag.links) {
+ if (link->fromnode && link->fromsock) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool should_create_drag_link_search_menu(const bNodeTree &node_tree,
+ const bNodeLinkDrag &nldrag)
+{
+ /* Custom node trees aren't supported yet. */
+ if (node_tree.type == NTREE_CUSTOM) {
+ return false;
+ }
+ /* Only create the search menu when the drag has not already connected the links to a socket. */
+ if (!dragged_links_are_detached(nldrag)) {
+ return false;
+ }
+ /* Don't create the search menu if the drag is disconnecting a link from an input node. */
+ if (nldrag.start_socket->in_out == SOCK_IN && nldrag.start_link_count > 0) {
+ return false;
+ }
+ /* Don't allow a drag from the "new socket" of a group input node. Handling these
+ * properly in node callbacks increases the complexity too much for now. */
+ if (ELEM(nldrag.start_node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ if (nldrag.start_socket->type == SOCK_CUSTOM) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void draw_draglink_tooltip(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
+{
+ bNodeLinkDrag *nldrag = static_cast<bNodeLinkDrag *>(arg);
+
+ const uchar text_col[4] = {255, 255, 255, 255};
+ const int padding = 4 * UI_DPI_FAC;
+ const float x = nldrag->in_out == SOCK_IN ? nldrag->cursor[0] - 3.3f * padding :
+ nldrag->cursor[0];
+ const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC;
+
+ UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false);
+}
+
+static void draw_draglink_tooltip_activate(const ARegion &region, bNodeLinkDrag &nldrag)
+{
+ if (nldrag.draw_handle == nullptr) {
+ nldrag.draw_handle = ED_region_draw_cb_activate(
+ region.type, draw_draglink_tooltip, &nldrag, REGION_DRAW_POST_PIXEL);
+ }
+}
+
+static void draw_draglink_tooltip_deactivate(const ARegion &region, bNodeLinkDrag &nldrag)
+{
+ if (nldrag.draw_handle) {
+ ED_region_draw_cb_exit(region.type, nldrag.draw_handle);
+ nldrag.draw_handle = nullptr;
+ }
+}
+
static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
{
char header[UI_MAX_DRAW_STR];
@@ -951,48 +983,49 @@ static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
ED_workspace_status_text(C, header);
}
-static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
+static int node_count_links(const bNodeTree &ntree, const bNodeSocket &socket)
{
int count = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- if (ELEM(socket, link->fromsock, link->tosock)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (ELEM(&socket, link->fromsock, link->tosock)) {
count++;
}
}
return count;
}
-static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
+static void node_remove_extra_links(SpaceNode &snode, bNodeLink &link)
{
- bNodeTree *ntree = snode->edittree;
- bNodeSocket *from = link->fromsock, *to = link->tosock;
+ bNodeTree &ntree = *snode.edittree;
+ bNodeSocket &from = *link.fromsock;
+ bNodeSocket &to = *link.tosock;
int to_count = node_count_links(ntree, to);
int from_count = node_count_links(ntree, from);
- int to_link_limit = nodeSocketLinkLimit(to);
- int from_link_limit = nodeSocketLinkLimit(from);
+ int to_link_limit = nodeSocketLinkLimit(&to);
+ int from_link_limit = nodeSocketLinkLimit(&from);
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, tlink, &ntree->links) {
- if (tlink == link) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, tlink, &ntree.links) {
+ if (tlink == &link) {
continue;
}
- if (tlink && tlink->fromsock == from) {
+ if (tlink && tlink->fromsock == &from) {
if (from_count > from_link_limit) {
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
from_count--;
}
}
- if (tlink && tlink->tosock == to) {
+ if (tlink && tlink->tosock == &to) {
if (to_count > to_link_limit) {
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
to_count--;
}
- else if (tlink->fromsock == from) {
+ else if (tlink->fromsock == &from) {
/* Also remove link if it comes from the same output. */
- nodeRemLink(ntree, tlink);
+ nodeRemLink(&ntree, tlink);
tlink = nullptr;
to_count--;
from_count--;
@@ -1001,21 +1034,18 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
}
}
-static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
+static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ Main *bmain = CTX_data_main(&C);
+ ARegion &region = *CTX_wm_region(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &ntree = *snode.edittree;
+ bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
bool do_tag_update = false;
- /* View will be reset if no links connect. */
- bool reset_view = true;
/* avoid updates while applying links */
- ntree->is_updating = true;
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ ntree.is_updating = true;
+ for (bNodeLink *link : nldrag->links) {
/* See note below, but basically TEST flag means that the link
* was connected to output (or to a node which affects the
* output).
@@ -1029,63 +1059,59 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
* let nodes perform special link insertion handling
*/
if (link->fromnode->typeinfo->insert_link) {
- link->fromnode->typeinfo->insert_link(ntree, link->fromnode, link);
+ link->fromnode->typeinfo->insert_link(&ntree, link->fromnode, link);
}
if (link->tonode->typeinfo->insert_link) {
- link->tonode->typeinfo->insert_link(ntree, link->tonode, link);
+ link->tonode->typeinfo->insert_link(&ntree, link->tonode, link);
}
/* add link to the node tree */
- BLI_addtail(&ntree->links, link);
+ BLI_addtail(&ntree.links, link);
- ntree->update |= NTREE_UPDATE_LINKS;
+ ntree.update |= NTREE_UPDATE_LINKS;
/* tag tonode for update */
link->tonode->update |= NODE_UPDATE;
/* we might need to remove a link */
- node_remove_extra_links(snode, link);
+ node_remove_extra_links(snode, *link);
if (link->tonode) {
- do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, link->tonode));
+ do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, ntree, *link->tonode));
}
-
- reset_view = false;
}
else {
- nodeRemLink(ntree, link);
+ nodeRemLink(&ntree, link);
}
}
- ntree->is_updating = false;
+ ntree.is_updating = false;
- ntreeUpdateTree(bmain, ntree);
+ ntreeUpdateTree(bmain, &ntree);
snode_notify(C, snode);
if (do_tag_update) {
snode_dag_update(C, snode);
}
- if (reset_view) {
- UI_view2d_edge_pan_cancel(C, &nldrag->pan_data);
- }
+ /* Ensure draglink tooltip is disabled. */
+ draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag);
+
+ ED_workspace_status_text(&C, nullptr);
+ ED_region_tag_redraw(&region);
+ clear_picking_highlight(&snode.edittree->links);
- BLI_remlink(&snode->runtime->linkdrag, nldrag);
- /* links->data pointers are either held by the tree or freed already */
- BLI_freelistN(&nldrag->links);
- MEM_freeN(nldrag);
+ snode.runtime->linkdrag.reset();
}
-static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
+static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cursor)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
if (nldrag->in_out == SOCK_OUT) {
bNode *tnode;
bNodeSocket *tsock = nullptr;
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
/* skip if socket is on the same node as the fromsock */
if (tnode && link->fromnode == tnode) {
continue;
@@ -1093,7 +1119,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
/* Skip if tsock is already linked with this output. */
bNodeLink *existing_link_connected_to_fromsock = nullptr;
- LISTBASE_FOREACH (bNodeLink *, existing_link, &snode->edittree->links) {
+ LISTBASE_FOREACH (bNodeLink *, existing_link, &snode.edittree->links) {
if (existing_link->fromsock == link->fromsock && existing_link->tosock == tsock) {
existing_link_connected_to_fromsock = existing_link;
break;
@@ -1110,16 +1136,15 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
continue;
}
if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) {
- sort_multi_input_socket_links(snode, tnode, link, cursor);
+ sort_multi_input_socket_links(snode, *tnode, link, &cursor);
}
}
}
else {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
+ for (bNodeLink *link : nldrag->links) {
if (nldrag->last_node_hovered_while_dragging_a_link) {
sort_multi_input_socket_links(
- snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, cursor);
+ snode, *nldrag->last_node_hovered_while_dragging_a_link, nullptr, &cursor);
}
link->tonode = nullptr;
link->tosock = nullptr;
@@ -1130,9 +1155,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
bNode *tnode;
bNodeSocket *tsock = nullptr;
if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
/* skip if this is already the target socket */
if (link->fromsock == tsock) {
continue;
@@ -1148,9 +1171,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
}
}
else {
- LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
- bNodeLink *link = (bNodeLink *)linkdata->data;
-
+ for (bNodeLink *link : nldrag->links) {
link->fromnode = nullptr;
link->fromsock = nullptr;
}
@@ -1163,67 +1184,93 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
+ SpaceNode &snode = *CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- float cursor[2];
UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event);
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ float2 cursor;
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor.x, &cursor.y);
+ nldrag->cursor[0] = event->mval[0];
+ nldrag->cursor[1] = event->mval[1];
switch (event->type) {
case MOUSEMOVE:
if (nldrag->from_multi_input_socket && !RNA_boolean_get(op->ptr, "has_link_picked")) {
- pick_input_link_by_link_intersect(C, op, nldrag, cursor);
+ pick_input_link_by_link_intersect(*C, *op, *nldrag, cursor);
}
else {
- node_link_find_socket(C, op, cursor);
+ node_link_find_socket(*C, *op, cursor);
node_link_update_header(C, nldrag);
ED_region_tag_redraw(region);
}
- break;
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ draw_draglink_tooltip_activate(*region, *nldrag);
+ }
+ else {
+ draw_draglink_tooltip_deactivate(*region, *nldrag);
+ }
+ break;
case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* Add a search menu for compatible sockets if the drag released on empty space. */
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ bNodeLink &link = *nldrag->links.first();
+ if (nldrag->in_out == SOCK_OUT) {
+ blender::ed::space_node::invoke_node_link_drag_add_menu(
+ *C, *link.fromnode, *link.fromsock, cursor);
+ }
+ else {
+ blender::ed::space_node::invoke_node_link_drag_add_menu(
+ *C, *link.tonode, *link.tosock, cursor);
+ }
+ }
+
+ /* Finish link. */
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
+ break;
case RIGHTMOUSE:
case MIDDLEMOUSE: {
if (event->val == KM_RELEASE) {
- node_link_exit(C, op, true);
-
- ED_workspace_status_text(C, nullptr);
- ED_region_tag_redraw(region);
- SpaceNode *snode = CTX_wm_space_node(C);
- clear_picking_highlight(&snode->edittree->links);
+ node_link_exit(*C, *op, true);
return OPERATOR_FINISHED;
}
break;
}
+ case EVT_ESCKEY: {
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
}
return OPERATOR_RUNNING_MODAL;
}
-/* return 1 when socket clicked */
-static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor[2], bool detach)
+static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
+ SpaceNode &snode,
+ float2 cursor,
+ const bool detach)
{
- bNodeLinkDrag *nldrag = nullptr;
-
/* output indicated? */
bNode *node;
bNodeSocket *sock;
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
- nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
-
- const int num_links = nodeCountSocketLinks(snode->edittree, sock);
+ std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
+ nldrag->start_node = node;
+ nldrag->start_socket = sock;
+ nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
int link_limit = nodeSocketLinkLimit(sock);
- if (num_links > 0 && (num_links >= link_limit || detach)) {
+ if (nldrag->start_link_count > 0 && (nldrag->start_link_count >= link_limit || detach)) {
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* detach current links and store them in the operator data */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
if (link->fromsock == sock) {
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
*oplink = *link;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
@@ -1236,12 +1283,12 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
* using TEST flag.
*/
oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, link->tonode)) {
+ if (node_connected_to_output(bmain, *snode.edittree, *link->tonode)) {
oplink->flag |= NODE_LINK_TEST;
}
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link);
+ nldrag->links.append(oplink);
+ nodeRemLink(snode.edittree, link);
}
}
}
@@ -1249,23 +1296,25 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* create a new link */
- LinkData *linkdata = create_drag_link(bmain, snode, node, sock);
-
- BLI_addtail(&nldrag->links, linkdata);
+ nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
}
+ return nldrag;
}
+
/* or an input? */
- else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
- nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
+ if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
+ std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
nldrag->last_node_hovered_while_dragging_a_link = node;
+ nldrag->start_node = node;
+ nldrag->start_socket = sock;
- const int num_links = nodeCountSocketLinks(snode->edittree, sock);
- if (num_links > 0) {
+ nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock);
+ if (nldrag->start_link_count > 0) {
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* detach current links and store them in the operator data */
bNodeLink *link_to_pick;
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
if (link->tosock == sock) {
if (sock->flag & SOCK_MULTI_INPUT) {
nldrag->from_multi_input_socket = true;
@@ -1275,20 +1324,18 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
}
if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) {
- LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data");
bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
- linkdata->data = oplink;
*oplink = *link_to_pick;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, snode->edittree, link_to_pick->tonode)) {
+ if (node_connected_to_output(bmain, *snode.edittree, *link_to_pick->tonode)) {
oplink->flag |= NODE_LINK_TEST;
}
- BLI_addtail(&nldrag->links, linkdata);
- nodeRemLink(snode->edittree, link_to_pick);
+ nldrag->links.append(oplink);
+ nodeRemLink(snode.edittree, link_to_pick);
/* send changed event to original link->tonode */
if (node) {
@@ -1300,37 +1347,40 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* create a new link */
- LinkData *linkdata = create_drag_link(bmain, snode, node, sock);
-
- BLI_addtail(&nldrag->links, linkdata);
+ nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
}
+ return nldrag;
}
- return nldrag;
+ return {};
}
static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
bool detach = RNA_boolean_get(op->ptr, "detach");
- float cursor[2];
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
+ float2 cursor;
+ UI_view2d_region_to_view(&region.v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
RNA_float_set_array(op->ptr, "drag_start", cursor);
RNA_boolean_set(op->ptr, "has_link_picked", false);
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach);
+ std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach);
if (nldrag) {
UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
- op->customdata = nldrag;
- BLI_addtail(&snode->runtime->linkdrag, nldrag);
+ /* Add "+" icon when the link is dragged in empty space. */
+ if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) {
+ draw_draglink_tooltip_activate(*CTX_wm_region(C), *nldrag);
+ }
+ snode.runtime->linkdrag = std::move(nldrag);
+ op->customdata = snode.runtime->linkdrag.get();
/* add modal handler */
WM_event_add_modal_handler(C, op);
@@ -1345,12 +1395,10 @@ static void node_link_cancel(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata;
- BLI_remlink(&snode->runtime->linkdrag, nldrag);
-
UI_view2d_edge_pan_cancel(C, &nldrag->pan_data);
- BLI_freelistN(&nldrag->links);
- MEM_freeN(nldrag);
+ snode->runtime->linkdrag.reset();
+
clear_picking_highlight(&snode->edittree->links);
}
@@ -1413,11 +1461,11 @@ void NODE_OT_link(wmOperatorType *ot)
/* makes a link between selected output and input sockets */
static int node_make_link_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
const bool replace = RNA_boolean_get(op->ptr, "replace");
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
snode_autoconnect(bmain, snode, true, replace);
@@ -1425,9 +1473,9 @@ static int node_make_link_exec(bContext *C, wmOperator *op)
node_deselect_all_input_sockets(snode, false);
node_deselect_all_output_sockets(snode, false);
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ ntreeUpdateTree(CTX_data_main(C), snode.edittree);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
return OPERATOR_FINISHED;
}
@@ -1457,7 +1505,7 @@ void NODE_OT_link_make(wmOperatorType *ot)
/** \name Node Link Intersect
* \{ */
-static bool node_links_intersect(bNodeLink *link, const float mcoords[][2], int tot)
+static bool node_links_intersect(bNodeLink &link, const float mcoords[][2], int tot)
{
float coord_array[NODE_LINK_RESOL + 1][2];
@@ -1481,9 +1529,9 @@ static bool node_links_intersect(bNodeLink *link, const float mcoords[][2], int
static int cut_links_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
bool do_tag_update = false;
int i = 0;
@@ -1493,7 +1541,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -1504,36 +1552,36 @@ static int cut_links_exec(bContext *C, wmOperator *op)
if (i > 1) {
bool found = false;
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
- if (node_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(*link, mcoords, i)) {
if (found == false) {
/* TODO(sergey): Why did we kill jobs twice? */
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
found = true;
}
do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, snode->edittree, link->tonode));
+ node_connected_to_output(bmain, *snode.edittree, *link->tonode));
snode_update(snode, link->tonode);
bNode *to_node = link->tonode;
- nodeRemLink(snode->edittree, link);
- sort_multi_input_socket_links(snode, to_node, nullptr, nullptr);
+ nodeRemLink(snode.edittree, link);
+ sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr);
}
}
if (found) {
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
+ ntreeUpdateTree(CTX_data_main(C), snode.edittree);
+ snode_notify(*C, snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, snode);
}
return OPERATOR_FINISHED;
@@ -1578,9 +1626,9 @@ void NODE_OT_links_cut(wmOperatorType *ot)
static int mute_links_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
bool do_tag_update = false;
int i = 0;
@@ -1590,7 +1638,7 @@ static int mute_links_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&itemptr, "loc", loc);
UI_view2d_region_to_view(
- &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ &region.v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
i++;
if (i >= 256) {
break;
@@ -1599,16 +1647,16 @@ static int mute_links_exec(bContext *C, wmOperator *op)
RNA_END;
if (i > 1) {
- ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
/* Count intersected links and clear test flag. */
int tot = 0;
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
link->flag &= ~NODE_LINK_TEST;
- if (node_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(*link, mcoords, i)) {
tot++;
}
}
@@ -1617,32 +1665,32 @@ static int mute_links_exec(bContext *C, wmOperator *op)
}
/* Mute links. */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link) || (link->flag & NODE_LINK_TEST)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link) || (link->flag & NODE_LINK_TEST)) {
continue;
}
- if (node_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(*link, mcoords, i)) {
do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, snode->edittree, link->tonode));
+ node_connected_to_output(bmain, *snode.edittree, *link->tonode));
snode_update(snode, link->tonode);
- nodeMuteLinkToggle(snode->edittree, link);
+ nodeMuteLinkToggle(snode.edittree, link);
}
}
/* Clear remaining test flags. */
- LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
continue;
}
link->flag &= ~NODE_LINK_TEST;
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
- snode_notify(C, snode);
+ ntreeUpdateTree(CTX_data_main(C), snode.edittree);
+ snode_notify(*C, snode);
if (do_tag_update) {
- snode_dag_update(C, snode);
+ snode_dag_update(*C, snode);
}
return OPERATOR_FINISHED;
@@ -1684,21 +1732,21 @@ void NODE_OT_links_mute(wmOperatorType *ot)
static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & SELECT) {
- nodeInternalRelink(ntree, node);
+ nodeInternalRelink(&ntree, node);
}
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ntreeUpdateTree(CTX_data_main(C), &ntree);
- snode_notify(C, snode);
- snode_dag_update(C, snode);
+ snode_notify(*C, snode);
+ snode_dag_update(*C, snode);
return OPERATOR_FINISHED;
}
@@ -1805,12 +1853,12 @@ static void node_join_attach_recursive(bNode *node, bNode *frame)
static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
/* XXX save selection: node_add_node call below sets the new frame as single
* active+selected node */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_SELECT) {
node->flag |= NODE_TEST;
}
@@ -1819,27 +1867,27 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- bNode *frame = node_add_node(C, nullptr, NODE_FRAME, 0.0f, 0.0f);
+ bNode *frame = node_add_node(*C, nullptr, NODE_FRAME, 0.0f, 0.0f);
/* reset tags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
node->done = 0;
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->done & NODE_JOIN_DONE)) {
node_join_attach_recursive(node, frame);
}
}
/* restore selection */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_TEST) {
node->flag |= NODE_SELECT;
}
}
- ED_node_sort(ntree);
+ ED_node_sort(&ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2073,7 +2121,7 @@ static bool ed_node_link_conditions(ScrArea *area,
/* test node for links */
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
continue;
}
@@ -2086,7 +2134,6 @@ static bool ed_node_link_conditions(ScrArea *area,
return true;
}
-/* test == 0, clear all intersect flags */
void ED_node_link_intersect_test(ScrArea *area, int test)
{
bNode *select;
@@ -2112,11 +2159,11 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
float coord_array[NODE_LINK_RESOL + 1][2];
- if (node_link_is_hidden_or_dimmed(&region->v2d, link)) {
+ if (node_link_is_hidden_or_dimmed(region->v2d, *link)) {
continue;
}
- if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) {
+ if (node_link_bezier_points(nullptr, nullptr, *link, coord_array, NODE_LINK_RESOL)) {
float dist = FLT_MAX;
/* loop over link coords to find shortest dist to
@@ -2158,18 +2205,19 @@ static int get_main_socket_priority(const bNodeSocket *socket)
{
switch ((eNodeSocketDatatype)socket->type) {
case __SOCK_MESH:
- case SOCK_CUSTOM:
return -1;
- case SOCK_BOOLEAN:
+ case SOCK_CUSTOM:
return 0;
- case SOCK_INT:
+ case SOCK_BOOLEAN:
return 1;
- case SOCK_FLOAT:
+ case SOCK_INT:
return 2;
- case SOCK_VECTOR:
+ case SOCK_FLOAT:
return 3;
- case SOCK_RGBA:
+ case SOCK_VECTOR:
return 4;
+ case SOCK_RGBA:
+ return 5;
case SOCK_STRING:
case SOCK_SHADER:
case SOCK_OBJECT:
@@ -2178,7 +2226,7 @@ static int get_main_socket_priority(const bNodeSocket *socket)
case SOCK_COLLECTION:
case SOCK_TEXTURE:
case SOCK_MATERIAL:
- return 5;
+ return 6;
}
return -1;
}
@@ -2251,19 +2299,19 @@ static bool node_parents_offset_flag_enable_cb(bNode *parent, void *UNUSED(userd
return true;
}
-static void node_offset_apply(bNode *node, const float offset_x)
+static void node_offset_apply(bNode &node, const float offset_x)
{
/* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
- if ((node->flag & NODE_TEST) == 0) {
- node->anim_init_locx = node->locx;
- node->anim_ofsx = (offset_x / UI_DPI_FAC);
- node->flag |= NODE_TEST;
+ if ((node.flag & NODE_TEST) == 0) {
+ node.anim_init_locx = node.locx;
+ node.anim_ofsx = (offset_x / UI_DPI_FAC);
+ node.flag |= NODE_TEST;
}
}
static void node_parent_offset_apply(NodeInsertOfsData *data, bNode *parent, const float offset_x)
{
- node_offset_apply(parent, offset_x);
+ node_offset_apply(*parent, offset_x);
/* Flag all children as offset to prevent them from being offset
* separately (they've already moved with the parent). */
@@ -2290,10 +2338,10 @@ static bool node_link_insert_offset_frame_chain_cb(bNode *fromnode,
bNode *ofs_node = reversed ? fromnode : tonode;
if (ofs_node->parent && ofs_node->parent != data->insert_parent) {
- node_offset_apply(ofs_node->parent, data->offset_x);
+ node_offset_apply(*ofs_node->parent, data->offset_x);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
return true;
@@ -2332,7 +2380,7 @@ static bool node_link_insert_offset_chain_cb(bNode *fromnode,
node_link_insert_offset_frame_chains(data->ntree, ofs_node->parent, data, reversed);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
if (nodeIsChildOf(data->insert_parent, ofs_node) == false) {
@@ -2341,10 +2389,10 @@ static bool node_link_insert_offset_chain_cb(bNode *fromnode,
}
else if (ofs_node->parent) {
bNode *node = nodeFindRootParent(ofs_node);
- node_offset_apply(node, data->offset_x);
+ node_offset_apply(*node, data->offset_x);
}
else {
- node_offset_apply(ofs_node, data->offset_x);
+ node_offset_apply(*ofs_node, data->offset_x);
}
return true;
@@ -2356,9 +2404,9 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
const bool right_alignment)
{
bNodeTree *ntree = iofsd->ntree;
- bNode *insert = iofsd->insert;
+ bNode &insert = *iofsd->insert;
bNode *prev = iofsd->prev, *next = iofsd->next;
- bNode *init_parent = insert->parent; /* store old insert->parent for restoring later */
+ bNode *init_parent = insert.parent; /* store old insert.parent for restoring later */
const float min_margin = U.node_margin * UI_DPI_FAC;
const float width = NODE_WIDTH(insert);
@@ -2369,20 +2417,20 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
/* NODE_TEST will be used later, so disable for all nodes */
ntreeNodeFlagSet(ntree, NODE_TEST, false);
- /* `insert->totr` isn't updated yet,
+ /* `insert.totr` isn't updated yet,
* so `totr_insert` is used to get the correct world-space coords. */
rctf totr_insert;
- node_to_updated_rect(insert, &totr_insert);
+ node_to_updated_rect(insert, totr_insert);
/* frame attachment wasn't handled yet
* so we search the frame that the node will be attached to later */
- insert->parent = node_find_frame_to_attach(region, ntree, mouse_xy);
+ insert.parent = node_find_frame_to_attach(region, ntree, mouse_xy);
/* this makes sure nodes are also correctly offset when inserting a node on top of a frame
* without actually making it a part of the frame (because mouse isn't intersecting it)
* - logic here is similar to node_find_frame_to_attach */
- if (!insert->parent ||
- (prev->parent && (prev->parent == next->parent) && (prev->parent != insert->parent))) {
+ if (!insert.parent ||
+ (prev->parent && (prev->parent == next->parent) && (prev->parent != insert.parent))) {
bNode *frame;
rctf totr_frame;
@@ -2394,15 +2442,15 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
}
/* for some reason frame y coords aren't correct yet */
- node_to_updated_rect(frame, &totr_frame);
+ node_to_updated_rect(*frame, totr_frame);
if (BLI_rctf_isect_x(&totr_frame, totr_insert.xmin) &&
BLI_rctf_isect_x(&totr_frame, totr_insert.xmax)) {
if (BLI_rctf_isect_y(&totr_frame, totr_insert.ymin) ||
BLI_rctf_isect_y(&totr_frame, totr_insert.ymax)) {
- /* frame isn't insert->parent actually, but this is needed to make offsetting
+ /* frame isn't insert.parent actually, but this is needed to make offsetting
* nodes work correctly for above checked cases (it is restored later) */
- insert->parent = frame;
+ insert.parent = frame;
break;
}
}
@@ -2432,12 +2480,12 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
const float addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
if (needs_alignment) {
bNode *offs_node = right_alignment ? next : prev;
- if (!offs_node->parent || offs_node->parent == insert->parent ||
- nodeIsChildOf(offs_node->parent, insert)) {
- node_offset_apply(offs_node, addval);
+ if (!offs_node->parent || offs_node->parent == insert.parent ||
+ nodeIsChildOf(offs_node->parent, &insert)) {
+ node_offset_apply(*offs_node, addval);
}
- else if (!insert->parent && offs_node->parent) {
- node_offset_apply(nodeFindRootParent(offs_node), addval);
+ else if (!insert.parent && offs_node->parent) {
+ node_offset_apply(*nodeFindRootParent(offs_node), addval);
}
margin = addval;
}
@@ -2449,11 +2497,11 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
}
if (needs_alignment) {
- iofsd->insert_parent = insert->parent;
+ iofsd->insert_parent = insert.parent;
iofsd->offset_x = margin;
/* flag all parents of insert as offset to prevent them from being offset */
- nodeParentsIter(insert, node_parents_offset_flag_enable_cb, nullptr);
+ nodeParentsIter(&insert, node_parents_offset_flag_enable_cb, nullptr);
/* iterate over entire chain and apply offsets */
nodeChainIter(ntree,
right_alignment ? next : prev,
@@ -2462,7 +2510,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
!right_alignment);
}
- insert->parent = init_parent;
+ insert.parent = init_parent;
}
/**
@@ -2567,7 +2615,6 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
/** \name Note Link Insert
* \{ */
-/* assumes link with NODE_LINKFLAG_HILITE set */
void ED_node_link_insert(Main *bmain, ScrArea *area)
{
bNode *select;
@@ -2594,7 +2641,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
link->tonode = select;
link->tosock = best_input;
- node_remove_extra_links(snode, link);
+ node_remove_extra_links(*snode, *link);
link->flag &= ~NODE_LINKFLAG_HILITE;
bNodeLink *new_link = nodeAddLink(snode->edittree, select, best_output, node, sockto);
@@ -2617,7 +2664,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
}
ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */
- snode_update(snode, select);
+ snode_update(*snode, select);
ED_node_tag_update_id((ID *)snode->edittree);
ED_node_tag_update_id(snode->id);
}
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index 3c7b404547b..334ca1f76ee 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -29,7 +29,6 @@
#include "BLI_lasso_2d.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_string_search.h"
@@ -63,6 +62,8 @@
#include "node_intern.hh" /* own include */
+using blender::float2;
+
/**
* Function to detect if there is a visible view3d that uses workbench in texture mode.
* This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in
@@ -98,43 +99,43 @@ static bool has_workbench_in_texture_color(const wmWindowManager *wm,
/** \name Public Node Selection API
* \{ */
-static bNode *node_under_mouse_select(bNodeTree *ntree, int mx, int my)
+static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my)
{
- bNode *node;
-
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (node->typeinfo->select_area_func) {
- if (node->typeinfo->select_area_func(node, mx, my)) {
- return node;
- }
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
+ if (BLI_rctf_isect_pt(&node->totr, mx, my)) {
+ return node;
}
}
return nullptr;
}
-static bNode *node_under_mouse_tweak(bNodeTree *ntree, int mx, int my)
+static bNode *node_under_mouse_tweak(bNodeTree &ntree, const float2 &mouse)
{
- bNode *node;
-
- for (node = (bNode *)ntree->nodes.last; node; node = node->prev) {
- if (node->typeinfo->tweak_area_func) {
- if (node->typeinfo->tweak_area_func(node, mx, my)) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
+ if (node->type == NODE_REROUTE) {
+ bNodeSocket *socket = (bNodeSocket *)node->inputs.first;
+ const float2 location{socket->locx, socket->locy};
+ if (float2::distance(mouse, location) < 24.0f) {
return node;
}
}
+ if (BLI_rctf_isect_pt(&node->totr, mouse.x, mouse.y)) {
+ return node;
+ }
}
return nullptr;
}
-static bool is_position_over_node_or_socket(SpaceNode *snode, float mouse[2])
+static bool is_position_over_node_or_socket(SpaceNode &snode, const float2 &mouse)
{
- if (node_under_mouse_tweak(snode->edittree, mouse[0], mouse[1])) {
+ if (node_under_mouse_tweak(*snode.edittree, mouse)) {
return true;
}
bNode *node;
bNodeSocket *sock;
- if (node_find_indicated_socket(snode, &node, &sock, mouse, SOCK_IN | SOCK_OUT)) {
+ if (node_find_indicated_socket(
+ snode, &node, &sock, mouse, (eNodeSocketInOut)(SOCK_IN | SOCK_OUT))) {
return true;
}
@@ -145,9 +146,9 @@ static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
- float mouse[2];
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mouse[0], &mouse[1]);
- return is_position_over_node_or_socket(snode, mouse);
+ float2 mouse;
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mouse.x, &mouse.y);
+ return is_position_over_node_or_socket(*snode, mouse);
}
static void node_toggle(bNode *node)
@@ -155,9 +156,9 @@ static void node_toggle(bNode *node)
nodeSetSelected(node, !(node->flag & SELECT));
}
-void node_socket_select(bNode *node, bNodeSocket *sock)
+void node_socket_select(bNode *node, bNodeSocket &sock)
{
- sock->flag |= SELECT;
+ sock.flag |= SELECT;
/* select node too */
if (node) {
@@ -165,22 +166,22 @@ void node_socket_select(bNode *node, bNodeSocket *sock)
}
}
-void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_node)
+void node_socket_deselect(bNode *node, bNodeSocket &sock, const bool deselect_node)
{
- sock->flag &= ~SELECT;
+ sock.flag &= ~SELECT;
if (node && deselect_node) {
bool sel = false;
/* if no selected sockets remain, also deselect the node */
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, input, &node->inputs) {
+ if (input->flag & SELECT) {
sel = true;
break;
}
}
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, output, &node->outputs) {
+ if (output->flag & SELECT) {
sel = true;
break;
}
@@ -192,9 +193,9 @@ void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_no
}
}
-static void node_socket_toggle(bNode *node, bNodeSocket *sock, int deselect_node)
+static void node_socket_toggle(bNode *node, bNodeSocket &sock, bool deselect_node)
{
- if (sock->flag & SELECT) {
+ if (sock.flag & SELECT) {
node_socket_deselect(node, sock, deselect_node);
}
else {
@@ -202,38 +203,32 @@ static void node_socket_toggle(bNode *node, bNodeSocket *sock, int deselect_node
}
}
-/* no undo here! */
-void node_deselect_all(SpaceNode *snode)
+void node_deselect_all(SpaceNode &snode)
{
- bNode *node;
-
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
nodeSetSelected(node, false);
}
}
-void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes)
+void node_deselect_all_input_sockets(SpaceNode &snode, const bool deselect_nodes)
{
- bNode *node;
- bNodeSocket *sock;
-
/* XXX not calling node_socket_deselect here each time, because this does iteration
* over all node sockets internally to check if the node stays selected.
* We can do that more efficiently here.
*/
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
- int sel = 0;
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
+ bool sel = false;
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- sock->flag &= ~SELECT;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->flag &= ~SELECT;
}
/* if no selected sockets remain, also deselect the node */
if (deselect_nodes) {
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
- sel = 1;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ if (socket->flag & SELECT) {
+ sel = true;
break;
}
}
@@ -245,27 +240,24 @@ void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes
}
}
-void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_nodes)
+void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_nodes)
{
- bNode *node;
- bNodeSocket *sock;
-
/* XXX not calling node_socket_deselect here each time, because this does iteration
* over all node sockets internally to check if the node stays selected.
* We can do that more efficiently here.
*/
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
bool sel = false;
- for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next) {
- sock->flag &= ~SELECT;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->flag &= ~SELECT;
}
/* if no selected sockets remain, also deselect the node */
if (deselect_nodes) {
- for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
- if (sock->flag & SELECT) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ if (socket->flag & SELECT) {
sel = true;
break;
}
@@ -305,10 +297,9 @@ static bool node_select_grouped_type(SpaceNode *snode, bNode *node_act)
static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act)
{
- bNode *node;
bool changed = false;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if ((node->flag & SELECT) == 0) {
if (compare_v3v3(node->color, node_act->color, 0.005f)) {
nodeSetSelected(node, true);
@@ -455,24 +446,24 @@ void NODE_OT_select_grouped(wmOperatorType *ot)
/** \name Select (Cursor Pick) Operator
* \{ */
-void node_select_single(bContext *C, bNode *node)
+void node_select_single(bContext &C, bNode &node)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- const Object *ob = CTX_data_active_object(C);
- const Scene *scene = CTX_data_scene(C);
- const wmWindowManager *wm = CTX_wm_manager(C);
+ Main *bmain = CTX_data_main(&C);
+ SpaceNode *snode = CTX_wm_space_node(&C);
+ const Object *ob = CTX_data_active_object(&C);
+ const Scene *scene = CTX_data_scene(&C);
+ const wmWindowManager *wm = CTX_wm_manager(&C);
bool active_texture_changed = false;
bNode *tnode;
for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode != node) {
+ if (tnode != &node) {
nodeSetSelected(tnode, false);
}
}
- nodeSetSelected(node, true);
+ nodeSetSelected(&node, true);
- ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed);
+ ED_node_set_active(bmain, snode, snode->edittree, &node, &active_texture_changed);
ED_node_set_active_viewer_key(snode);
ED_node_sort(snode->edittree);
@@ -480,7 +471,7 @@ void node_select_single(bContext *C, bNode *node)
DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
}
- WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
+ WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr);
}
static int node_mouse_select(bContext *C,
@@ -488,9 +479,9 @@ static int node_mouse_select(bContext *C,
const int mval[2],
bool wait_to_deselect_others)
{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ Main &bmain = *CTX_data_main(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ARegion &region = *CTX_wm_region(C);
const Object *ob = CTX_data_active_object(C);
const Scene *scene = CTX_data_scene(C);
const wmWindowManager *wm = CTX_wm_manager(C);
@@ -511,20 +502,20 @@ static int node_mouse_select(bContext *C,
}
/* get mouse coordinates in view2d space */
- UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
+ UI_view2d_region_to_view(&region.v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
/* first do socket selection, these generally overlap with nodes. */
if (socket_select) {
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
/* NOTE: SOCK_IN does not take into account the extend case...
* This feature is not really used anyway currently? */
- node_socket_toggle(node, sock, true);
+ node_socket_toggle(node, *sock, true);
ret_value = OPERATOR_FINISHED;
}
else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
if (sock->flag & SELECT) {
if (extend) {
- node_socket_deselect(node, sock, true);
+ node_socket_deselect(node, *sock, true);
}
else {
ret_value = OPERATOR_FINISHED;
@@ -538,20 +529,20 @@ static int node_mouse_select(bContext *C,
if (tsock == sock) {
continue;
}
- node_socket_deselect(node, tsock, true);
+ node_socket_deselect(node, *tsock, true);
}
}
if (!extend) {
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
if (tnode == node) {
continue;
}
for (tsock = (bNodeSocket *)tnode->outputs.first; tsock; tsock = tsock->next) {
- node_socket_deselect(tnode, tsock, true);
+ node_socket_deselect(tnode, *tsock, true);
}
}
}
- node_socket_select(node, sock);
+ node_socket_select(node, *sock);
ret_value = OPERATOR_FINISHED;
}
}
@@ -559,7 +550,7 @@ static int node_mouse_select(bContext *C,
if (!sock) {
/* find the closest visible node */
- node = node_under_mouse_select(snode->edittree, (int)cursor[0], (int)cursor[1]);
+ node = node_under_mouse_select(*snode.edittree, (int)cursor[0], (int)cursor[1]);
if (extend) {
if (node != nullptr) {
@@ -580,7 +571,7 @@ static int node_mouse_select(bContext *C,
}
else {
/* Deselect in empty space. */
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
nodeSetSelected(tnode, false);
}
ret_value = OPERATOR_FINISHED;
@@ -595,7 +586,7 @@ static int node_mouse_select(bContext *C,
else {
nodeSetSelected(node, true);
- for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) {
+ for (tnode = (bNode *)snode.edittree->nodes.first; tnode; tnode = tnode->next) {
if (tnode != node) {
nodeSetSelected(tnode, false);
}
@@ -612,16 +603,16 @@ static int node_mouse_select(bContext *C,
bool viewer_node_changed = false;
if (node != nullptr && ret_value != OPERATOR_RUNNING_MODAL) {
viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
- ED_node_set_active(bmain, snode, snode->edittree, node, &active_texture_changed);
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
}
else if (node != nullptr && node->type == GEO_NODE_VIEWER) {
- ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node);
+ ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node);
}
- ED_node_set_active_viewer_key(snode);
- ED_node_sort(snode->edittree);
+ ED_node_set_active_viewer_key(&snode);
+ ED_node_sort(snode.edittree);
if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) ||
viewer_node_changed) {
- DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE);
}
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
@@ -1149,13 +1140,13 @@ static int node_select_same_type_step_exec(bContext *C, wmOperator *op)
}
}
- node_select_single(C, active);
+ node_select_single(*C, *active);
/* is note outside view? */
if (active->totr.xmax < region->v2d.cur.xmin || active->totr.xmin > region->v2d.cur.xmax ||
active->totr.ymax < region->v2d.cur.ymin || active->totr.ymin > region->v2d.cur.ymax) {
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx);
+ space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx);
}
}
@@ -1213,7 +1204,7 @@ static void node_find_update_fn(const struct bContext *C,
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
char name[256];
node_find_create_label(node, name, ARRAY_SIZE(name));
- BLI_string_search_add(search, name, node);
+ BLI_string_search_add(search, name, node, 0);
}
bNode **filtered_nodes;
@@ -1239,12 +1230,12 @@ static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2
if (active) {
ARegion *region = CTX_wm_region(C);
- node_select_single(C, active);
+ node_select_single(*C, *active);
/* is note outside view? */
if (active->totr.xmax < region->v2d.cur.xmin || active->totr.xmin > region->v2d.cur.xmax ||
active->totr.ymax < region->v2d.cur.ymin || active->totr.ymin > region->v2d.cur.ymax) {
- space_node_view_flag(C, snode, region, NODE_SELECT, U.smooth_viewtx);
+ space_node_view_flag(*C, *snode, *region, NODE_SELECT, U.smooth_viewtx);
}
}
}
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index b2a7c1753fb..386178596af 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -447,7 +447,9 @@ static void ui_node_link(bContext *C, void *arg_p, void *event_p)
ED_undo_push(C, "Node input modify");
}
-static void ui_node_sock_name(bNodeTree *ntree, bNodeSocket *sock, char name[UI_MAX_NAME_STR])
+static void ui_node_sock_name(const bNodeTree *ntree,
+ bNodeSocket *sock,
+ char name[UI_MAX_NAME_STR])
{
if (sock->link && sock->link->fromnode) {
bNode *node = sock->link->fromnode;
@@ -709,7 +711,7 @@ void uiTemplateNodeLink(
PointerRNA node_ptr;
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
- node_socket_color_get(C, ntree, &node_ptr, input, socket_col);
+ node_socket_color_get(*C, *ntree, node_ptr, *input, socket_col);
UI_block_layout_set_current(block, layout);
@@ -769,7 +771,6 @@ static void ui_node_draw_input(
PointerRNA inputptr, nodeptr;
uiBlock *block = uiLayoutGetBlock(layout);
uiLayout *row = nullptr;
- bNode *lnode;
bool dependency_loop;
if (input->flag & SOCK_UNAVAIL) {
@@ -778,7 +779,7 @@ static void ui_node_draw_input(
/* to avoid eternal loops on cyclic dependencies */
node->flag |= NODE_TEST;
- lnode = (input->link) ? input->link->fromnode : nullptr;
+ bNode *lnode = (input->link) ? input->link->fromnode : nullptr;
dependency_loop = (lnode && (lnode->flag & NODE_TEST));
if (dependency_loop) {
@@ -868,7 +869,7 @@ static void ui_node_draw_input(
if (node_tree->type == NTREE_GEOMETRY && snode != nullptr) {
/* Only add the attribute search in the node editor, in other places there is not
* enough context. */
- node_geometry_add_attribute_search_button(C, node_tree, node, &inputptr, row);
+ node_geometry_add_attribute_search_button(*C, *node_tree, *node, inputptr, *row);
}
else {
uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index 36b84bec7eb..df629a983e3 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -24,7 +24,6 @@
#include "DNA_node_types.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
@@ -62,25 +61,21 @@ using blender::StringRef;
/** \name View All Operator
* \{ */
-int space_node_view_flag(
- bContext *C, SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx)
+bool space_node_view_flag(
+ bContext &C, SpaceNode &snode, ARegion &region, const int node_flag, const int smooth_viewtx)
{
- bNode *node;
- rctf cur_new;
- float oldwidth, oldheight, width, height;
- float oldasp, asp;
- int tot = 0;
- bool has_frame = false;
+ const float oldwidth = BLI_rctf_size_x(&region.v2d.cur);
+ const float oldheight = BLI_rctf_size_y(&region.v2d.cur);
- oldwidth = BLI_rctf_size_x(&region->v2d.cur);
- oldheight = BLI_rctf_size_y(&region->v2d.cur);
-
- oldasp = oldwidth / oldheight;
+ const float old_aspect = oldwidth / oldheight;
+ rctf cur_new;
BLI_rctf_init_minmax(&cur_new);
- if (snode->edittree) {
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ int tot = 0;
+ bool has_frame = false;
+ if (snode.edittree) {
+ LISTBASE_FOREACH (const bNode *, node, &snode.edittree->nodes) {
if ((node->flag & node_flag) == node_flag) {
BLI_rctf_union(&cur_new, &node->totr);
tot++;
@@ -92,37 +87,39 @@ int space_node_view_flag(
}
}
- if (tot) {
- width = BLI_rctf_size_x(&cur_new);
- height = BLI_rctf_size_y(&cur_new);
- asp = width / height;
+ if (tot == 0) {
+ return false;
+ }
+
+ const float width = BLI_rctf_size_x(&cur_new);
+ const float height = BLI_rctf_size_y(&cur_new);
+ const float new_aspect = width / height;
- /* for single non-frame nodes, don't zoom in, just pan view,
- * but do allow zooming out, this allows for big nodes to be zoomed out */
- if ((tot == 1) && (has_frame == false) && ((oldwidth * oldheight) > (width * height))) {
- /* center, don't zoom */
- BLI_rctf_resize(&cur_new, oldwidth, oldheight);
+ /* for single non-frame nodes, don't zoom in, just pan view,
+ * but do allow zooming out, this allows for big nodes to be zoomed out */
+ if ((tot == 1) && (has_frame == false) && ((oldwidth * oldheight) > (width * height))) {
+ /* center, don't zoom */
+ BLI_rctf_resize(&cur_new, oldwidth, oldheight);
+ }
+ else {
+ if (old_aspect < new_aspect) {
+ const float height_new = width / old_aspect;
+ cur_new.ymin = cur_new.ymin - height_new / 2.0f;
+ cur_new.ymax = cur_new.ymax + height_new / 2.0f;
}
else {
- if (oldasp < asp) {
- const float height_new = width / oldasp;
- cur_new.ymin = cur_new.ymin - height_new / 2.0f;
- cur_new.ymax = cur_new.ymax + height_new / 2.0f;
- }
- else {
- const float width_new = height * oldasp;
- cur_new.xmin = cur_new.xmin - width_new / 2.0f;
- cur_new.xmax = cur_new.xmax + width_new / 2.0f;
- }
-
- /* add some padding */
- BLI_rctf_scale(&cur_new, 1.1f);
+ const float width_new = height * old_aspect;
+ cur_new.xmin = cur_new.xmin - width_new / 2.0f;
+ cur_new.xmax = cur_new.xmax + width_new / 2.0f;
}
- UI_view2d_smooth_view(C, region, &cur_new, smooth_viewtx);
+ /* add some padding */
+ BLI_rctf_scale(&cur_new, 1.1f);
}
- return (tot != 0);
+ UI_view2d_smooth_view(&C, &region, &cur_new, smooth_viewtx);
+
+ return true;
}
static int node_view_all_exec(bContext *C, wmOperator *op)
@@ -135,7 +132,7 @@ static int node_view_all_exec(bContext *C, wmOperator *op)
snode->xof = 0;
snode->yof = 0;
- if (space_node_view_flag(C, snode, region, 0, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, 0, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
@@ -168,7 +165,7 @@ static int node_view_selected_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- if (space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
@@ -447,7 +444,6 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
}
}
-/* Returns mouse position in image space. */
bool ED_space_node_get_position(
Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2])
{
@@ -475,9 +471,6 @@ bool ED_space_node_get_position(
return true;
}
-/* Returns color in linear space, matching ED_space_image_color_sample().
- * And here we've got recursion in the comments tips...
- */
bool ED_space_node_color_sample(
Main *bmain, SpaceNode *snode, ARegion *region, const int mval[2], float r_col[3])
{
@@ -738,7 +731,7 @@ static int space_node_view_geometry_nodes_legacy(bContext *C, SpaceNode *snode,
}
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- if (space_node_view_flag(C, snode, region, NODE_SELECT, smooth_viewtx)) {
+ if (space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx)) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index 784cf7d4dd8..4cc0bed1928 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -29,9 +29,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_node.h"
@@ -54,6 +51,8 @@
#include "node_intern.hh" /* own include */
+using blender::float2;
+
/* ******************** tree path ********************* */
void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
@@ -207,19 +206,14 @@ void ED_node_set_active_viewer_key(SpaceNode *snode)
}
}
-void space_node_group_offset(SpaceNode *snode, float *x, float *y)
+float2 space_node_group_offset(const SpaceNode &snode)
{
- bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
+ const bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
if (path && path->prev) {
- float dcenter[2];
- sub_v2_v2v2(dcenter, path->view_center, path->prev->view_center);
- *x = dcenter[0];
- *y = dcenter[1];
- }
- else {
- *x = *y = 0.0f;
+ return float2(path->view_center) - float2(path->prev->view_center);
}
+ return float2(0);
}
/* ******************** default callbacks for node space ***************** */
@@ -230,8 +224,8 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
snode->spacetype = SPACE_NODE;
snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
- snode->overlay.flag |= SN_OVERLAY_SHOW_OVERLAYS;
- snode->overlay.flag |= SN_OVERLAY_SHOW_WIRE_COLORS;
+ snode->overlay.flag = (SN_OVERLAY_SHOW_OVERLAYS | SN_OVERLAY_SHOW_WIRE_COLORS |
+ SN_OVERLAY_SHOW_PATH);
/* backdrop */
snode->zoom = 1.0f;
@@ -303,7 +297,10 @@ static void node_free(SpaceLink *sl)
MEM_freeN(path);
}
- MEM_SAFE_FREE(snode->runtime);
+ if (snode->runtime) {
+ snode->runtime->linkdrag.reset();
+ MEM_freeN(snode->runtime);
+ }
}
/* spacetype; init callback */
@@ -482,30 +479,10 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
/* default now: refresh node is starting preview */
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
- snode_set_context(C);
+ snode_set_context(*C);
if (snode->nodetree) {
- if (snode->nodetree->type == NTREE_SHADER) {
- if (GS(snode->id->name) == ID_MA) {
- Material *ma = (Material *)snode->id;
- if (ma->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- else if (GS(snode->id->name) == ID_LA) {
- Light *la = (Light *)snode->id;
- if (la->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- else if (GS(snode->id->name) == ID_WO) {
- World *wo = (World *)snode->id;
- if (wo->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
- }
- else if (snode->nodetree->type == NTREE_COMPOSIT) {
+ if (snode->nodetree->type == NTREE_COMPOSIT) {
Scene *scene = (Scene *)snode->id;
if (scene->use_nodes) {
/* recalc is set on 3d view changes for auto compo */
@@ -518,12 +495,6 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
}
}
}
- else if (snode->nodetree->type == NTREE_TEXTURE) {
- Tex *tex = (Tex *)snode->id;
- if (tex->use_nodes) {
- ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER);
- }
- }
}
}
@@ -534,10 +505,7 @@ static SpaceLink *node_duplicate(SpaceLink *sl)
BLI_duplicatelist(&snoden->treepath, &snode->treepath);
- if (snode->runtime != nullptr) {
- snoden->runtime = (SpaceNode_Runtime *)MEM_dupallocN(snode->runtime);
- BLI_listbase_clear(&snoden->runtime->linkdrag);
- }
+ snoden->runtime = nullptr;
/* NOTE: no need to set node tree user counts,
* the editor only keeps at least 1 (id_us_ensure_real),
@@ -601,7 +569,7 @@ static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
&snode->runtime->cursor[1]);
/* here snode->runtime->cursor is used to detect the node edge for sizing */
- node_set_cursor(win, snode, snode->runtime->cursor);
+ node_set_cursor(*win, *snode, snode->runtime->cursor);
/* XXX snode->runtime->cursor is in placing new nodes space */
snode->runtime->cursor[0] /= UI_DPI_FAC;
@@ -635,7 +603,7 @@ static void node_main_region_init(wmWindowManager *wm, ARegion *region)
static void node_main_region_draw(const bContext *C, ARegion *region)
{
- node_draw_space(C, region);
+ node_draw_space(*C, *region);
}
/* ************* dropboxes ************* */
@@ -758,7 +726,7 @@ static void node_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region
static void node_header_region_draw(const bContext *C, ARegion *region)
{
/* find and set the context */
- snode_set_context(C);
+ snode_set_context(*C);
ED_region_header(C, region);
}
@@ -1001,8 +969,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
}
}
-/* only called once, from space/spacetypes.c */
-void ED_spacetype_node(void)
+void ED_spacetype_node()
{
SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node");
ARegionType *art;
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index ff0bd533671..946d7a0538d 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -134,11 +134,6 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
return TRAVERSE_CONTINUE;
}
-/**
- * Populates the \param objects: ListBase with all the outliner selected objects
- * We store it as (Object *)LinkData->data
- * \param objects: expected to be empty
- */
void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index ed52eeab98c..a4d5f2635d4 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -1515,7 +1515,6 @@ void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
/* *************************** Drop Boxes ************************** */
-/* region dropbox definition */
void outliner_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 956c455c545..a586f268128 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2368,6 +2368,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eGpencilModifierType_WeightAngle:
data.icon = ICON_MOD_VERTEX_WEIGHT;
break;
+ case eGpencilModifierType_Shrinkwrap:
+ data.icon = ICON_MOD_SHRINKWRAP;
+ break;
/* Default */
default:
@@ -2933,12 +2936,6 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
(*offsx) += UI_UNIT_X;
}
-/**
- * Return the index to use based on the TreeElement ID and object type
- *
- * We use a continuum of indices until we get to the object data-blocks
- * and we then make room for the object types.
- */
int tree_element_id_type_to_index(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index e449e4a609b..97e5c046452 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -78,8 +78,6 @@ static void outliner_show_active(SpaceOutliner *space_outliner,
TreeElement *te,
ID *id);
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Highlight on Cursor Motion Operator
* \{ */
@@ -154,9 +152,6 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
/** \name Toggle Open/Closed Operator
* \{ */
-/**
- * Open or close a tree element, optionally toggling all children recursively.
- */
void outliner_item_openclose(SpaceOutliner *space_outliner,
TreeElement *te,
bool open,
@@ -708,6 +703,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
+ /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways. */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
@@ -964,9 +961,6 @@ void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* XXX This does not work with several items
- * (it is only called once in the end, due to the 'deferred'
- * file-browser invocation through event system...). */
void lib_relocate_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -975,6 +969,10 @@ void lib_relocate_fn(bContext *C,
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
+ /* XXX: This does not work with several items
+ * (it is only called once in the end, due to the 'deferred'
+ * file-browser invocation through event system...). */
+
wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
lib_relocate(C, te, tselem, ot, false);
@@ -1068,10 +1066,6 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
return 0;
}
-/**
- * Set or unset \a flag for all outliner elements in \a lb and sub-trees.
- * \return if any flag was modified.
- */
bool outliner_flag_set(ListBase *lb, short flag, short set)
{
bool changed = false;
@@ -1225,7 +1219,6 @@ static void outliner_set_coordinates_element_recursive(SpaceOutliner *space_outl
}
}
-/* to retrieve coordinates with redrawing the entire tree */
void outliner_set_coordinates(ARegion *region, SpaceOutliner *space_outliner)
{
int starty = (int)(region->v2d.tot.ymax) - UI_UNIT_Y;
@@ -2234,8 +2227,6 @@ static bool ed_operator_outliner_id_orphans_active(bContext *C)
return true;
}
-/** \} */
-
static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 5336376b576..3439e4fa219 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -250,8 +250,17 @@ typedef enum TreeItemSelectAction {
void outliner_free_tree(ListBase *tree);
void outliner_cleanup_tree(struct SpaceOutliner *space_outliner);
+/**
+ * Free \a element and its sub-tree and remove its link in \a parent_subtree.
+ *
+ * \note Does not remove the #TreeStoreElem of \a element!
+ * \param parent_subtree: Sub-tree of the parent element, so the list containing \a element.
+ */
void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree);
+/**
+ * Main entry point for building the tree data-structure that the outliner represents.
+ */
void outliner_build_tree(struct Main *mainvar,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -260,6 +269,10 @@ void outliner_build_tree(struct Main *mainvar,
bool outliner_requires_rebuild_on_select_or_active_change(
const struct SpaceOutliner *space_outliner);
+/**
+ * Check if a display mode needs a full rebuild if the open/collapsed state changes.
+ * Element types in these modes don't actually add children if collapsed, so the rebuild is needed.
+ */
bool outliner_requires_rebuild_on_open_change(const struct SpaceOutliner *space_outliner);
typedef struct IDsSelectedData {
@@ -285,19 +298,34 @@ void outliner_collection_isolate_flag(struct Scene *scene,
const char *propname,
const bool value);
+/**
+ * Return the index to use based on the TreeElement ID and object type
+ *
+ * We use a continuum of indices until we get to the object data-blocks
+ * and we then make room for the object types.
+ */
int tree_element_id_type_to_index(TreeElement *te);
/* outliner_select.c -------------------------------------------- */
+/**
+ * Generic call for non-id data to make active in UI
+ */
void tree_element_type_active_set(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
TreeStoreElem *tselem,
const eOLSetState set,
bool recursive);
+/**
+ * Generic call for non-id data to check the active state in UI.
+ */
eOLDrawState tree_element_type_active_state_get(const struct bContext *C,
const struct TreeViewContext *tvc,
const TreeElement *te,
const TreeStoreElem *tselem);
+/**
+ * Generic call for ID data check or make/check active in UI.
+ */
void tree_element_activate(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
@@ -309,17 +337,32 @@ eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc,
struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te);
+/**
+ * Select the item using the set flags.
+ */
void outliner_item_select(struct bContext *C,
struct SpaceOutliner *space_outliner,
struct TreeElement *te,
const short select_flag);
+/**
+ * Find if x coordinate is over an icon or name.
+ */
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x);
bool outliner_item_is_co_over_icon(const TreeElement *te, float view_co_x);
+/**
+ * Find if x coordinate is over element name.
+ */
bool outliner_item_is_co_over_name(const TreeElement *te, float view_co_x);
+/**
+ * Find if x coordinate is over element disclosure toggle.
+ */
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x);
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2]);
+/**
+ * Toggle the item's interaction mode if supported.
+ */
void outliner_item_mode_toggle(struct bContext *C,
TreeViewContext *tvc,
TreeElement *te,
@@ -334,6 +377,10 @@ typedef void (*outliner_operation_fn)(struct bContext *C,
TreeStoreElem *,
void *);
+/**
+ * \param recurse_selected: Set to false for operations which are already
+ * recursively operating on their children.
+ */
void outliner_do_object_operation_ex(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
@@ -350,6 +397,10 @@ void outliner_do_object_operation(struct bContext *C,
outliner_operation_fn operation_fn);
int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel);
+/**
+ * Set or unset \a flag for all outliner elements in \a lb and sub-trees.
+ * \return if any flag was modified.
+ */
bool outliner_flag_set(ListBase *lb, short flag, short set);
bool outliner_flag_flip(ListBase *lb, short flag);
@@ -390,14 +441,24 @@ void id_remap_fn(struct bContext *C,
struct TreeStoreElem *tselem,
void *user_data);
+/**
+ * To retrieve coordinates with redrawing the entire tree.
+ */
void outliner_set_coordinates(struct ARegion *region, struct SpaceOutliner *space_outliner);
+/**
+ * Open or close a tree element, optionally toggling all children recursively.
+ */
void outliner_item_openclose(struct SpaceOutliner *space_outliner,
TreeElement *te,
bool open,
bool toggle_all);
/* outliner_dragdrop.c */
+
+/**
+ * Region drop-box definition.
+ */
void outliner_dropboxes(void);
void OUTLINER_OT_item_drag_drop(struct wmOperatorType *ot);
@@ -446,6 +507,8 @@ void merged_element_search_menu_invoke(struct bContext *C,
TreeElement *parent_te,
TreeElement *activate_te);
+/* Menu only! Calls other operators */
+
void OUTLINER_OT_operation(struct wmOperatorType *ot);
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
@@ -510,19 +573,41 @@ void OUTLINER_OT_collection_color_tag_set(struct wmOperatorType *ot);
void outliner_viewcontext_init(const struct bContext *C, TreeViewContext *tvc);
+/**
+ * Try to find an item under y-coordinate \a view_co_y (view-space).
+ * \note Recursive
+ */
TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
const ListBase *tree,
float view_co_y);
+/**
+ * Collapsed items can show their children as click-able icons. This function tries to find
+ * such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
+ *
+ * \return a hovered child item or \a parent_te (if no hovered child found).
+ */
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
TreeElement *parent_te,
float view_co_x,
bool *r_is_merged_icon,
bool *r_is_over_icon);
+/**
+ * `tse` is not in the treestore, we use its contents to find a match.
+ */
TreeElement *outliner_find_tse(struct SpaceOutliner *space_outliner, const TreeStoreElem *tse);
+/**
+ * Find specific item from the trees-tore.
+ */
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
+/**
+ * Find parent element of te.
+ */
TreeElement *outliner_find_parent_element(ListBase *lb,
TreeElement *parent_te,
const TreeElement *child_te);
+/**
+ * Find treestore that refers to given ID.
+ */
TreeElement *outliner_find_id(struct SpaceOutliner *space_outliner,
ListBase *lb,
const struct ID *id);
@@ -530,6 +615,14 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *
TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone);
TreeElement *outliner_search_back_te(TreeElement *te, short idcode);
struct ID *outliner_search_back(TreeElement *te, short idcode);
+/**
+ * Iterate over all tree elements (pre-order traversal), executing \a func callback for
+ * each tree element matching the optional filters.
+ *
+ * \param filter_te_flag: If not 0, only TreeElements with this flag will be visited.
+ * \param filter_tselem_flag: Same as \a filter_te_flag, but for the TreeStoreElem.
+ * \param func: Custom callback to execute for each visited item.
+ */
bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
ListBase *tree,
int filter_te_flag,
@@ -537,16 +630,33 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
TreeTraversalFunc func,
void *customdata);
float outliner_restrict_columns_width(const struct SpaceOutliner *space_outliner);
+/**
+ * Find first tree element in tree with matching treestore flag.
+ */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag);
+/**
+ * Find if element is visible in the outliner tree.
+ */
bool outliner_is_element_visible(const TreeElement *te);
+/**
+ * Scroll view vertically while keeping within total bounds.
+ */
void outliner_scroll_view(struct SpaceOutliner *space_outliner,
struct ARegion *region,
int delta_y);
+/**
+ * The outliner should generally use #ED_region_tag_redraw_no_rebuild() to avoid unnecessary tree
+ * rebuilds. If elements are open or closed, we may still have to rebuild.
+ * Upon changing the open/closed state, call this to avoid rebuilds if possible.
+ */
void outliner_tag_redraw_avoid_rebuild_on_open_change(const struct SpaceOutliner *space_outliner,
struct ARegion *region);
/* outliner_sync.c ---------------------------------------------- */
+/**
+ * If outliner is dirty sync selection from view layer and sequencer.
+ */
void outliner_sync_selection(const struct bContext *C, struct SpaceOutliner *space_outliner);
/* outliner_context.c ------------------------------------------- */
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 5e409db0059..855975eb2dc 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -184,7 +184,6 @@ static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *t
ED_undo_group_end(C);
}
-/* Toggle the item's interaction mode if supported */
void outliner_item_mode_toggle(bContext *C,
TreeViewContext *tvc,
TreeElement *te,
@@ -747,7 +746,6 @@ static void tree_element_text_activate(bContext *C, TreeElement *te)
/* ---------------------------------------------- */
-/* generic call for ID data check or make/check active in UI */
void tree_element_activate(bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
@@ -778,9 +776,6 @@ void tree_element_activate(bContext *C,
}
}
-/**
- * Generic call for non-id data to make active in UI
- */
void tree_element_type_active_set(bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
@@ -1086,9 +1081,6 @@ eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc,
return OL_DRAWSEL_NONE;
}
-/**
- * Generic call for non-id data to check the active state in UI.
- */
eOLDrawState tree_element_type_active_state_get(const bContext *C,
const TreeViewContext *tvc,
const TreeElement *te,
@@ -1446,7 +1438,6 @@ static void do_outliner_item_activate_tree_element(bContext *C,
}
}
-/* Select the item using the set flags */
void outliner_item_select(bContext *C,
SpaceOutliner *space_outliner,
TreeElement *te,
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index d78767019b5..d95a0dde858 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -52,7 +52,6 @@
#include "outliner_intern.h"
-/* Functions for tagging outliner selection syncing is dirty from operators */
void ED_outliner_select_sync_from_object_tag(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -89,7 +88,6 @@ bool ED_outliner_select_sync_is_dirty(const bContext *C)
return wm->outliner_sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL;
}
-/* Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw */
void ED_outliner_select_sync_flag_outliners(const bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -352,7 +350,6 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
}
}
-/* Set clean outliner and mark other outliners for syncing */
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner)
{
/* Don't sync if not checked or in certain outliner display modes */
@@ -547,7 +544,6 @@ static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData
active_data->sequence = SEQ_select_active_get(scene);
}
-/* If outliner is dirty sync selection from view layer and sequencer. */
void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner)
{
/* Set which types of data to sync from sync dirty flag and outliner display mode */
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index ae2b1870884..01f0feec771 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -1095,10 +1095,6 @@ static void singleuser_world_fn(bContext *C,
}
}
-/**
- * \param recurse_selected: Set to false for operations which are already
- * recursively operating on their children.
- */
void outliner_do_object_operation_ex(bContext *C,
ReportList *reports,
Scene *scene_act,
@@ -2984,7 +2980,6 @@ static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event)
return do_outliner_operation_event(C, op->reports, region, space_outliner, hovered_te);
}
-/* Menu only! Calls other operators */
void OUTLINER_OT_operation(wmOperatorType *ot)
{
ot->name = "Context Menu";
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 5427ae31ac3..3353726de18 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -203,12 +203,6 @@ void outliner_cleanup_tree(SpaceOutliner *space_outliner)
outliner_storage_cleanup(space_outliner);
}
-/**
- * Free \a element and its sub-tree and remove its link in \a parent_subtree.
- *
- * \note Does not remove the #TreeStoreElem of \a element!
- * \param parent_subtree: Sub-tree of the parent element, so the list containing \a element.
- */
void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
{
BLI_assert(BLI_findindex(parent_subtree, element) > -1);
@@ -235,10 +229,6 @@ bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *s
return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE);
}
-/**
- * Check if a display mode needs a full rebuild if the open/collapsed state changes.
- * Element types in these modes don't actually add children if collapsed, so the rebuild is needed.
- */
bool outliner_requires_rebuild_on_open_change(const SpaceOutliner *space_outliner)
{
return ELEM(space_outliner->outlinevis, SO_DATA_API);
@@ -822,13 +812,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
}
-/**
- * TODO: this function needs to be split up! It's getting a bit too large...
- *
- * \note "ID" is not always a real ID.
- * \note If child items are only added to the tree if the item is open,
- * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
- */
TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
@@ -1176,7 +1159,6 @@ TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
/* Hierarchy --------------------------------------------- */
-/* make sure elements are correctly nested */
void outliner_make_object_parent_hierarchy(ListBase *lb)
{
/* build hierarchy */
@@ -1876,7 +1858,6 @@ static void outliner_clear_newid_from_main(Main *bmain)
/* ======================================================= */
/* Main Tree Building API */
-/* Main entry point for building the tree data-structure that the outliner represents. */
void outliner_build_tree(Main *mainvar,
Scene *scene,
ViewLayer *view_layer,
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index c62ca468747..d370d508198 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -71,10 +71,6 @@ void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
/** \} */
-/**
- * Try to find an item under y-coordinate \a view_co_y (view-space).
- * \note Recursive
- */
TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
const ListBase *tree,
float view_co_y)
@@ -142,12 +138,6 @@ static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *
return (TreeElement *)parent_te;
}
-/**
- * Collapsed items can show their children as click-able icons. This function tries to find
- * such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
- *
- * \return a hovered child item or \a parent_te (if no hovered child found).
- */
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
TreeElement *parent_te,
float view_co_x,
@@ -167,7 +157,6 @@ TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
return te;
}
-/* Find specific item from the trees-tore. */
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -182,7 +171,6 @@ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store
return NULL;
}
-/* Find parent element of te */
TreeElement *outliner_find_parent_element(ListBase *lb,
TreeElement *parent_te,
const TreeElement *child_te)
@@ -200,7 +188,6 @@ TreeElement *outliner_find_parent_element(ListBase *lb,
return NULL;
}
-/* tse is not in the treestore, we use its contents to find a match */
TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreElem *tse)
{
TreeStoreElem *tselem;
@@ -219,7 +206,6 @@ TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreEle
return NULL;
}
-/* Find treestore that refers to given ID */
TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -302,14 +288,6 @@ ID *outliner_search_back(TreeElement *te, short idcode)
return NULL;
}
-/**
- * Iterate over all tree elements (pre-order traversal), executing \a func callback for
- * each tree element matching the optional filters.
- *
- * \param filter_te_flag: If not 0, only TreeElements with this flag will be visited.
- * \param filter_tselem_flag: Same as \a filter_te_flag, but for the TreeStoreElem.
- * \param func: Custom callback to execute for each visited item.
- */
bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
ListBase *tree,
int filter_te_flag,
@@ -393,7 +371,6 @@ float outliner_restrict_columns_width(const SpaceOutliner *space_outliner)
return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH);
}
-/* Find first tree element in tree with matching treestore flag */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
@@ -408,7 +385,6 @@ TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
return NULL;
}
-/* Find if element is visible in the outliner tree */
bool outliner_is_element_visible(const TreeElement *te)
{
TreeStoreElem *tselem;
@@ -425,7 +401,6 @@ bool outliner_is_element_visible(const TreeElement *te)
return true;
}
-/* Find if x coordinate is over an icon or name */
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x)
{
/* Special case: count area left of Scene Collection as empty space */
@@ -441,19 +416,16 @@ bool outliner_item_is_co_over_icon(const TreeElement *te, float view_co_x)
return (view_co_x > (te->xs + UI_UNIT_X)) && (view_co_x < (te->xs + UI_UNIT_X * 2));
}
-/* Find if x coordinate is over element name. */
bool outliner_item_is_co_over_name(const TreeElement *te, float view_co_x)
{
return (view_co_x > (te->xs + UI_UNIT_X * 2)) && (view_co_x < te->xend);
}
-/* Find if x coordinate is over element disclosure toggle */
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x)
{
return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
}
-/* Scroll view vertically while keeping within total bounds */
void outliner_scroll_view(SpaceOutliner *space_outliner, ARegion *region, int delta_y)
{
int tree_width, tree_height;
@@ -477,11 +449,6 @@ void outliner_scroll_view(SpaceOutliner *space_outliner, ARegion *region, int de
}
}
-/**
- * The outliner should generally use #ED_region_tag_redraw_no_rebuild() to avoid unnecessary tree
- * rebuilds. If elements are open or closed, we may still have to rebuild.
- * Upon changing the open/closed state, call this to avoid rebuilds if possible.
- */
void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space_outliner,
ARegion *region)
{
@@ -494,7 +461,6 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space
}
}
-/* Get base of object under cursor. Used for eyedropper tool */
Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
{
ARegion *region = CTX_wm_region(C);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 205f0117e6a..6c45d39e0d8 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -449,7 +449,6 @@ static void outliner_deactivate(struct ScrArea *area)
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
-/* only called once, from space_api/spacetypes.c */
void ED_spacetype_outliner(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h
index c0a751f2cd5..b6dc33ba7b7 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.h
+++ b/source/blender/editors/space_outliner/tree/tree_display.h
@@ -49,12 +49,20 @@ ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceD
/* The following functions are needed to build the tree. They are calls back into C; the way
* elements are created should be refactored and ported to C++ with a new design/API too. */
+/**
+ * TODO: this function needs to be split up! It's getting a bit too large...
+ *
+ * \note "ID" is not always a real ID.
+ * \note If child items are only added to the tree if the item is open,
+ * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change().
+ */
struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
struct TreeElement *parent,
short type,
short index);
+/* make sure elements are correctly nested */
void outliner_make_object_parent_hierarchy(ListBase *lb);
bool outliner_animdata_test(const struct AnimData *adt);
TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 8aaf396888f..54e64655b18 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -148,6 +148,9 @@ class TreeDisplaySequencer final : public AbstractTreeDisplay {
private:
TreeElement *add_sequencer_contents() const;
+ /**
+ * Helped function to put duplicate sequence in the same tree.
+ */
SequenceAddOp need_add_seq_dup(Sequence *seq) const;
void add_seq_dup(Sequence *seq, TreeElement *te, short index) const;
};
diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
index 371813cfb3f..836f0937cf4 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -33,7 +33,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayLibraries::TreeDisplayLibraries(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
index 69ccf014642..eeb3ca6893a 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
@@ -31,7 +31,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayIDOrphans::TreeDisplayIDOrphans(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
index 0e4636db69d..943e182277c 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc
@@ -34,6 +34,11 @@
namespace blender::ed::outliner {
/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
+/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayOverrideLibrary::TreeDisplayOverrideLibrary(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
index 390f81cfcd1..29442aace37 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -29,7 +29,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplayScenes::TreeDisplayScenes(SpaceOutliner &space_outliner)
diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
index 02af6a13cb3..aa28b164584 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
@@ -31,7 +31,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
TreeDisplaySequencer::TreeDisplaySequencer(SpaceOutliner &space_outliner)
@@ -63,7 +62,6 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data)
return tree;
}
-/* Helped function to put duplicate sequence in the same tree. */
SequenceAddOp TreeDisplaySequencer::need_add_seq_dup(Sequence *seq) const
{
if ((!seq->strip) || (!seq->strip->stripdata)) {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index c3d0aecd3cb..ebbc9baaa9f 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
@@ -37,7 +37,6 @@
namespace blender::ed::outliner {
-/* Convenience/readability. */
template<typename T> using List = ListBaseWrapper<T>;
class ObjectsChildrenBuilder {
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index 11bee36e914..4c4cba2ac58 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -162,7 +162,6 @@ static void script_main_region_listener(const wmRegionListenerParams *UNUSED(par
#endif
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_script(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype script");
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 2bbc346fb50..e814530d1e2 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -668,7 +668,6 @@ static void drawmeta_contents(Scene *scene,
GPU_blend(GPU_BLEND_NONE);
}
-/* Get handle width in 2d-View space. */
float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
{
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
@@ -1517,13 +1516,6 @@ void ED_sequencer_special_preview_clear(void)
sequencer_special_update_set(NULL);
}
-/**
- * Rendering using opengl will change the current viewport/context.
- * This is why we need the \a region, to set back the render area.
- *
- * TODO: do not rely on such hack and just update the \a ibuf outside of
- * the UI drawing code.
- */
ImBuf *sequencer_ibuf_get(struct Main *bmain,
ARegion *region,
struct Depsgraph *depsgraph,
@@ -2097,6 +2089,10 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene)
static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq, bool is_active_seq)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
+ const ARegion *region = CTX_wm_region(C);
+ if (region->regiontype == RGN_TYPE_PREVIEW && !sequencer_view_preview_only_poll(C)) {
+ return;
+ }
if ((seq->flag & SELECT) == 0) {
return;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 899c2f6b4f4..e9f37fa6838 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -127,7 +127,6 @@ bool ED_space_sequencer_maskedit_poll(bContext *C)
return false;
}
-/* Are we displaying the seq output (not channels or histogram). */
bool ED_space_sequencer_check_show_imbuf(SpaceSeq *sseq)
{
return (sseq->mainb == SEQ_DRAW_IMG_IMBUF) &&
@@ -152,12 +151,6 @@ static bool sequencer_fcurves_targets_color_strip(const FCurve *fcurve)
return true;
}
-/*
- * Check if there is animation shown during playback.
- *
- * - Colors of color strips are displayed on the strip itself.
- * - Backdrop is drawn.
- */
bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
const struct Scene *scene)
{
@@ -187,7 +180,6 @@ bool ED_space_sequencer_has_playback_animation(const struct SpaceSeq *sseq,
/** \name Shared Poll Functions
* \{ */
-/* Operator functions. */
bool sequencer_edit_poll(bContext *C)
{
return (SEQ_editing_get(CTX_data_scene(C)) != NULL);
@@ -210,7 +202,7 @@ bool sequencer_strip_has_path_poll(bContext *C)
(SEQ_HAS_PATH(seq)));
}
-bool sequencer_view_preview_poll(bContext *C)
+bool sequencer_view_has_preview_poll(bContext *C)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq == NULL) {
@@ -231,6 +223,26 @@ bool sequencer_view_preview_poll(bContext *C)
return true;
}
+bool sequencer_view_preview_only_poll(const bContext *C)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq == NULL) {
+ return false;
+ }
+ if (SEQ_editing_get(CTX_data_scene(C)) == NULL) {
+ return false;
+ }
+ if (!(ELEM(sseq->view, SEQ_VIEW_PREVIEW) && (sseq->mainb == SEQ_DRAW_IMG_IMBUF))) {
+ return false;
+ }
+ ARegion *region = CTX_wm_region(C);
+ if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
+ return false;
+ }
+
+ return true;
+}
+
bool sequencer_view_strips_poll(bContext *C)
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
@@ -1708,23 +1720,22 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ListBase *seqbasep = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
+
SEQ_prefetch_stop(scene);
- const bool is_preview = sequencer_view_preview_poll(C);
- if (is_preview) {
- SEQ_query_rendered_strips_to_tag(seqbasep, scene->r.cfra, 0);
- }
+ SeqCollection *selected_strips = selected_strips_from_context(C);
+ Sequence *seq;
- LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
- if (seq->flag & SELECT) {
- SEQ_edit_flag_for_removal(scene, seqbasep, seq);
- }
+ SEQ_ITERATOR_FOREACH (seq, selected_strips) {
+ SEQ_edit_flag_for_removal(scene, seqbasep, seq);
}
SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+ SEQ_collection_free(selected_strips);
+
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -3438,7 +3449,7 @@ void SEQUENCER_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = sequencer_set_2d_cursor_exec;
ot->invoke = sequencer_set_2d_cursor_invoke;
- ot->poll = sequencer_view_preview_poll;
+ ot->poll = sequencer_view_has_preview_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 5982a0a8993..cb33c648b0a 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -34,6 +34,7 @@ struct Depsgraph;
struct Main;
struct Scene;
struct Sequence;
+struct SeqCollection;
struct SpaceSeq;
struct StripElem;
struct bContext;
@@ -60,11 +61,19 @@ void color3ubv_from_seq(const struct Scene *curscene,
uchar r_col[3]);
void sequencer_special_update_set(Sequence *seq);
+/* Get handle width in 2d-View space. */
float sequence_handle_size_get_clamped(struct Sequence *seq, const float pixelx);
/* UNUSED */
/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
+/**
+ * Rendering using opengl will change the current viewport/context.
+ * This is why we need the \a region, to set back the render area.
+ *
+ * TODO: do not rely on such hack and just update the \a ibuf outside of
+ * the UI drawing code.
+ */
struct ImBuf *sequencer_ibuf_get(struct Main *bmain,
struct ARegion *region,
struct Depsgraph *depsgraph,
@@ -110,9 +119,29 @@ bool sequencer_edit_poll(struct bContext *C);
/* UNUSED */
/* bool sequencer_strip_poll(struct bContext *C); */
bool sequencer_strip_has_path_poll(struct bContext *C);
-bool sequencer_view_preview_poll(struct bContext *C);
+bool sequencer_view_has_preview_poll(struct bContext *C);
+bool sequencer_view_preview_only_poll(const struct bContext *C);
bool sequencer_view_strips_poll(struct bContext *C);
+/**
+ * Returns collection with all strips presented to user. If operation is done in preview,
+ * collection is limited to all presented strips that can produce image output.
+ *
+ * \param C: context
+ * \return collection of strips (`Sequence`)
+ */
+struct SeqCollection *all_strips_from_context(struct bContext *C);
+
+/**
+ * Returns collection with selected strips presented to user. If operation is done in preview,
+ * collection is limited to selected presented strips, that can produce image output at current
+ * frame.
+ *
+ * \param C: context
+ * \return collection of strips (`Sequence`)
+ */
+struct SeqCollection *selected_strips_from_context(struct bContext *C);
+
/* Externs. */
extern EnumPropertyItem sequencer_prop_effect_types[];
extern EnumPropertyItem prop_side_types[];
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 8a8a24f08ff..47696ab9256 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -64,6 +64,34 @@
/** \name Selection Utilities
* \{ */
+SeqCollection *all_strips_from_context(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview) {
+ return SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ }
+
+ return SEQ_query_all_strips(seqbase);
+}
+
+SeqCollection *selected_strips_from_context(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview) {
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ return strips;
+ }
+
+ return SEQ_query_selected_strips(seqbase);
+}
+
static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
{
Sequence *neighbor;
@@ -411,22 +439,18 @@ static void sequencer_select_do_updates(bContext *C, Scene *scene)
static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
{
int action = RNA_enum_get(op->ptr, "action");
-
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
- Sequence *seq;
- const bool is_preview = sequencer_view_preview_poll(C);
- if (is_preview) {
- SEQ_query_rendered_strips_to_tag(ed->seqbasep, scene->r.cfra, 0);
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
}
+ SeqCollection *strips = all_strips_from_context(C);
+ Sequence *seq;
+
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->flag & SEQ_ALLSEL) {
action = SEL_DESELECT;
break;
@@ -434,10 +458,7 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
}
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
switch (action) {
case SEL_SELECT:
seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
@@ -458,8 +479,9 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ SEQ_collection_free(strips);
+ ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -491,18 +513,15 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
- Sequence *seq;
- const bool is_preview = sequencer_view_preview_poll(C);
- if (is_preview) {
- SEQ_query_rendered_strips_to_tag(ed->seqbasep, scene->r.cfra, 0);
+ if (sequencer_view_has_preview_poll(C) && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
}
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SeqCollection *strips = all_strips_from_context(C);
+ Sequence *seq;
+
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_ALLSEL;
}
@@ -512,8 +531,9 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ SEQ_collection_free(strips);
+ ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -866,6 +886,9 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
}
if (region->regiontype == RGN_TYPE_PREVIEW) {
+ if (!sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
const SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
return OPERATOR_CANCELLED;
@@ -1612,6 +1635,9 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
ARegion *region = CTX_wm_region(C);
if (region->regiontype == RGN_TYPE_PREVIEW) {
+ if (!sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
seq_box_select_seq_from_preview(C, &rectf, sel_op);
sequencer_select_do_updates(C, scene);
return OPERATOR_FINISHED;
@@ -1671,6 +1697,11 @@ static int sequencer_box_select_invoke(bContext *C, wmOperator *op, const wmEven
{
Scene *scene = CTX_data_scene(C);
View2D *v2d = &CTX_wm_region(C)->v2d;
+ ARegion *region = CTX_wm_region(C);
+
+ if (region->regiontype == RGN_TYPE_PREVIEW && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
+ }
const bool tweak = RNA_boolean_get(op->ptr, "tweak");
@@ -1767,17 +1798,15 @@ static const EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
-static bool select_grouped_type(ListBase *seqbasep,
- const bool is_preview,
+static bool select_grouped_type(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
seq->flag |= SELECT;
changed = true;
@@ -1787,18 +1816,16 @@ static bool select_grouped_type(ListBase *seqbasep,
return changed;
}
-static bool select_grouped_type_basic(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_type_basic(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
bool changed = false;
const bool is_sound = SEQ_IS_SOUND(actseq);
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
seq->flag |= SELECT;
changed = true;
@@ -1808,18 +1835,16 @@ static bool select_grouped_type_basic(ListBase *seqbase,
return changed;
}
-static bool select_grouped_type_effect(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_type_effect(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
bool changed = false;
const bool is_effect = SEQ_IS_EFFECT(actseq);
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) &&
(is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
seq->flag |= SELECT;
@@ -1830,8 +1855,8 @@ static bool select_grouped_type_effect(ListBase *seqbase,
return changed;
}
-static bool select_grouped_data(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_data(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
@@ -1842,11 +1867,10 @@ static bool select_grouped_data(ListBase *seqbase,
return changed;
}
+ Sequence *seq;
+
if (SEQ_HAS_PATH(actseq) && dir) {
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
@@ -1856,7 +1880,7 @@ static bool select_grouped_data(ListBase *seqbase,
}
else if (actseq->type == SEQ_TYPE_SCENE) {
Scene *sce = actseq->scene;
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
seq->flag |= SELECT;
changed = true;
@@ -1865,7 +1889,7 @@ static bool select_grouped_data(ListBase *seqbase,
}
else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
MovieClip *clip = actseq->clip;
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP &&
seq->clip == clip) {
seq->flag |= SELECT;
@@ -1875,7 +1899,7 @@ static bool select_grouped_data(ListBase *seqbase,
}
else if (actseq->type == SEQ_TYPE_MASK) {
struct Mask *mask = actseq->mask;
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
seq->flag |= SELECT;
changed = true;
@@ -1886,8 +1910,8 @@ static bool select_grouped_data(ListBase *seqbase,
return changed;
}
-static bool select_grouped_effect(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_effect(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
Sequence *actseq,
const int channel)
{
@@ -1898,20 +1922,15 @@ static bool select_grouped_effect(ListBase *seqbase,
effects[i] = false;
}
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
effects[seq->type] = true;
}
}
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
if (seq->seq1) {
seq->seq1->flag |= SELECT;
@@ -1929,14 +1948,14 @@ static bool select_grouped_effect(ListBase *seqbase,
return changed;
}
-static bool select_grouped_time_overlap(ListBase *seqbase, const bool is_preview, Sequence *actseq)
+static bool select_grouped_time_overlap(SeqCollection *strips,
+ ListBase *UNUSED(seqbase),
+ Sequence *actseq)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
seq->flag |= SELECT;
changed = true;
@@ -1965,31 +1984,26 @@ static void query_lower_channel_strips(Sequence *seq_reference,
/* Select all strips within time range and with lower channel of initial selection. Then select
* effect chains of these strips. */
-static bool select_grouped_effect_link(ListBase *seqbase,
- const bool is_preview,
+static bool select_grouped_effect_link(SeqCollection *strips,
+ ListBase *seqbase,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
{
/* Get collection of strips. */
- SeqCollection *collection = SEQ_query_selected_strips(seqbase);
- const int selected_strip_count = BLI_gset_len(collection->set);
- SEQ_collection_expand(seqbase, collection, query_lower_channel_strips);
- SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain);
+ SEQ_filter_selected_strips(strips);
+ const int selected_strip_count = SEQ_collection_len(strips);
+ SEQ_collection_expand(seqbase, strips, query_lower_channel_strips);
+ SEQ_collection_expand(seqbase, strips, SEQ_query_strip_effect_chain);
/* Check if other strips will be affected. */
- const bool changed = BLI_gset_len(collection->set) > selected_strip_count;
+ const bool changed = SEQ_collection_len(strips) > selected_strip_count;
/* Actual logic. */
Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- if (is_preview && (seq->tmp_tag == false)) {
- continue;
- }
+ SEQ_ITERATOR_FOREACH (seq, strips) {
seq->flag |= SELECT;
}
- SEQ_collection_free(collection);
-
return changed;
}
@@ -2003,15 +2017,14 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
Sequence *actseq = SEQ_select_active_get(scene);
- const bool is_preview = sequencer_view_preview_poll(C);
- if (is_preview) {
- SEQ_query_rendered_strips_to_tag(seqbase, scene->r.cfra, 0);
- if (actseq && actseq->tmp_tag == false) {
- actseq = NULL;
- }
+ const bool is_preview = sequencer_view_has_preview_poll(C);
+ if (is_preview && !sequencer_view_preview_only_poll(C)) {
+ return OPERATOR_CANCELLED;
}
- if (actseq == NULL) {
+ SeqCollection *strips = all_strips_from_context(C);
+
+ if (actseq == NULL || (is_preview && !SEQ_collection_has_strip(actseq, strips))) {
BKE_report(op->reports, RPT_ERROR, "No active sequence!");
return OPERATOR_CANCELLED;
}
@@ -2031,31 +2044,33 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case SEQ_SELECT_GROUP_TYPE:
- changed |= select_grouped_type(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_type(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_BASIC:
- changed |= select_grouped_type_basic(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_type_basic(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_EFFECT:
- changed |= select_grouped_type_effect(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_type_effect(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_DATA:
- changed |= select_grouped_data(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_data(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT:
- changed |= select_grouped_effect(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_effect(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT_LINK:
- changed |= select_grouped_effect_link(seqbase, is_preview, actseq, channel);
+ changed |= select_grouped_effect_link(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_OVERLAP:
- changed |= select_grouped_time_overlap(seqbase, is_preview, actseq);
+ changed |= select_grouped_time_overlap(strips, seqbase, actseq);
break;
default:
BLI_assert(0);
break;
}
+ SEQ_collection_free(strips);
+
if (changed) {
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index fe9cd44c5df..c6fecdb1fc6 100644
--- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -452,7 +452,7 @@ void draw_seq_strip_thumbnail(View2D *v2d,
rcti crop;
/* If width of the strip too small ignore drawing thumbnails. */
- if ((y2 - y1) / pixely <= 40 * U.dpi_fac) {
+ if ((y2 - y1) / pixely <= 20 * U.dpi_fac) {
return;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 2d2e7de7135..360aa2253de 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -405,7 +405,7 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
ot->invoke = WM_gesture_box_invoke;
ot->exec = view_ghost_border_exec;
ot->modal = WM_gesture_box_modal;
- ot->poll = sequencer_view_preview_poll;
+ ot->poll = sequencer_view_has_preview_poll;
ot->cancel = WM_gesture_box_cancel;
/* Flags. */
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 4b6c5e29d77..b93f421ff5c 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -28,6 +28,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
#include "MEM_guardedalloc.h"
@@ -400,7 +401,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
- return 0;
+ return WM_drag_is_ID_type(drag, ID_IM);
}
static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -416,7 +417,8 @@ static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
}
- return 0;
+
+ return WM_drag_is_ID_type(drag, ID_MC);
}
static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -432,35 +434,61 @@ static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
}
}
}
- return 0;
+
+ return WM_drag_is_ID_type(drag, ID_SO);
}
static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- /* Copy drag path to properties. */
- if (RNA_struct_find_property(drop->ptr, "filepath")) {
- RNA_string_set(drop->ptr, "filepath", drag->path);
+ ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
+ /* ID dropped. */
+ if (id != NULL) {
+ const ID_Type id_type = GS(id->name);
+ if (id_type == ID_IM) {
+ Image *ima = (Image *)id;
+ PointerRNA itemptr;
+ char dir[FILE_MAX], file[FILE_MAX];
+ BLI_split_dirfile(ima->filepath, dir, file, sizeof(dir), sizeof(file));
+ RNA_string_set(drop->ptr, "directory", dir);
+ RNA_collection_clear(drop->ptr, "files");
+ RNA_collection_add(drop->ptr, "files", &itemptr);
+ RNA_string_set(&itemptr, "name", file);
+ }
+ else if (id_type == ID_MC) {
+ MovieClip *clip = (MovieClip *)id;
+ RNA_string_set(drop->ptr, "filepath", clip->filepath);
+ RNA_struct_property_unset(drop->ptr, "name");
+ }
+ else if (id_type == ID_SO) {
+ bSound *sound = (bSound *)id;
+ RNA_string_set(drop->ptr, "filepath", sound->filepath);
+ RNA_struct_property_unset(drop->ptr, "name");
+ }
}
+ /* Path dropped. */
+ else if (drag->path[0]) {
+ if (RNA_struct_find_property(drop->ptr, "filepath")) {
+ RNA_string_set(drop->ptr, "filepath", drag->path);
+ }
+ if (RNA_struct_find_property(drop->ptr, "directory")) {
+ PointerRNA itemptr;
+ char dir[FILE_MAX], file[FILE_MAX];
- if (RNA_struct_find_property(drop->ptr, "directory")) {
- PointerRNA itemptr;
- char dir[FILE_MAX], file[FILE_MAX];
-
- BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file));
+ BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file));
- RNA_string_set(drop->ptr, "directory", dir);
+ RNA_string_set(drop->ptr, "directory", dir);
- RNA_collection_clear(drop->ptr, "files");
- RNA_collection_add(drop->ptr, "files", &itemptr);
- RNA_string_set(&itemptr, "name", file);
+ RNA_collection_clear(drop->ptr, "files");
+ RNA_collection_add(drop->ptr, "files", &itemptr);
+ RNA_string_set(&itemptr, "name", file);
+ }
}
}
/* This region dropbox definition. */
-static void sequencer_dropboxes(void)
-{
- ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
+static void sequencer_dropboxes_add_to_lb(ListBase *lb)
+{
WM_dropbox_add(
lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy, NULL, NULL);
WM_dropbox_add(
@@ -469,6 +497,14 @@ static void sequencer_dropboxes(void)
lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, NULL, NULL);
}
+static void sequencer_dropboxes(void)
+{
+ ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
+ sequencer_dropboxes_add_to_lb(lb);
+ lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW);
+ sequencer_dropboxes_add_to_lb(lb);
+}
+
/* ************* end drop *********** */
/* DO NOT make this static, this hides the symbol and breaks API generation script. */
@@ -757,6 +793,9 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region)
/* Own keymap. */
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
+
+ ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW);
+ WM_event_add_dropbox_handler(&region->handlers, lb);
}
static void sequencer_preview_region_layout(const bContext *C, ARegion *region)
@@ -966,7 +1005,6 @@ static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_
/* ************************************* */
-/* Only called once, from space/spacetypes.c. */
void ED_spacetype_sequencer(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index 192b80881ee..f1db8dedf1a 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -41,22 +41,20 @@ set(SRC
spreadsheet_data_source.cc
spreadsheet_data_source_geometry.cc
spreadsheet_dataset_draw.cc
- spreadsheet_dataset_layout.cc
spreadsheet_draw.cc
spreadsheet_layout.cc
spreadsheet_ops.cc
+ spreadsheet_panels.cc
spreadsheet_row_filter.cc
spreadsheet_row_filter_ui.cc
spreadsheet_cache.hh
- spreadsheet_cell_value.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
spreadsheet_context.hh
spreadsheet_data_source.hh
spreadsheet_data_source_geometry.hh
spreadsheet_dataset_draw.hh
- spreadsheet_dataset_layout.hh
spreadsheet_draw.hh
spreadsheet_intern.hh
spreadsheet_layout.hh
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 50b67c55bd6..61cc70830af 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -41,6 +41,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "BLT_translation.h"
+
#include "BLF_api.h"
#include "spreadsheet_intern.hh"
@@ -321,6 +323,8 @@ static float get_default_column_width(const ColumnValues &values)
return 8.0f;
case SPREADSHEET_VALUE_TYPE_STRING:
return 5.0f;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ return 2.0f;
}
return float_width;
}
@@ -591,35 +595,10 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa
spreadsheet_header_region_listener(params);
}
-static void spreadsheet_dataset_region_init(wmWindowManager *wm, ARegion *region)
-{
- region->v2d.scroll |= V2D_SCROLL_RIGHT;
- region->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM);
- region->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
- region->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
-
- UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
-
- wmKeyMap *keymap = WM_keymap_ensure(
- wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
- WM_event_add_keymap_handler(&region->handlers, keymap);
-}
-
static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region)
{
spreadsheet_update_context_path(C);
-
- View2D *v2d = &region->v2d;
- UI_view2d_view_ortho(v2d);
- UI_ThemeClearColor(TH_BACK);
-
- draw_dataset_in_region(C, region);
-
- /* reset view matrix */
- UI_view2d_view_restore(C);
-
- /* scrollers */
- UI_view2d_scrollers_draw(v2d, nullptr);
+ ED_region_panels(C, region);
}
static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region)
@@ -640,7 +619,7 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS
{
}
-void ED_spacetype_spreadsheet(void)
+void ED_spacetype_spreadsheet()
{
SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
ARegionType *art;
@@ -710,11 +689,12 @@ void ED_spacetype_spreadsheet(void)
/* regions: channels */
art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region");
art->regionid = RGN_TYPE_CHANNELS;
- art->prefsizex = 200 + V2D_SCROLL_WIDTH;
+ art->prefsizex = 150 + V2D_SCROLL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
- art->init = spreadsheet_dataset_region_init;
+ art->init = ED_region_panels_init;
art->draw = spreadsheet_dataset_region_draw;
art->listener = spreadsheet_dataset_region_listener;
+ blender::ed::spreadsheet::spreadsheet_data_set_region_panels_register(*art);
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
deleted file mode 100644
index c11b4a2b23d..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include <optional>
-
-#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-
-struct Collection;
-struct Object;
-
-namespace blender::ed::spreadsheet {
-
-struct ObjectCellValue {
- const Object *object;
-};
-
-struct CollectionCellValue {
- const Collection *collection;
-};
-
-struct GeometrySetCellValue {
- const GeometrySet *geometry_set;
-};
-
-/**
- * This is a type that can hold the value of a cell in a spreadsheet. This type allows us to
- * decouple the drawing of individual cells from the code that generates the data to be displayed.
- */
-class CellValue {
- public:
- /* The implementation just uses a bunch of `std::option` for now. Unfortunately, we cannot use
- * `std::variant` yet, due to missing compiler support. This type can really be optimized more,
- * but it does not really matter too much currently. */
-
- std::optional<int> value_int;
- std::optional<float> value_float;
- std::optional<bool> value_bool;
- std::optional<float2> value_float2;
- std::optional<float3> value_float3;
- std::optional<ColorGeometry4f> value_color;
- std::optional<ObjectCellValue> value_object;
- std::optional<CollectionCellValue> value_collection;
- std::optional<GeometrySetCellValue> value_geometry_set;
- std::optional<std::string> value_string;
-};
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index ee08c86b29f..7551593ef38 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -18,14 +18,52 @@
#include "MEM_guardedalloc.h"
+#include "BLI_color.hh"
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
#include "BLI_hash.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
+#include "BKE_geometry_set.hh"
+
+#include "FN_cpp_type.hh"
+
#include "spreadsheet_column.hh"
+#include "spreadsheet_column_values.hh"
namespace blender::ed::spreadsheet {
+eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type)
+{
+ if (type.is<bool>()) {
+ return SPREADSHEET_VALUE_TYPE_BOOL;
+ }
+ if (type.is<int>()) {
+ return SPREADSHEET_VALUE_TYPE_INT32;
+ }
+ if (type.is<float>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT;
+ }
+ if (type.is<float2>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT2;
+ }
+ if (type.is<float3>()) {
+ return SPREADSHEET_VALUE_TYPE_FLOAT3;
+ }
+ if (type.is<ColorGeometry4f>()) {
+ return SPREADSHEET_VALUE_TYPE_COLOR;
+ }
+ if (type.is<std::string>()) {
+ return SPREADSHEET_VALUE_TYPE_STRING;
+ }
+ if (type.is<InstanceReference>()) {
+ return SPREADSHEET_VALUE_TYPE_INSTANCES;
+ }
+
+ return SPREADSHEET_VALUE_TYPE_UNKNOWN;
+}
+
SpreadsheetColumnID *spreadsheet_column_id_new()
{
SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID),
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
index 877651d6530..83e3217e5c8 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
@@ -20,33 +20,36 @@
#include "BLI_string_ref.hh"
-#include "spreadsheet_cell_value.hh"
+#include "FN_generic_virtual_array.hh"
namespace blender::ed::spreadsheet {
+struct CellDrawParams;
+
+eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type);
+
/**
* This represents a column in a spreadsheet. It has a name and provides a value for all the cells
* in the column.
*/
-class ColumnValues {
+class ColumnValues final {
protected:
- eSpreadsheetColumnValueType type_;
std::string name_;
- int size_;
+
+ fn::GVArray data_;
public:
- ColumnValues(const eSpreadsheetColumnValueType type, std::string name, const int size)
- : type_(type), name_(std::move(name)), size_(size)
+ ColumnValues(std::string name, fn::GVArray data) : name_(std::move(name)), data_(std::move(data))
{
+ /* The array should not be empty. */
+ BLI_assert(data_);
}
virtual ~ColumnValues() = default;
- virtual void get_value(int index, CellValue &r_cell_value) const = 0;
-
eSpreadsheetColumnValueType type() const
{
- return type_;
+ return cpp_type_to_column_type(data_.type());
}
StringRefNull name() const
@@ -56,45 +59,16 @@ class ColumnValues {
int size() const
{
- return size_;
+ return data_.size();
}
- /* The default width of newly created columns, in UI units. */
- float default_width = 0.0f;
-};
-
-/* Utility class for the function below. */
-template<typename GetValueF> class LambdaColumnValues : public ColumnValues {
- private:
- GetValueF get_value_;
-
- public:
- LambdaColumnValues(const eSpreadsheetColumnValueType type,
- std::string name,
- int size,
- GetValueF get_value)
- : ColumnValues(type, std::move(name), size), get_value_(std::move(get_value))
+ const fn::GVArray &data() const
{
+ return data_;
}
- void get_value(int index, CellValue &r_cell_value) const final
- {
- get_value_(index, r_cell_value);
- }
+ /* The default width of newly created columns, in UI units. */
+ float default_width = 0.0f;
};
-/* Utility function that simplifies creating a spreadsheet column from a lambda function. */
-template<typename GetValueF>
-std::unique_ptr<ColumnValues> column_values_from_function(const eSpreadsheetColumnValueType type,
- std::string name,
- const int size,
- GetValueF get_value,
- const float default_width = 0.0f)
-{
- std::unique_ptr<ColumnValues> column_values = std::make_unique<LambdaColumnValues<GetValueF>>(
- type, std::move(name), size, std::move(get_value));
- column_values->default_width = default_width;
- return column_values;
-}
-
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index fef84719bc4..337a6037c42 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_virtual_array.hh"
+
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_lib_id.h"
@@ -51,30 +53,6 @@ using blender::fn::GField;
namespace blender::ed::spreadsheet {
-static std::optional<eSpreadsheetColumnValueType> cpp_type_to_column_value_type(
- const fn::CPPType &type)
-{
- if (type.is<bool>()) {
- return SPREADSHEET_VALUE_TYPE_BOOL;
- }
- if (type.is<int>()) {
- return SPREADSHEET_VALUE_TYPE_INT32;
- }
- if (type.is<float>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT;
- }
- if (type.is<float2>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT2;
- }
- if (type.is<float3>()) {
- return SPREADSHEET_VALUE_TYPE_FLOAT3;
- }
- if (type.is<ColorGeometry4f>()) {
- return SPREADSHEET_VALUE_TYPE_COLOR;
- }
- return std::nullopt;
-}
-
void ExtraColumns::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
@@ -92,39 +70,7 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
if (values == nullptr) {
return {};
}
- eSpreadsheetColumnValueType column_type = *cpp_type_to_column_value_type(values->type());
- return column_values_from_function(column_type,
- column_id.name,
- values->size(),
- [column_type, values](int index, CellValue &r_cell_value) {
- const void *value = (*values)[index];
- switch (column_type) {
- case SPREADSHEET_VALUE_TYPE_BOOL:
- r_cell_value.value_bool = *(const bool *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_INT32:
- r_cell_value.value_int = *(const int *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT:
- r_cell_value.value_float = *(const float *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT2:
- r_cell_value.value_float2 = *(const float2 *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_FLOAT3:
- r_cell_value.value_float3 = *(const float3 *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_COLOR:
- r_cell_value.value_color = *(
- const ColorGeometry4f *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_STRING:
- r_cell_value.value_string = *(const std::string *)value;
- break;
- case SPREADSHEET_VALUE_TYPE_INSTANCES:
- break;
- }
- });
+ return std::make_unique<ColumnValues>(column_id.name, fn::GVArray::ForSpan(*values));
}
void GeometryDataSource::foreach_default_column_ids(
@@ -134,6 +80,10 @@ void GeometryDataSource::foreach_default_column_ids(
return;
}
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ fn({(char *)"Name"}, false);
+ }
+
extra_columns_.foreach_default_column_ids(fn);
component_->attribute_foreach(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
@@ -148,12 +98,18 @@ void GeometryDataSource::foreach_default_column_ids(
fn(column_id, false);
return true;
});
+
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ fn({(char *)"Rotation"}, false);
+ fn({(char *)"Scale"}, false);
+ }
}
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
- if (component_->attribute_domain_size(domain_) == 0) {
+ const int domain_size = component_->attribute_domain_size(domain_);
+ if (domain_size == 0) {
return {};
}
@@ -164,6 +120,33 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return extra_column_values;
}
+ if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
+ const InstancesComponent &instances = static_cast<const InstancesComponent &>(*component_);
+ if (STREQ(column_id.name, "Name")) {
+ Span<int> reference_handles = instances.instance_reference_handles();
+ Span<InstanceReference> references = instances.references();
+ return std::make_unique<ColumnValues>(
+ column_id.name,
+ VArray<InstanceReference>::ForFunc(domain_size,
+ [reference_handles, references](int64_t index) {
+ return references[reference_handles[index]];
+ }));
+ }
+ Span<float4x4> transforms = instances.instance_transforms();
+ if (STREQ(column_id.name, "Rotation")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].to_euler();
+ }));
+ }
+ if (STREQ(column_id.name, "Scale")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].scale();
+ }));
+ }
+ }
+
bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
if (!attribute) {
return {};
@@ -172,72 +155,8 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (attribute.domain != domain_) {
return {};
}
- int domain_size = varray.size();
- const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type());
- switch (type) {
- case CD_PROP_FLOAT:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float value;
- varray.get(index, &value);
- r_cell_value.value_float = value;
- });
- case CD_PROP_INT32:
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- int value;
- varray.get(index, &value);
- r_cell_value.value_int = value;
- },
- STREQ(column_id.name, "id") ? 5.5f : 0.0f);
- case CD_PROP_BOOL:
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_BOOL,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- bool value;
- varray.get(index, &value);
- r_cell_value.value_bool = value;
- });
- case CD_PROP_FLOAT2: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT2,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float2 value;
- varray.get(index, &value);
- r_cell_value.value_float2 = value;
- });
- }
- case CD_PROP_FLOAT3: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- float3 value;
- varray.get(index, &value);
- r_cell_value.value_float3 = value;
- });
- }
- case CD_PROP_COLOR: {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_COLOR,
- column_id.name,
- domain_size,
- [varray](int index, CellValue &r_cell_value) {
- ColorGeometry4f value;
- varray.get(index, &value);
- r_cell_value.value_color = value;
- });
- }
- default:
- break;
- }
- return {};
+
+ return std::make_unique<ColumnValues>(column_id.name, std::move(varray));
}
int GeometryDataSource::tot_rows() const
@@ -245,90 +164,6 @@ int GeometryDataSource::tot_rows() const
return component_->attribute_domain_size(domain_);
}
-using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
-
-static void get_selected_vertex_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totvert)) {
- if (!selection[i]) {
- continue;
- }
- if (!is_vertex_selected_fn(i)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_corner_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totloop)) {
- const MLoop &loop = mesh.mloop[i];
- if (!selection[i]) {
- continue;
- }
- if (!is_vertex_selected_fn(loop.v)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_face_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- if (!selection[poly_index]) {
- continue;
- }
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- if (!is_vertex_selected_fn(loop.v)) {
- selection[poly_index] = false;
- break;
- }
- }
- }
-}
-
-static void get_selected_edge_indices(const Mesh &mesh,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- for (const int i : IndexRange(mesh.totedge)) {
- if (!selection[i]) {
- continue;
- }
- const MEdge &edge = mesh.medge[i];
- if (!is_vertex_selected_fn(edge.v1) || !is_vertex_selected_fn(edge.v2)) {
- selection[i] = false;
- }
- }
-}
-
-static void get_selected_indices_on_domain(const Mesh &mesh,
- const AttributeDomain domain,
- const IsVertexSelectedFn is_vertex_selected_fn,
- MutableSpan<bool> selection)
-{
- switch (domain) {
- case ATTR_DOMAIN_POINT:
- return get_selected_vertex_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_FACE:
- return get_selected_face_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_CORNER:
- return get_selected_corner_indices(mesh, is_vertex_selected_fn, selection);
- case ATTR_DOMAIN_EDGE:
- return get_selected_edge_indices(mesh, is_vertex_selected_fn, selection);
- default:
- return;
- }
-}
-
/**
* Only data sets corresponding to mesh objects in edit mode currently support selection filtering.
*/
@@ -348,7 +183,18 @@ bool GeometryDataSource::has_selection_filter() const
return true;
}
-void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included) const
+static IndexMask index_mask_from_bool_array(const VArray<bool> &selection,
+ Vector<int64_t> &indices)
+{
+ for (const int i : selection.index_range()) {
+ if (selection[i]) {
+ indices.append(i);
+ }
+ }
+ return IndexMask(indices);
+}
+
+IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) const
{
std::lock_guard lock{mutex_};
@@ -364,136 +210,38 @@ void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included)
int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- const int i_orig = orig_indices[vertex_index];
- if (i_orig < 0) {
- return false;
- }
- if (i_orig >= bm->totvert) {
- return false;
- }
- BMVert *vert = bm->vtable[i_orig];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
- }
- else if (mesh_eval->totvert == bm->totvert) {
+ VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm, orig_indices](int vertex_index) -> bool {
+ const int i_orig = orig_indices[vertex_index];
+ if (i_orig < 0) {
+ return false;
+ }
+ if (i_orig >= bm->totvert) {
+ return false;
+ }
+ BMVert *vert = bm->vtable[i_orig];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_from_bool_array(selection, indices);
+ }
+
+ if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
- auto is_vertex_selected = [&](int vertex_index) -> bool {
- BMVert *vert = bm->vtable[vertex_index];
- return BM_elem_flag_test(vert, BM_ELEM_SELECT);
- };
- get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included);
- }
-}
-
-void InstancesDataSource::foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
-{
- if (component_->instances_amount() == 0) {
- return;
- }
-
- extra_columns_.foreach_default_column_ids(fn);
-
- SpreadsheetColumnID column_id;
- column_id.name = (char *)"Name";
- fn(column_id, false);
- for (const char *name : {"Position", "Rotation", "Scale", "id"}) {
- column_id.name = (char *)name;
- fn(column_id, false);
- }
-}
-
-std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
- const SpreadsheetColumnID &column_id) const
-{
- if (component_->instances_amount() == 0) {
- return {};
- }
-
- std::unique_ptr<ColumnValues> extra_column_values = extra_columns_.get_column_values(column_id);
- if (extra_column_values) {
- return extra_column_values;
- }
-
- const int size = this->tot_rows();
- if (STREQ(column_id.name, "Name")) {
- Span<int> reference_handles = component_->instance_reference_handles();
- Span<InstanceReference> references = component_->references();
- std::unique_ptr<ColumnValues> values = column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INSTANCES,
- "Name",
- size,
- [reference_handles, references](int index, CellValue &r_cell_value) {
- const InstanceReference &reference = references[reference_handles[index]];
- switch (reference.type()) {
- case InstanceReference::Type::Object: {
- Object &object = reference.object();
- r_cell_value.value_object = ObjectCellValue{&object};
- break;
- }
- case InstanceReference::Type::Collection: {
- Collection &collection = reference.collection();
- r_cell_value.value_collection = CollectionCellValue{&collection};
- break;
- }
- case InstanceReference::Type::GeometrySet: {
- const GeometrySet &geometry_set = reference.geometry_set();
- r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set};
- break;
- }
- case InstanceReference::Type::None: {
- break;
- }
- }
- });
- return values;
- }
- Span<float4x4> transforms = component_->instance_transforms();
- if (STREQ(column_id.name, "Position")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].translation();
- });
- }
- if (STREQ(column_id.name, "Rotation")) {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].to_euler();
- });
- }
- if (STREQ(column_id.name, "Scale")) {
- return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].scale();
- });
- }
- Span<int> ids = component_->instance_ids();
- if (!ids.is_empty()) {
- if (STREQ(column_id.name, "id")) {
- /* Make the column a bit wider by default, since the IDs tend to be large numbers. */
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INT32,
- column_id.name,
- size,
- [ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
- 5.5f);
- }
- }
- return {};
-}
-
-int InstancesDataSource::tot_rows() const
-{
- return component_->instances_amount();
+ VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForFunc(mesh_eval->totvert,
+ [bm](int vertex_index) -> bool {
+ BMVert *vert = bm->vtable[vertex_index];
+ return BM_elem_flag_test(vert, BM_ELEM_SELECT);
+ }),
+ ATTR_DOMAIN_POINT,
+ domain_);
+ return index_mask_from_bool_array(selection, indices);
+ }
+
+ return IndexMask(mesh_eval->totvert);
}
void VolumeDataSource::foreach_default_column_ids(
@@ -520,50 +268,36 @@ std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values(
#ifdef WITH_OPENVDB
const int size = this->tot_rows();
if (STREQ(column_id.name, "Grid Name")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Grid Name"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Grid Name"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
- r_cell_value.value_string = BKE_volume_grid_name(volume_grid);
- },
- 6.0f);
+ return BKE_volume_grid_name(volume_grid);
+ }));
}
if (STREQ(column_id.name, "Data Type")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Type"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Data Type"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
const VolumeGridType type = BKE_volume_grid_type(volume_grid);
const char *name = nullptr;
RNA_enum_name_from_value(rna_enum_volume_grid_data_type_items, type, &name);
- r_cell_value.value_string = IFACE_(name);
- },
- 5.0f);
+ return IFACE_(name);
+ }));
}
if (STREQ(column_id.name, "Class")) {
- return column_values_from_function(
- SPREADSHEET_VALUE_TYPE_STRING,
- IFACE_("Class"),
- size,
- [volume](int index, CellValue &r_cell_value) {
+ return std::make_unique<ColumnValues>(
+ IFACE_("Class"), VArray<std::string>::ForFunc(size, [volume](int64_t index) {
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index);
openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
openvdb::GridClass grid_class = grid->getGridClass();
if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) {
- r_cell_value.value_string = IFACE_("Fog Volume");
- }
- else if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
- r_cell_value.value_string = IFACE_("Level Set");
+ return IFACE_("Fog Volume");
}
- else {
- r_cell_value.value_string = IFACE_("Unkown");
+ if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
+ return IFACE_("Level Set");
}
- },
- 5.0f);
+ return IFACE_("Unknown");
+ }));
}
#else
UNUSED_VARS(column_id);
@@ -582,8 +316,7 @@ int VolumeDataSource::tot_rows() const
}
GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
- Object *object_eval,
- const GeometryComponentType used_component_type)
+ Object *object_eval)
{
GeometrySet geometry_set;
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
@@ -615,7 +348,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
}
}
else {
- if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
+ if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
if (mesh == nullptr) {
return geometry_set;
@@ -762,8 +495,7 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
const GeometryComponentType component_type = get_display_component_type(C, object_eval);
- GeometrySet geometry_set = spreadsheet_get_display_geometry_set(
- sspreadsheet, object_eval, component_type);
+ GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval);
if (!geometry_set.has(component_type)) {
return {};
@@ -773,9 +505,6 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
ExtraColumns extra_columns;
add_fields_as_extra_columns(sspreadsheet, component, extra_columns);
- if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
- return std::make_unique<InstancesDataSource>(geometry_set, std::move(extra_columns));
- }
if (component_type == GEO_COMPONENT_TYPE_VOLUME) {
return std::make_unique<VolumeDataSource>(geometry_set);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
index a4114dd1f6a..b5105050d2b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -82,30 +82,12 @@ class GeometryDataSource : public DataSource {
return object_eval_;
}
+ /**
+ * Only data sets corresponding to mesh objects in edit mode currently support selection
+ * filtering.
+ */
bool has_selection_filter() const override;
- void apply_selection_filter(MutableSpan<bool> rows_included) const;
-
- void foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
-
- std::unique_ptr<ColumnValues> get_column_values(
- const SpreadsheetColumnID &column_id) const override;
-
- int tot_rows() const override;
-};
-
-class InstancesDataSource : public DataSource {
- const GeometrySet geometry_set_;
- const InstancesComponent *component_;
- ExtraColumns extra_columns_;
-
- public:
- InstancesDataSource(GeometrySet geometry_set, ExtraColumns extra_columns)
- : geometry_set_(std::move(geometry_set)),
- component_(geometry_set_.get_component_for_read<InstancesComponent>()),
- extra_columns_(std::move(extra_columns))
- {
- }
+ IndexMask apply_selection_filter(Vector<int64_t> &indices) const;
void foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
index acedcebe05c..2a81b56d129 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -14,288 +14,226 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include <array>
-
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_context.h"
#include "BKE_volume.h"
-#include "BLF_api.h"
-
-#include "BLI_rect.h"
-
#include "RNA_access.h"
#include "UI_interface.h"
-#include "UI_view2d.h"
+#include "UI_interface.hh"
+#include "UI_tree_view.hh"
#include "WM_types.h"
+#include "BLT_translation.h"
+
#include "spreadsheet_dataset_draw.hh"
#include "spreadsheet_draw.hh"
#include "spreadsheet_intern.hh"
-static int is_component_row_selected(struct uiBut *but, const void *arg)
-{
- SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)arg;
-
- GeometryComponentType component = (GeometryComponentType)UI_but_datasetrow_component_get(but);
- AttributeDomain domain = (AttributeDomain)UI_but_datasetrow_domain_get(but);
+namespace blender::ed::spreadsheet {
- const bool is_component_selected = (GeometryComponentType)
- sspreadsheet->geometry_component_type == component;
- const bool is_domain_selected = (AttributeDomain)sspreadsheet->attribute_domain == domain;
- bool is_selected = is_component_selected && is_domain_selected;
+class GeometryDataSetTreeView;
- if (component == GEO_COMPONENT_TYPE_VOLUME) {
- is_selected = is_component_selected;
- }
+class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem {
+ GeometryComponentType component_type_;
+ std::optional<AttributeDomain> domain_;
+ BIFIconID icon_;
- return is_selected;
-}
+ public:
+ GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ StringRef label,
+ BIFIconID icon);
+ GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ AttributeDomain domain,
+ StringRef label,
+ BIFIconID icon);
-namespace blender::ed::spreadsheet {
+ void on_activate() override;
-/* -------------------------------------------------------------------- */
-/* Draw Context */
+ void build_row(uiLayout &row) override;
-class DatasetDrawContext {
- std::array<int, 2> mval_;
+ protected:
+ std::optional<bool> should_be_active() const override;
+ bool supports_collapsing() const override;
- public:
- const SpaceSpreadsheet *sspreadsheet;
- Object *object_eval;
- /* Current geometry set, changes per component. */
- GeometrySet current_geometry_set;
+ private:
+ GeometryDataSetTreeView &get_tree() const;
+ std::optional<int> count() const;
+};
- DatasetDrawContext(const bContext *C);
+class GeometryDataSetTreeView : public ui::AbstractTreeView {
+ GeometrySet geometry_set_;
+ const bContext &C_;
+ SpaceSpreadsheet &sspreadsheet_;
+ bScreen &screen_;
- GeometrySet geometry_set_from_component(GeometryComponentType component);
- const std::array<int, 2> &cursor_mval() const;
-};
+ friend class GeometryDataSetTreeViewItem;
-DatasetDrawContext::DatasetDrawContext(const bContext *C)
- : sspreadsheet(CTX_wm_space_spreadsheet(C)),
- object_eval(spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C)))
-{
- const wmWindow *win = CTX_wm_window(C);
- const ARegion *region = CTX_wm_region(C);
- mval_ = {win->eventstate->xy[0] - region->winrct.xmin,
- win->eventstate->xy[1] - region->winrct.ymin};
-}
+ public:
+ GeometryDataSetTreeView(GeometrySet geometry_set, const bContext &C)
+ : geometry_set_(std::move(geometry_set)),
+ C_(C),
+ sspreadsheet_(*CTX_wm_space_spreadsheet(&C)),
+ screen_(*CTX_wm_screen(&C))
+ {
+ }
-GeometrySet DatasetDrawContext::geometry_set_from_component(GeometryComponentType component)
-{
- return spreadsheet_get_display_geometry_set(sspreadsheet, object_eval, component);
-}
+ void build_tree() override
+ {
+ GeometryDataSetTreeViewItem &mesh = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, IFACE_("Mesh"), ICON_MESH_DATA);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_POINT, IFACE_("Vertex"), ICON_VERTEXSEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_EDGE, IFACE_("Edge"), ICON_EDGESEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_FACE, IFACE_("Face"), ICON_FACESEL);
+ mesh.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_CORNER, IFACE_("Face Corner"), ICON_NODE_CORNER);
+
+ GeometryDataSetTreeViewItem &curve = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_CURVE, IFACE_("Curve"), ICON_CURVE_DATA);
+ curve.add_tree_item<GeometryDataSetTreeViewItem>(GEO_COMPONENT_TYPE_CURVE,
+ ATTR_DOMAIN_POINT,
+ IFACE_("Control Point"),
+ ICON_CURVE_BEZCIRCLE);
+ curve.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_CURVE, ATTR_DOMAIN_CURVE, IFACE_("Spline"), ICON_CURVE_PATH);
+
+ GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_POINT_CLOUD, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA);
+ pointcloud.add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_POINT_CLOUD, ATTR_DOMAIN_POINT, IFACE_("Point"), ICON_PARTICLE_POINT);
+
+ this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_VOLUME, IFACE_("Volume Grids"), ICON_VOLUME_DATA);
+
+ this->add_tree_item<GeometryDataSetTreeViewItem>(
+ GEO_COMPONENT_TYPE_INSTANCES, ATTR_DOMAIN_INSTANCE, IFACE_("Instances"), ICON_EMPTY_AXIS);
+ }
+};
-const std::array<int, 2> &DatasetDrawContext::cursor_mval() const
+GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ StringRef label,
+ BIFIconID icon)
+ : component_type_(component_type), domain_(std::nullopt), icon_(icon)
{
- return mval_;
+ label_ = label;
+ this->set_collapsed(false);
}
-
-/* -------------------------------------------------------------------- */
-/* Drawer */
-
-DatasetRegionDrawer::DatasetRegionDrawer(const ARegion *region,
- uiBlock &block,
- DatasetDrawContext &draw_context)
- : row_height(UI_UNIT_Y),
- xmin(region->v2d.cur.xmin),
- xmax(region->v2d.cur.xmax),
- block(block),
- v2d(region->v2d),
- draw_context(draw_context)
+GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
+ AttributeDomain domain,
+ StringRef label,
+ BIFIconID icon)
+ : component_type_(component_type), domain_(domain), icon_(icon)
{
+ label_ = label;
}
-void DatasetRegionDrawer::draw_hierarchy(const DatasetLayoutHierarchy &layout)
+void GeometryDataSetTreeViewItem::on_activate()
{
- for (const DatasetComponentLayoutInfo &component : layout.components) {
- draw_context.current_geometry_set = draw_context.geometry_set_from_component(component.type);
-
- draw_component_row(component);
-
- /* Iterate attribute domains, skip unset ones (storage has to be in a enum-based, fixed size
- * array so uses optionals to support skipping enum values that shouldn't be displayed for a
- * component). */
- for (const auto &optional_domain : component.attr_domains) {
- if (!optional_domain) {
- continue;
- }
-
- const DatasetAttrDomainLayoutInfo &domain_info = *optional_domain;
- draw_attribute_domain_row(component, domain_info);
- }
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ bContext &C = const_cast<bContext &>(tree_view.C_);
+ SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
+ tree_view.sspreadsheet_.geometry_component_type = component_type_;
+ if (domain_) {
+ tree_view.sspreadsheet_.attribute_domain = *domain_;
}
+ PointerRNA ptr;
+ RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet, &ptr);
+ RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain"));
+ RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type"));
}
-static int element_count_from_volume(const GeometrySet &geometry_set)
+void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
{
- if (const Volume *volume = geometry_set.get_volume_for_read()) {
- return BKE_volume_num_grids(volume);
+ uiItemL(&row, label_.c_str(), icon_);
+
+ if (const std::optional<int> count = this->count()) {
+ /* Using the tree row button instead of a separate right aligned button gives padding
+ * to the right side of the number, which it didn't have with the button. */
+ char element_count[7];
+ BLI_str_format_attribute_domain_size(element_count, *count);
+ UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count);
}
- return 0;
}
-static int element_count_from_component_domain(const GeometrySet &geometry_set,
- GeometryComponentType component,
- AttributeDomain domain)
+std::optional<bool> GeometryDataSetTreeViewItem::should_be_active() const
{
- if (geometry_set.has_mesh() && component == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
- return mesh_component->attribute_domain_size(domain);
- }
-
- if (geometry_set.has_pointcloud() && component == GEO_COMPONENT_TYPE_POINT_CLOUD) {
- const PointCloudComponent *point_cloud_component =
- geometry_set.get_component_for_read<PointCloudComponent>();
- return point_cloud_component->attribute_domain_size(domain);
- }
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
- if (geometry_set.has_volume() && component == GEO_COMPONENT_TYPE_VOLUME) {
- const VolumeComponent *volume_component =
- geometry_set.get_component_for_read<VolumeComponent>();
- return volume_component->attribute_domain_size(domain);
+ if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) {
+ return sspreadsheet.geometry_component_type == component_type_;
}
- if (geometry_set.has_curve() && component == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- return curve_component->attribute_domain_size(domain);
+ if (!domain_) {
+ return false;
}
- if (geometry_set.has_instances() && component == GEO_COMPONENT_TYPE_INSTANCES) {
- const InstancesComponent *instances_component =
- geometry_set.get_component_for_read<InstancesComponent>();
- return instances_component->attribute_domain_size(domain);
- }
-
- return 0;
+ return sspreadsheet.geometry_component_type == component_type_ &&
+ sspreadsheet.attribute_domain == *domain_;
}
-void DatasetRegionDrawer::draw_dataset_row(const int indentation,
- const GeometryComponentType component,
- const std::optional<AttributeDomain> domain,
- BIFIconID icon,
- const char *label,
- const bool is_active)
+bool GeometryDataSetTreeViewItem::supports_collapsing() const
{
+ return false;
+}
- const float row_height = UI_UNIT_Y;
- const float padding_x = UI_UNIT_X * 0.25f;
-
- const rctf rect = {float(xmin) + padding_x,
- float(xmax) - V2D_SCROLL_HANDLE_WIDTH,
- ymin_offset - row_height,
- ymin_offset};
-
- char element_count[7];
- if (component == GEO_COMPONENT_TYPE_VOLUME) {
- BLI_str_format_attribute_domain_size(
- element_count, element_count_from_volume(draw_context.current_geometry_set));
- }
- else {
- BLI_str_format_attribute_domain_size(
- element_count,
- domain ? element_count_from_component_domain(
- draw_context.current_geometry_set, component, *domain) :
- 0);
- }
+GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const
+{
+ return static_cast<GeometryDataSetTreeView &>(this->get_tree_view());
+}
- std::string label_and_element_count = label;
- label_and_element_count += UI_SEP_CHAR;
- label_and_element_count += element_count;
-
- uiBut *bt = uiDefIconTextButO(&block,
- UI_BTYPE_DATASETROW,
- "SPREADSHEET_OT_change_spreadsheet_data_source",
- WM_OP_INVOKE_DEFAULT,
- icon,
- label,
- rect.xmin,
- rect.ymin,
- BLI_rctf_size_x(&rect),
- BLI_rctf_size_y(&rect),
- nullptr);
-
- UI_but_datasetrow_indentation_set(bt, indentation);
-
- if (is_active) {
- UI_but_hint_drawstr_set(bt, element_count);
- UI_but_datasetrow_component_set(bt, component);
- if (domain) {
- UI_but_datasetrow_domain_set(bt, *domain);
- }
- UI_but_func_pushed_state_set(bt, &is_component_row_selected, draw_context.sspreadsheet);
+std::optional<int> GeometryDataSetTreeViewItem::count() const
+{
+ GeometryDataSetTreeView &tree_view = this->get_tree();
+ GeometrySet &geometry = tree_view.geometry_set_;
- PointerRNA *but_ptr = UI_but_operator_ptr_get((uiBut *)bt);
- RNA_int_set(but_ptr, "component_type", component);
- if (domain) {
- RNA_int_set(but_ptr, "attribute_domain_type", *domain);
+ /* Special case for volumes since there is no grid domain. */
+ if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) {
+ if (const Volume *volume = geometry.get_volume_for_read()) {
+ return BKE_volume_num_grids(volume);
}
+ return 0;
}
- ymin_offset -= row_height;
-}
-
-void DatasetRegionDrawer::draw_component_row(const DatasetComponentLayoutInfo &component_info)
-{
- if (component_info.type == GEO_COMPONENT_TYPE_INSTANCES) {
- draw_dataset_row(0,
- component_info.type,
- ATTR_DOMAIN_INSTANCE,
- component_info.icon,
- component_info.label,
- true);
- }
- else if (component_info.type == GEO_COMPONENT_TYPE_VOLUME) {
- draw_dataset_row(
- 0, component_info.type, std::nullopt, component_info.icon, component_info.label, true);
+ if (!domain_) {
+ return std::nullopt;
}
- else {
- draw_dataset_row(
- 0, component_info.type, std::nullopt, component_info.icon, component_info.label, false);
+
+ if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
+ return component->attribute_domain_size(*domain_);
}
-}
-void DatasetRegionDrawer::draw_attribute_domain_row(
- const DatasetComponentLayoutInfo &component_info,
- const DatasetAttrDomainLayoutInfo &domain_info)
-{
- draw_dataset_row(
- 1, component_info.type, domain_info.type, domain_info.icon, domain_info.label, true);
+ return 0;
}
-/* -------------------------------------------------------------------- */
-/* Drawer */
-
-void draw_dataset_in_region(const bContext *C, ARegion *region)
+void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel)
{
- DatasetDrawContext draw_context{C};
- if (!draw_context.object_eval) {
- /* No object means nothing to display. Keep the region empty. */
+ const SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
+ Object *object = spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C));
+ if (!object) {
return;
}
+ uiLayout *layout = panel->layout;
- uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
-
- DatasetRegionDrawer drawer{region, *block, draw_context};
+ uiBlock *block = uiLayoutGetBlock(layout);
- /* Start with an offset to align buttons to spreadsheet rows. Use spreadsheet drawing info for
- * that. */
- drawer.ymin_offset = -SpreadsheetDrawer().top_row_height + drawer.row_height;
+ UI_block_layout_set_current(block, layout);
- const DatasetLayoutHierarchy hierarchy = dataset_layout_hierarchy();
- drawer.draw_hierarchy(hierarchy);
-#ifndef NDEBUG
- dataset_layout_hierarchy_sanity_check(hierarchy);
-#endif
+ ui::AbstractTreeView *tree_view = UI_block_add_view(
+ *block,
+ "Data Set Tree View",
+ std::make_unique<GeometryDataSetTreeView>(
+ spreadsheet_get_display_geometry_set(sspreadsheet, object), *C));
- UI_block_end(C, block);
- UI_view2d_totRect_set(&region->v2d, region->winx, abs(drawer.ymin_offset));
- UI_block_draw(C, block);
+ ui::TreeViewBuilder builder(*block);
+ builder.build_tree_view(*tree_view);
}
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
index 19906d73e7f..4a604533f11 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh
@@ -16,49 +16,11 @@
#pragma once
-#include <array>
-
-#include "BKE_geometry_set.hh"
-#include "UI_interface.h"
-#include "spreadsheet_dataset_layout.hh"
-
-struct ARegion;
-struct View2D;
+struct Panel;
struct bContext;
-struct uiBlock;
namespace blender::ed::spreadsheet {
-class DatasetDrawContext;
-
-class DatasetRegionDrawer {
- public:
- const int row_height;
- float ymin_offset = 0;
-
- int xmin;
- int xmax;
- uiBlock &block;
- const View2D &v2d;
- DatasetDrawContext &draw_context;
-
- DatasetRegionDrawer(const ARegion *region, uiBlock &block, DatasetDrawContext &draw_context);
-
- void draw_hierarchy(const DatasetLayoutHierarchy &layout);
-
- void draw_attribute_domain_row(const DatasetComponentLayoutInfo &component,
- const DatasetAttrDomainLayoutInfo &domain_info);
- void draw_component_row(const DatasetComponentLayoutInfo &component_info);
-
- private:
- void draw_dataset_row(const int indentation,
- const GeometryComponentType component,
- const std::optional<AttributeDomain> domain,
- const BIFIconID icon,
- const char *label,
- const bool is_active);
-};
-
-void draw_dataset_in_region(const bContext *C, ARegion *region);
+void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel);
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
deleted file mode 100644
index f15af2e4d32..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <optional>
-
-#include "BLI_span.hh"
-
-#include "BLT_translation.h"
-
-#include "spreadsheet_dataset_layout.hh"
-
-namespace blender::ed::spreadsheet {
-
-#define ATTR_INFO(type, label, icon) \
- std::optional<DatasetAttrDomainLayoutInfo> \
- { \
- std::in_place, type, label, icon \
- }
-#define ATTR_INFO_NONE(type) \
- { \
- std::nullopt \
- }
-
-/**
- * Definition for the component->attribute-domain hierarchy.
- * Constructed at compile time.
- *
- * \warning Order of attribute-domains matters! It __must__ match the #AttributeDomain
- * definition and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use
- * array designators for this (which C++ doesn't support).
- */
-constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = {
- {
- GEO_COMPONENT_TYPE_MESH,
- N_("Mesh"),
- ICON_MESH_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Vertex"), ICON_VERTEXSEL),
- ATTR_INFO(ATTR_DOMAIN_EDGE, N_("Edge"), ICON_EDGESEL),
- ATTR_INFO(ATTR_DOMAIN_FACE, N_("Face"), ICON_FACESEL),
- ATTR_INFO(ATTR_DOMAIN_CORNER, N_("Face Corner"), ICON_NODE_CORNER),
- },
- },
- {
- GEO_COMPONENT_TYPE_CURVE,
- N_("Curves"),
- ICON_CURVE_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Control Point"), ICON_CURVE_BEZCIRCLE),
- ATTR_INFO_NONE(ATTR_DOMAIN_EDGE),
- ATTR_INFO_NONE(ATTR_DOMAIN_CORNER),
- ATTR_INFO_NONE(ATTR_DOMAIN_FACE),
- ATTR_INFO(ATTR_DOMAIN_CURVE, N_("Spline"), ICON_CURVE_PATH),
- },
- },
- {
- GEO_COMPONENT_TYPE_POINT_CLOUD,
- N_("Point Cloud"),
- ICON_POINTCLOUD_DATA,
- {
- ATTR_INFO(ATTR_DOMAIN_POINT, N_("Point"), ICON_PARTICLE_POINT),
- },
- },
- {
- GEO_COMPONENT_TYPE_VOLUME,
- N_("Volume Grids"),
- ICON_VOLUME_DATA,
- {},
- },
- {
- GEO_COMPONENT_TYPE_INSTANCES,
- N_("Instances"),
- ICON_EMPTY_AXIS,
- {},
- },
-};
-
-#undef ATTR_INFO
-#undef ATTR_INFO_LABEL
-
-DatasetLayoutHierarchy dataset_layout_hierarchy()
-{
- return DatasetLayoutHierarchy{
- Span{DATASET_layout_hierarchy, ARRAY_SIZE(DATASET_layout_hierarchy)}};
-}
-
-#ifndef NDEBUG
-/**
- * Debug-only sanity check for correct attribute domain initialization (order/indices must
- * match AttributeDomain). This doesn't check for all possible missuses, but should catch the most
- * likely mistakes.
- */
-void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy)
-{
- for (const DatasetComponentLayoutInfo &component : hierarchy.components) {
- for (uint i = 0; i < component.attr_domains.size(); i++) {
- if (component.attr_domains[i]) {
- BLI_assert(component.attr_domains[i]->type == static_cast<AttributeDomain>(i));
- }
- }
- }
-}
-#endif
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh
deleted file mode 100644
index d463739a0fa..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include <array>
-#include <optional>
-
-/* Enum definitions... */
-#include "BKE_attribute.h"
-#include "BKE_geometry_set.h"
-
-#include "BLI_span.hh"
-
-/* More enum definitions... */
-#include "UI_resources.h"
-
-#pragma once
-
-namespace blender::ed::spreadsheet {
-
-struct DatasetAttrDomainLayoutInfo {
- AttributeDomain type;
- const char *label;
- BIFIconID icon;
-
- constexpr DatasetAttrDomainLayoutInfo(AttributeDomain type, const char *label, BIFIconID icon)
- : type(type), label(label), icon(icon)
- {
- }
-};
-
-struct DatasetComponentLayoutInfo {
- GeometryComponentType type;
- const char *label;
- BIFIconID icon;
- /** Array of attribute-domains. Has to be fixed size based on #AttributeDomain enum, but not all
- * values need displaying for all parent components. Hence the optional use. */
- using AttrDomainArray = std::array<std::optional<DatasetAttrDomainLayoutInfo>, ATTR_DOMAIN_NUM>;
- const AttrDomainArray attr_domains;
-};
-
-struct DatasetLayoutHierarchy {
- /** The components for display (with layout info like icon and label). Each component stores
- * the attribute domains it wants to display (also with layout info like icon and label). */
- const Span<DatasetComponentLayoutInfo> components;
-};
-
-DatasetLayoutHierarchy dataset_layout_hierarchy();
-
-#ifndef NDEBUG
-void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy);
-#endif
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
index b911c80fa63..857aa20da92 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
@@ -27,6 +27,8 @@
#include "spreadsheet_draw.hh"
+#define CELL_RIGHT_PADDING (2.0f * UI_DPI_FAC)
+
namespace blender::ed::spreadsheet {
SpreadsheetDrawer::SpreadsheetDrawer()
@@ -159,7 +161,7 @@ static void draw_left_column_content(const int scroll_offset_y,
params.xmin = 0;
params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
scroll_offset_y;
- params.width = drawer.left_column_width;
+ params.width = drawer.left_column_width - CELL_RIGHT_PADDING;
params.height = drawer.row_height;
drawer.draw_left_column_cell(row_index, params);
}
@@ -194,7 +196,7 @@ static void draw_top_row_content(const bContext *C,
params.block = first_row_block;
params.xmin = left_x;
params.ymin = region->winy - drawer.top_row_height;
- params.width = column_width;
+ params.width = column_width - CELL_RIGHT_PADDING;
params.height = drawer.top_row_height;
drawer.draw_top_row_cell(column_index, params);
@@ -242,7 +244,7 @@ static void draw_cell_contents(const bContext *C,
params.xmin = left_x;
params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
scroll_offset_y;
- params.width = column_width;
+ params.width = column_width - CELL_RIGHT_PADDING;
params.height = drawer.row_height;
drawer.draw_content_cell(row_index, column_index, params);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
index 8b050c2e69b..e62835d5792 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
@@ -37,6 +37,7 @@ struct SpaceSpreadsheet_Runtime {
};
struct bContext;
+struct ARegionType;
void spreadsheet_operatortypes(void);
void spreadsheet_update_context_path(const bContext *C);
@@ -45,6 +46,8 @@ Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet,
namespace blender::ed::spreadsheet {
GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
- Object *object_eval,
- const GeometryComponentType used_component_type);
-}
+ Object *object_eval);
+
+void spreadsheet_data_set_region_panels_register(ARegionType &region_type);
+
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 202523c0e64..7cc2d8d0b48 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -17,8 +17,16 @@
#include <iomanip>
#include <sstream>
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+
+#include "BKE_geometry_set.hh"
+
+#include "spreadsheet_column_values.hh"
#include "spreadsheet_layout.hh"
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "UI_interface.h"
@@ -92,13 +100,14 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
{
const int real_index = spreadsheet_layout_.row_indices[row_index];
const ColumnValues &column = *spreadsheet_layout_.columns[column_index].values;
- CellValue cell_value;
- if (real_index < column.size()) {
- column.get_value(real_index, cell_value);
+ if (real_index > column.size()) {
+ return;
}
- if (cell_value.value_int.has_value()) {
- const int value = *cell_value.value_int;
+ const fn::GVArray &data = column.data();
+
+ if (data.type().is<int>()) {
+ const int value = data.get<int>(real_index);
const std::string value_str = std::to_string(value);
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -119,8 +128,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
}
- else if (cell_value.value_float.has_value()) {
- const float value = *cell_value.value_float;
+ else if (data.type().is<float>()) {
+ const float value = data.get<float>(real_index);
std::stringstream ss;
ss << std::fixed << std::setprecision(3) << value;
const std::string value_str = ss.str();
@@ -143,8 +152,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
}
- else if (cell_value.value_bool.has_value()) {
- const bool value = *cell_value.value_bool;
+ else if (data.type().is<bool>()) {
+ const bool value = data.get<bool>(real_index);
const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
@@ -163,87 +172,81 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
nullptr);
UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT);
}
- else if (cell_value.value_float2.has_value()) {
- const float2 value = *cell_value.value_float2;
+ else if (data.type().is<float2>()) {
+ const float2 value = data.get<float2>(real_index);
this->draw_float_vector(params, Span(&value.x, 2));
}
- else if (cell_value.value_float3.has_value()) {
- const float3 value = *cell_value.value_float3;
+ else if (data.type().is<float3>()) {
+ const float3 value = data.get<float3>(real_index);
this->draw_float_vector(params, Span(&value.x, 3));
}
- else if (cell_value.value_color.has_value()) {
- const ColorGeometry4f value = *cell_value.value_color;
+ else if (data.type().is<ColorGeometry4f>()) {
+ const ColorGeometry4f value = data.get<ColorGeometry4f>(real_index);
this->draw_float_vector(params, Span(&value.r, 4));
}
- else if (cell_value.value_object.has_value()) {
- const ObjectCellValue value = *cell_value.value_object;
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_OBJECT_DATA,
- reinterpret_cast<const ID *const>(value.object)->name + 2,
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_collection.has_value()) {
- const CollectionCellValue value = *cell_value.value_collection;
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_OUTLINER_COLLECTION,
- reinterpret_cast<const ID *const>(value.collection)->name + 2,
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_geometry_set.has_value()) {
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_MESH_DATA,
- "Geometry",
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
- }
- else if (cell_value.value_string.has_value()) {
- uiDefIconTextBut(params.block,
- UI_BTYPE_LABEL,
- 0,
- ICON_NONE,
- cell_value.value_string->c_str(),
- params.xmin,
- params.ymin,
- params.width,
- params.height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- nullptr);
+ else if (data.type().is<InstanceReference>()) {
+ const InstanceReference value = data.get<InstanceReference>(real_index);
+ switch (value.type()) {
+ case InstanceReference::Type::Object: {
+ const Object &object = value.object();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_OBJECT_DATA,
+ object.id.name + 2,
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::Collection: {
+ Collection &collection = value.collection();
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_OUTLINER_COLLECTION,
+ collection.id.name + 2,
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::GeometrySet: {
+ uiDefIconTextBut(params.block,
+ UI_BTYPE_LABEL,
+ 0,
+ ICON_MESH_DATA,
+ "Geometry",
+ params.xmin,
+ params.ymin,
+ params.width,
+ params.height,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullptr);
+ break;
+ }
+ case InstanceReference::Type::None: {
+ break;
+ }
+ }
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
index 1768af6ae09..f996cd99dad 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh
@@ -32,7 +32,7 @@ struct ColumnLayout {
/* Layout information for the entire spreadsheet. */
struct SpreadsheetLayout {
Vector<ColumnLayout> columns;
- Span<int64_t> row_indices;
+ IndexMask row_indices;
int index_column_width = 100;
};
diff --git a/source/blender/functions/FN_multi_function_parallel.hh b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
index 84c57efd434..854c3d4aba6 100644
--- a/source/blender/functions/FN_multi_function_parallel.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
@@ -14,26 +14,24 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#pragma once
+#include "BKE_screen.h"
-/** \file
- * \ingroup fn
- */
-
-#include "FN_multi_function.hh"
-
-namespace blender::fn {
+#include "BLT_translation.h"
-class ParallelMultiFunction : public MultiFunction {
- private:
- const MultiFunction &fn_;
- const int64_t grain_size_;
- bool threading_supported_;
+#include "spreadsheet_dataset_draw.hh"
+#include "spreadsheet_intern.hh"
- public:
- ParallelMultiFunction(const MultiFunction &fn, const int64_t grain_size);
+namespace blender::ed::spreadsheet {
- void call(IndexMask mask, MFParams params, MFContext context) const override;
-};
+void spreadsheet_data_set_region_panels_register(ARegionType &region_type)
+{
+ PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ strcpy(panel_type->idname, "SPREADSHEET_PT_data_set");
+ strcpy(panel_type->label, N_("Data Set"));
+ strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ panel_type->flag = PANEL_TYPE_NO_HEADER;
+ panel_type->draw = spreadsheet_data_set_panel_draw;
+ BLI_addtail(&region_type.paneltypes, panel_type);
+}
-} // namespace blender::fn
+} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 1e46fef8d71..a6a0266fcc1 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -18,7 +18,6 @@
#include "BLI_listbase.h"
-#include "DNA_collection_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -38,238 +37,197 @@
namespace blender::ed::spreadsheet {
-template<typename OperationFn>
-static void apply_filter_operation(const ColumnValues &values,
+template<typename T, typename OperationFn>
+static void apply_filter_operation(const VArray<T> &data,
OperationFn check_fn,
- MutableSpan<bool> rows_included)
+ const IndexMask mask,
+ Vector<int64_t> &new_indices)
{
- for (const int i : rows_included.index_range()) {
- if (!rows_included[i]) {
- continue;
- }
- CellValue cell_value;
- values.get_value(i, cell_value);
- if (!check_fn(cell_value)) {
- rows_included[i] = false;
+ for (const int64_t i : mask) {
+ if (check_fn(data[i])) {
+ new_indices.append(i);
}
}
}
-static void apply_row_filter(const SpreadsheetLayout &spreadsheet_layout,
- const SpreadsheetRowFilter &row_filter,
- MutableSpan<bool> rows_included)
+static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
+ const Map<StringRef, const ColumnValues *> &columns,
+ const IndexMask prev_mask,
+ Vector<int64_t> &new_indices)
{
- for (const ColumnLayout &column : spreadsheet_layout.columns) {
- const ColumnValues &values = *column.values;
- if (values.name() != row_filter.column_name) {
- continue;
+ const ColumnValues &column = *columns.lookup(row_filter.column_name);
+ const fn::GVArray &column_data = column.data();
+ if (column_data.type().is<float>()) {
+ const float value = row_filter.value_float;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return std::abs(cell - value) < threshold; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return cell > value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<float>(),
+ [&](const float cell) { return cell < value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
}
-
- switch (values.type()) {
- case SPREADSHEET_VALUE_TYPE_INT32: {
- const int value = row_filter.value_int;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int == value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int > value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_int < value;
- },
- rows_included);
- break;
- }
- }
+ }
+ else if (column_data.type().is<int>()) {
+ const int value = row_filter.value_int;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [&](const int cell) { return cell == value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT: {
- const float value = row_filter.value_float;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold = row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold](const CellValue &cell_value) -> bool {
- return std::abs(*cell_value.value_float - value) < threshold;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_float > value;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_float < value;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [value](const int cell) { return cell > value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT2: {
- const float2 value = row_filter.value_float2;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return float2::distance_squared(*cell_value.value_float2, value) <
- threshold_squared;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float2->x > value.x &&
- cell_value.value_float2->y > value.y;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float2->x < value.x &&
- cell_value.value_float2->y < value.y;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<int>(),
+ [&](const int cell) { return cell < value; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_FLOAT3: {
- const float3 value = row_filter.value_float3;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return float3::distance_squared(*cell_value.value_float3, value) <
- threshold_squared;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_GREATER: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float3->x > value.x &&
- cell_value.value_float3->y > value.y &&
- cell_value.value_float3->z > value.z;
- },
- rows_included);
- break;
- }
- case SPREADSHEET_ROW_FILTER_LESS: {
- apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return cell_value.value_float3->x < value.x &&
- cell_value.value_float3->y < value.y &&
- cell_value.value_float3->z < value.z;
- },
- rows_included);
- break;
- }
- }
+ }
+ }
+ else if (column_data.type().is<float2>()) {
+ const float2 value = row_filter.value_float2;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) {
+ return float2::distance_squared(cell, value) > threshold_sq;
+ },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_COLOR: {
- const ColorGeometry4f value = row_filter.value_color;
- switch (row_filter.operation) {
- case SPREADSHEET_ROW_FILTER_EQUAL: {
- const float threshold_squared = row_filter.threshold * row_filter.threshold;
- apply_filter_operation(
- values,
- [value, threshold_squared](const CellValue &cell_value) -> bool {
- return len_squared_v4v4(value, *cell_value.value_color) < threshold_squared;
- },
- rows_included);
- break;
- }
- }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; },
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_BOOL: {
- const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0;
+ case SPREADSHEET_ROW_FILTER_LESS: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_bool == value;
+ column_data.typed<float2>(),
+ [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
+ else if (column_data.type().is<float3>()) {
+ const float3 value = row_filter.value_float3;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return float3::distance_squared(cell, value) > threshold_sq;
},
- rows_included);
+ prev_mask,
+ new_indices);
break;
}
- case SPREADSHEET_VALUE_TYPE_INSTANCES: {
- const StringRef value = row_filter.value_string;
+ case SPREADSHEET_ROW_FILTER_GREATER: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- const ID *id = nullptr;
- if (cell_value.value_object) {
- id = &cell_value.value_object->object->id;
- }
- else if (cell_value.value_collection) {
- id = &cell_value.value_collection->collection->id;
- }
- if (id == nullptr) {
- return false;
- }
-
- return value == id->name + 2;
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return cell.x > value.x && cell.y > value.y && cell.z > value.z;
},
- rows_included);
+ prev_mask,
+ new_indices);
break;
}
- default:
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<float3>(),
+ [&](const float3 cell) {
+ return cell.x < value.x && cell.y < value.y && cell.z < value.z;
+ },
+ prev_mask,
+ new_indices);
break;
+ }
}
-
- /* Only one column should have this name. */
- break;
}
-}
-
-static void index_vector_from_bools(Span<bool> selection, Vector<int64_t> &indices)
-{
- for (const int i : selection.index_range()) {
- if (selection[i]) {
- indices.append(i);
+ else if (column_data.type().is<ColorGeometry4f>()) {
+ const ColorGeometry4f value = row_filter.value_color;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = row_filter.threshold;
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return len_squared_v4v4(cell, value) > threshold_sq;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
+ else if (column_data.type().is<InstanceReference>()) {
+ const StringRef value = row_filter.value_string;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<InstanceReference>(),
+ [&](const InstanceReference cell) {
+ switch (cell.type()) {
+ case InstanceReference::Type::Object: {
+ return value == (reinterpret_cast<ID &>(cell.object()).name + 2);
+ }
+ case InstanceReference::Type::Collection: {
+ return value == (reinterpret_cast<ID &>(cell.collection()).name + 2);
+ }
+ case InstanceReference::Type::GeometrySet: {
+ return false;
+ }
+ case InstanceReference::Type::None: {
+ return false;
+ }
+ }
+ BLI_assert_unreachable();
+ return false;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
}
}
}
@@ -297,10 +255,10 @@ static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet,
return true;
}
-Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
- const SpreadsheetLayout &spreadsheet_layout,
- const DataSource &data_source,
- ResourceScope &scope)
+IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope)
{
const int tot_rows = data_source.tot_rows();
@@ -309,29 +267,46 @@ Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
/* Avoid allocating an array if no row filtering is necessary. */
if (!(use_filters || use_selection)) {
- return IndexRange(tot_rows).as_span();
+ return IndexMask(tot_rows);
}
- Array<bool> rows_included(tot_rows, true);
+ IndexMask mask(tot_rows);
+
+ Vector<int64_t> mask_indices;
+ mask_indices.reserve(tot_rows);
+
+ if (use_selection) {
+ const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
+ &data_source);
+ mask = geometry_data_source->apply_selection_filter(mask_indices);
+ }
if (use_filters) {
+ Map<StringRef, const ColumnValues *> columns;
+ for (const ColumnLayout &column : spreadsheet_layout.columns) {
+ columns.add(column.values->name(), column.values);
+ }
+
LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) {
if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) {
- apply_row_filter(spreadsheet_layout, *row_filter, rows_included);
+ if (!columns.contains(row_filter->column_name)) {
+ continue;
+ }
+ Vector<int64_t> new_indices;
+ new_indices.reserve(mask_indices.size());
+ apply_row_filter(*row_filter, columns, mask, new_indices);
+ std::swap(new_indices, mask_indices);
+ mask = IndexMask(mask_indices);
}
}
}
- if (use_selection) {
- const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>(
- &data_source);
- geometry_data_source->apply_selection_filter(rows_included);
+ if (mask_indices.is_empty()) {
+ BLI_assert(mask.is_empty() || mask.is_range());
+ return mask;
}
- Vector<int64_t> &indices = scope.construct<Vector<int64_t>>();
- index_vector_from_bools(rows_included, indices);
-
- return indices;
+ return IndexMask(scope.add_value(std::move(mask_indices)));
}
SpreadsheetRowFilter *spreadsheet_row_filter_new()
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
index 0a5783e318d..3788baaa993 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh
@@ -23,10 +23,10 @@
namespace blender::ed::spreadsheet {
-Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
- const SpreadsheetLayout &spreadsheet_layout,
- const DataSource &data_source,
- ResourceScope &scope);
+IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
+ const SpreadsheetLayout &spreadsheet_layout,
+ const DataSource &data_source,
+ ResourceScope &scope);
SpreadsheetRowFilter *spreadsheet_row_filter_new();
SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
index a07abac4474..bcced7b5937 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -114,6 +114,8 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
}
case SPREADSHEET_VALUE_TYPE_STRING:
return row_filter.value_string;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ return "";
}
BLI_assert_unreachable();
return "";
@@ -238,6 +240,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_STRING:
+ uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
+ break;
+ case SPREADSHEET_VALUE_TYPE_UNKNOWN:
+ uiItemL(layout, IFACE_("Unkown column type"), ICON_ERROR);
break;
}
}
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index bf2a5534e0b..91a85e4c4b0 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -144,7 +144,6 @@ static void statusbar_header_region_message_subscribe(const wmRegionMessageSubsc
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_statusbar(void)
{
SpaceType *st = MEM_callocN(sizeof(*st), "spacetype statusbar");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index f8dc61f18f2..f449ce50ae3 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -417,7 +417,6 @@ static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
/********************* registration ********************/
-/* only called once, from space/spacetypes.c */
void ED_spacetype_text(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype text");
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index f8d16e396d4..8fb55ed9b46 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -200,7 +200,6 @@ int wrap_width(const SpaceText *st, ARegion *region)
return max > 8 ? max : 8;
}
-/* Sets (offl, offc) for transforming (line, curs) to its wrapped position */
void wrap_offset(
const SpaceText *st, ARegion *region, TextLine *linein, int cursin, int *offl, int *offc)
{
@@ -305,7 +304,6 @@ void wrap_offset(
}
}
-/* cursin - mem, offc - view */
void wrap_offset_in_line(
const SpaceText *st, ARegion *region, TextLine *linein, int cursin, int *offl, int *offc)
{
@@ -1671,7 +1669,7 @@ void draw_text_main(SpaceText *st, ARegion *region)
if (st->showlinenrs && !wrap_skip) {
/* Draw line number. */
- UI_FontThemeColor(tdc.font_id, (tmp == text->curl) ? TH_HILITE : TH_LINENUMBERS);
+ UI_FontThemeColor(tdc.font_id, (tmp == text->sell) ? TH_HILITE : TH_LINENUMBERS);
BLI_snprintf(linenr,
sizeof(linenr),
"%*d",
@@ -1754,8 +1752,6 @@ bool ED_text_activate_in_screen(bContext *C, Text *text)
return false;
}
-/* Moves the view to the cursor location,
- * also used to make sure the view isn't outside the file */
void ED_text_scroll_to_cursor(SpaceText *st, ARegion *region, const bool center)
{
Text *text;
@@ -1823,7 +1819,6 @@ void ED_text_scroll_to_cursor(SpaceText *st, ARegion *region, const bool center)
st->runtime.scroll_ofs_px[1] = 0;
}
-/* takes an area instead of a region, use for listeners */
void text_scroll_to_cursor__area(SpaceText *st, ScrArea *area, const bool center)
{
ARegion *region;
@@ -1847,9 +1842,6 @@ void text_update_cursor_moved(bContext *C)
text_scroll_to_cursor__area(st, area, true);
}
-/**
- * Takes a cursor (row, character) and returns x,y pixel coords.
- */
bool ED_text_region_location_from_cursor(SpaceText *st,
ARegion *region,
const int cursor_co[2],
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index 66765206fa6..cf0a7c089b5 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -111,7 +111,6 @@ void flatten_string_free(FlattenString *fs)
}
}
-/* takes a string within fs->buf and returns its length */
int flatten_string_strlen(FlattenString *fs, const char *str)
{
const int len = (fs->pos - (int)(str - fs->buf)) - 1;
@@ -119,8 +118,6 @@ int flatten_string_strlen(FlattenString *fs, const char *str)
return len;
}
-/* Ensures the format string for the given line is long enough, reallocating
- * as needed. Allocation is done here, alone, to ensure consistency. */
int text_check_format_len(TextLine *line, uint len)
{
if (line->format) {
@@ -142,12 +139,6 @@ int text_check_format_len(TextLine *line, uint len)
return 1;
}
-/**
- * Fill the string with formatting constant,
- * advancing \a str_p and \a fmt_p
- *
- * \param len: length in bytes of \a fmt_p to fill.
- */
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
{
const char *str = *str_p;
@@ -170,10 +161,6 @@ void text_format_fill(const char **str_p, char **fmt_p, const char type, const i
*str_p = str;
*fmt_p = fmt;
}
-/**
- * ascii version of #text_format_fill,
- * use when we no the text being stepped over is ascii (as is the case for most keywords)
- */
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len)
{
const char *str = *str_p;
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index fe7b3328030..01c40b4ed22 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -33,7 +33,9 @@ typedef struct FlattenString {
int pos, len;
} FlattenString;
-/* format continuation flags (stored just after the NULL terminator) */
+/**
+ * Format continuation flags (stored just after the NULL terminator).
+ */
enum {
FMT_CONT_NOP = 0, /* no continuation */
FMT_CONT_QUOTESINGLE = (1 << 0), /* single quotes */
@@ -48,10 +50,27 @@ enum {
int flatten_string(const struct SpaceText *st, FlattenString *fs, const char *in);
void flatten_string_free(FlattenString *fs);
+/**
+ * Takes a string within `fs->buf` and returns its length.
+ */
int flatten_string_strlen(FlattenString *fs, const char *str);
+/**
+ * Ensures the format string for the given line is long enough, reallocating
+ * as needed. Allocation is done here, alone, to ensure consistency.
+ */
int text_check_format_len(TextLine *line, unsigned int len);
+/**
+ * Fill the string with formatting constant,
+ * advancing \a str_p and \a fmt_p
+ *
+ * \param len: length in bytes of \a fmt_p to fill.
+ */
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len);
+/**
+ * ASCII version of #text_format_fill,
+ * use when we no the text being stepped over is ascii (as is the case for most keywords)
+ */
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len);
/* *** Generalize Formatting *** */
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 241e0133a8a..3cae4188932 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -39,6 +39,9 @@ void draw_text_main(struct SpaceText *st, struct ARegion *region);
void text_update_line_edited(struct TextLine *line);
void text_update_edited(struct Text *text);
void text_update_character_width(struct SpaceText *st);
+/**
+ * Takes an area instead of a region, use for listeners.
+ */
void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, const bool center);
void text_update_cursor_moved(struct bContext *C);
@@ -73,12 +76,18 @@ void text_update_cursor_moved(struct bContext *C);
#define TOOL_DOCUMENT 0x02
int wrap_width(const struct SpaceText *st, struct ARegion *region);
+/**
+ * Sets (offl, offc) for transforming (line, curs) to its wrapped position.
+ */
void wrap_offset(const struct SpaceText *st,
struct ARegion *region,
struct TextLine *linein,
int cursin,
int *offl,
int *offc);
+/**
+ * cursin - mem, offc - view.
+ */
void wrap_offset_in_line(const struct SpaceText *st,
struct ARegion *region,
struct TextLine *linein,
diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c
index 80af7d8c9f6..3e40593d40e 100644
--- a/source/blender/editors/space_text/text_undo.c
+++ b/source/blender/editors/space_text/text_undo.c
@@ -252,8 +252,6 @@ static void text_undosys_foreach_ID_ref(UndoStep *us_p,
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->text_ref));
}
-/* Export for ED_undo_sys. */
-
void ED_text_undosys_type(UndoType *ut)
{
ut->name = "Text";
@@ -276,7 +274,6 @@ void ED_text_undosys_type(UndoType *ut)
/** \name Utilities
* \{ */
-/* Use operator system to finish the undo step. */
UndoStep *ED_text_undo_push_init(bContext *C)
{
UndoStack *ustack = ED_undo_stack_get();
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 419721cf89e..7f0f30624cb 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -236,7 +237,59 @@ static void recent_files_menu_register(void)
WM_menutype_add(mt);
}
-/* only called once, from space/spacetypes.c */
+static void undo_history_draw_menu(const bContext *C, Menu *menu)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->undo_stack == NULL) {
+ return;
+ }
+ int undo_step_count = 0;
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next) {
+ if (us->skip) {
+ continue;
+ }
+ undo_step_count += 1;
+ }
+
+ uiLayout *split = uiLayoutSplit(menu->layout, 0.0f, false);
+ uiLayout *column = NULL;
+
+ const int col_size = 20 + (undo_step_count / 12);
+ int i = 0;
+
+ undo_step_count = 0;
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
+ if (us->skip) {
+ continue;
+ }
+ if (!(undo_step_count % col_size)) {
+ column = uiLayoutColumn(split, false);
+ }
+ const bool is_active = (us == wm->undo_stack->step_active);
+ uiLayout *row = uiLayoutRow(column, false);
+ uiLayoutSetEnabled(row, !is_active);
+ uiItemIntO(row,
+ IFACE_(us->name),
+ is_active ? ICON_LAYER_ACTIVE : ICON_NONE,
+ "ED_OT_undo_history",
+ "item",
+ i);
+ undo_step_count += 1;
+ }
+}
+
+static void undo_history_menu_register(void)
+{
+ MenuType *mt;
+
+ mt = MEM_callocN(sizeof(MenuType), __func__);
+ strcpy(mt->idname, "TOPBAR_MT_undo_history");
+ strcpy(mt->label, N_("Undo History"));
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = undo_history_draw_menu;
+ WM_menutype_add(mt);
+}
+
void ED_spacetype_topbar(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar");
@@ -279,6 +332,7 @@ void ED_spacetype_topbar(void)
BLI_addhead(&st->regiontypes, art);
recent_files_menu_register();
+ undo_history_menu_register();
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index ceba8ca268d..1711188fca7 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -199,7 +199,6 @@ static void userpref_execute_region_listener(const wmRegionListenerParams *UNUSE
{
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_userpref(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype userpref");
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index e54ef3c931a..8822ea6af3b 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -91,7 +91,6 @@
/* ******************** manage regions ********************* */
-/* function to always find a regionview3d context inside 3D window */
RegionView3D *ED_view3d_context_rv3d(bContext *C)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -108,8 +107,6 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C)
return rv3d;
}
-/* ideally would return an rv3d but in some cases the region is needed too
- * so return that, the caller can then access the region->regiondata */
bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_region)
{
ScrArea *area = CTX_wm_area(C);
@@ -140,10 +137,6 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_regi
return false;
}
-/**
- * Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
- * Also works if \a v3d is not the active space.
- */
bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion **r_region)
{
RegionView3D *rv3d = NULL;
@@ -182,17 +175,6 @@ bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion
return false;
}
-/* Most of the time this isn't needed since you could assume the view matrix was
- * set while drawing, however when functions like mesh_foreachScreenVert are
- * called by selection tools, we can't be sure this object was the last.
- *
- * for example, transparent objects are drawn after editmode and will cause
- * the rv3d mat's to change and break selection.
- *
- * 'ED_view3d_init_mats_rv3d' should be called before
- * view3d_project_short_clip and view3d_project_short_noclip in cases where
- * these functions are not used during draw_object
- */
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
{
/* local viewmat and persmat, to calculate projections */
@@ -214,7 +196,6 @@ void ED_view3d_init_mats_rv3d_gl(const struct Object *ob, struct RegionView3D *r
}
#ifdef DEBUG
-/* ensure we correctly initialize */
void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d)
{
zero_m4(rv3d->viewmatob);
@@ -1294,6 +1275,7 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
&RNA_Object,
&RNA_UnitSettings, /* grid-floor */
+ &RNA_View3DCursor,
&RNA_View3DOverlay,
&RNA_View3DShading,
&RNA_World,
@@ -1878,7 +1860,6 @@ static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new
}
}
-/* only called once, from space/spacetypes.c */
void ED_spacetype_view3d(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype view3d");
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 8380c87b999..535a65c8f0c 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -102,9 +102,6 @@ BLI_INLINE Object *view3d_cameracontrol_object(const View3DCameraControl *vctrl)
return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
}
-/**
- * Returns the object which is being manipulated or NULL.
- */
Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
{
RegionView3D *rv3d = vctrl->ctx_rv3d;
@@ -116,10 +113,6 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
return NULL;
}
-/**
- * Creates a #View3DCameraControl handle and sets up
- * the view for first-person style navigation.
- */
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph,
Scene *scene,
View3D *v3d,
@@ -243,9 +236,6 @@ static bool object_apply_mat4_with_protect(Object *ob,
return view_changed;
}
-/**
- * Updates cameras from the `rv3d` values, optionally auto-keyframing.
- */
void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
/* args for keyframing */
const bool use_autokey,
@@ -317,12 +307,6 @@ void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl,
}
}
-/**
- * Release view control.
- *
- * \param restore: Sets the view state to the values that were set
- * before #ED_view3d_control_acquire was called.
- */
void ED_view3d_cameracontrol_release(View3DCameraControl *vctrl, const bool restore)
{
View3D *v3d = vctrl->ctx_v3d;
diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
index ac80a70011a..f5abba2c674 100644
--- a/source/blender/editors/space_view3d/view3d_cursor_snap.c
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -94,7 +94,7 @@ typedef struct SnapCursorDataIntern {
} SnapCursorDataIntern;
static SnapCursorDataIntern g_data_intern = {
- .state_default = {.prevpoint = NULL,
+ .state_default = {.flag = V3D_SNAPCURSOR_SNAP_EDIT_GEOM_FINAL,
.snap_elem_force = SCE_SNAP_MODE_GEOM,
.plane_axis = 2,
.color_point = {255, 255, 255, 255},
@@ -104,6 +104,12 @@ static SnapCursorDataIntern g_data_intern = {
.draw_point = true}};
/**
+ * Dot products below this will be considered view aligned.
+ * In this case we can't usefully project the mouse cursor onto the plane.
+ */
+static const float eps_view_align = 1e-2f;
+
+/**
* Calculate a 3x3 orientation matrix from the surface under the cursor.
*/
static void v3d_cursor_poject_surface_normal(const float normal[3],
@@ -714,14 +720,19 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
float *co_depth = snap_elem ? co : scene->cursor.location;
snap_elem &= ~data_intern->snap_elem_hidden;
if (snap_elem == 0) {
- float plane[4];
- if (state->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) {
- const float *plane_normal = omat[state->plane_axis];
+ RegionView3D *rv3d = region->regiondata;
+ const float *plane_normal = omat[state->plane_axis];
+ bool do_plane_isect = (state->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) &&
+ (rv3d->is_persp ||
+ (fabsf(dot_v3v3(plane_normal, rv3d->viewinv[2])) > eps_view_align));
+
+ if (do_plane_isect) {
+ float plane[4];
plane_from_point_normal_v3(plane, co_depth, plane_normal);
+ do_plane_isect = ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, rv3d->is_persp, co);
}
- if ((state->plane_depth == V3D_PLACE_DEPTH_CURSOR_VIEW) ||
- !ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, true, co)) {
+ if (!do_plane_isect) {
ED_view3d_win_to_3d(v3d, region, co_depth, mval_fl, co);
}
@@ -919,6 +930,14 @@ static void v3d_cursor_snap_free(void)
void ED_view3d_cursor_snap_state_default_set(V3DSnapCursorState *state)
{
g_data_intern.state_default = *state;
+
+ /* These values are temporarily set by the tool.
+ * They are not convenient as default values.
+ * So reset to null. */
+ g_data_intern.state_default.gzgrp_type = NULL;
+ g_data_intern.state_default.prevpoint = NULL;
+ g_data_intern.state_default.draw_plane = false;
+ g_data_intern.state_default.draw_box = false;
}
V3DSnapCursorState *ED_view3d_cursor_snap_active(void)
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 6f6fa8b7576..a7d170982ed 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -108,9 +108,6 @@
/** \name General Functions
* \{ */
-/**
- * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
- */
void ED_view3d_update_viewmat(Depsgraph *depsgraph,
const Scene *scene,
View3D *v3d,
@@ -355,9 +352,6 @@ static void view3d_xr_mirror_setup(const wmWindowManager *wm,
}
#endif /* WITH_XR_OPENXR */
-/**
- * Set the correct matrices
- */
void ED_view3d_draw_setup_view(const wmWindowManager *wm,
wmWindow *win,
Depsgraph *depsgraph,
@@ -848,7 +842,6 @@ static void drawrenderborder(ARegion *region, View3D *v3d)
/** \name Other Elements
* \{ */
-/** could move this elsewhere, but tied into #ED_view3d_grid_scale */
float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit)
{
/* apply units */
@@ -921,9 +914,6 @@ void ED_view3d_grid_steps(const Scene *scene,
}
}
-/* Simulates the grid scale that is actually viewed.
- * The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
- * Currently the simulation is only done when RV3D_VIEW_IS_AXIS. */
float ED_view3d_grid_view_scale(Scene *scene,
View3D *v3d,
ARegion *region,
@@ -1472,9 +1462,6 @@ static void draw_grid_unit_name(
}
}
-/**
- * Information drawn on top of the solid plates and composed data
- */
void view3d_draw_region_info(const bContext *C, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -1751,10 +1738,6 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
G.f &= ~G_FLAG_RENDER_VIEWPORT;
}
-/**
- * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen). Similar too
- * #ED_view_draw_offscreen_imbuf_simple, but takes view/projection matrices as arguments.
- */
void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
Scene *scene,
View3DShading *shading_override,
@@ -1853,12 +1836,6 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
viewport);
}
-/**
- * Utility func for ED_view3d_draw_offscreen
- *
- * \param ofs: Optional off-screen buffer, can be NULL.
- * (avoids re-creating when doing multiple GL renders).
- */
ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
Scene *scene,
eDrawType drawtype,
@@ -2008,14 +1985,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
return ibuf;
}
-/**
- * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
- *
- * \param ofs: Optional off-screen buffer can be NULL.
- * (avoids re-creating when doing multiple GL renders).
- *
- * \note used by the sequencer
- */
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
Scene *scene,
View3DShading *shading_override,
@@ -2046,6 +2015,15 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
}
memcpy(&v3d.shading, source_shading_settings, sizeof(View3DShading));
+ if (drawtype == OB_RENDER) {
+ /* Don't use external engines for preview. Fall back to solid instead of Eevee as rendering
+ * with Eevee is potentially slow due to compiling shaders and loading textures, and the
+ * depsgraph may not have been updated to have all the right geometry attributes. */
+ if (!(BKE_scene_uses_blender_eevee(scene) || BKE_scene_uses_blender_workbench(scene))) {
+ drawtype = OB_SOLID;
+ }
+ }
+
if (drawtype == OB_MATERIAL) {
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
v3d.shading.render_pass = SCE_PASS_COMBINED;
@@ -2137,15 +2115,6 @@ static bool view3d_clipping_test(const float co[3], const float clip[6][4])
return true;
}
-/**
- * Return true when `co` is hidden by the 3D views clipping planes.
- *
- * \param local: When true use local (object-space) #ED_view3d_clipping_local must run first,
- * then all comparisons can be done in local-space.
- * \return True when `co` is outside all clipping planes.
- *
- * \note Callers should check #RV3D_CLIPPING_ENABLED first.
- */
bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
{
return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
@@ -2231,10 +2200,6 @@ void ED_view3d_select_id_validate(ViewContext *vc)
validate_object_select_id(vc->depsgraph, vc->view_layer, vc->region, vc->v3d, vc->obact);
}
-/**
- * allow for small values [0.5 - 2.5],
- * and large values, FLT_MAX by clamping by the area size
- */
int ED_view3d_backbuf_sample_size_clamp(ARegion *region, const float dist)
{
return (int)min_ff(ceilf(dist), (float)max_ii(region->winx, region->winx));
@@ -2311,7 +2276,6 @@ static ViewDepths *view3d_depths_create(ARegion *region)
return d;
}
-/* Utility function to find the closest Z value, use for auto-depth. */
float view3d_depth_near(ViewDepths *d)
{
/* Convert to float for comparisons. */
@@ -2335,14 +2299,6 @@ float view3d_depth_near(ViewDepths *d)
return far == far_real ? FLT_MAX : far;
}
-/**
- * Redraw the viewport depth buffer.
- *
- * \param mode: V3D_DEPTH_NO_GPENCIL - Redraw viewport without Grease Pencil and Annotations.
- * V3D_DEPTH_GPENCIL_ONLY - Redraw viewport with Grease Pencil and Annotations only.
- * V3D_DEPTH_OBJECT_ONLY - Redraw viewport with active object only.
- * \param update_cache: If true, store the entire depth buffer in #rv3d->depths.
- */
void ED_view3d_depth_override(Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -2457,7 +2413,6 @@ void ED_view3d_datamask(const bContext *C,
}
}
-/* Goes over all modes and view3d settings. */
void ED_view3d_screen_datamask(const bContext *C,
const Scene *scene,
const bScreen *screen,
@@ -2527,10 +2482,6 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto
/** \name FPS Drawing
* \{ */
-/**
- * \note The info that this uses is updated in #ED_refresh_viewport_fps,
- * which currently gets called during #SCREEN_OT_animation_step.
- */
void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset)
{
ScreenFrameRateInfo *fpsi = scene->fps_info;
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index b85b424405e..830f7cbeff1 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -618,7 +618,6 @@ enum {
VIEWROT_MODAL_SWITCH_ROTATE = 6,
};
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewrotate_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -1250,9 +1249,6 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof,
}
}
-/**
- * Called from both fly mode and walk mode,
- */
void view3d_ndof_fly(const wmNDOFMotionData *ndof,
View3D *v3d,
RegionView3D *rv3d,
@@ -1685,7 +1681,6 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewmove_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -1882,7 +1877,6 @@ void VIEW3D_OT_move(wmOperatorType *ot)
* \{ */
/* #viewdolly_modal_keymap has an exact copy of this, apply fixes to both. */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewzoom_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -2446,7 +2440,6 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
* \{ */
/* This is an exact copy of #viewzoom_modal_keymap. */
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void viewdolly_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -3059,6 +3052,23 @@ static int viewselected_exec(bContext *C, wmOperator *op)
if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) {
ok |= BKE_gpencil_stroke_minmax(gps, true, min, max);
}
+ if (gps->editcurve != NULL) {
+ for (int i = 0; i < gps->editcurve->tot_curve_points; i++) {
+ BezTriple *bezt = &gps->editcurve->curve_points[i].bezt;
+ if ((bezt->f1 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[0]);
+ ok = true;
+ }
+ if ((bezt->f2 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[1]);
+ ok = true;
+ }
+ if ((bezt->f3 & SELECT)) {
+ minmax_v3v3_v3(min, max, bezt->vec[2]);
+ ok = true;
+ }
+ }
+ }
}
CTX_DATA_END;
@@ -5010,7 +5020,6 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
* \{ */
/* cursor position in vec, result in vec, mval in region coords */
-/* NOTE: cannot use `event->mval` here, called by #object_add(). */
void ED_view3d_cursor3d_position(bContext *C,
const int mval[2],
const bool use_depth,
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index a21fc006b02..7388004125c 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -91,7 +91,13 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot);
+/**
+ * For home, center etc.
+ */
void view3d_boxview_copy(struct ScrArea *area, struct ARegion *region);
+/**
+ * Sync center/zoom view of region to others, for view transforms.
+ */
void view3d_boxview_sync(struct ScrArea *area, struct ARegion *region);
void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
@@ -103,6 +109,9 @@ void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
#ifdef WITH_INPUT_NDOF
struct wmNDOFMotionData;
+/**
+ * Called from both fly mode and walk mode,
+ */
void view3d_ndof_fly(const struct wmNDOFMotionData *ndof,
struct View3D *v3d,
struct RegionView3D *rv3d,
@@ -113,17 +122,24 @@ void view3d_ndof_fly(const struct wmNDOFMotionData *ndof,
#endif /* WITH_INPUT_NDOF */
/* view3d_navigate_fly.c */
+
void view3d_keymap(struct wmKeyConfig *keyconf);
void VIEW3D_OT_fly(struct wmOperatorType *ot);
/* view3d_navigate_walk.c */
+
void VIEW3D_OT_walk(struct wmOperatorType *ot);
/* view3d_draw.c */
+
void view3d_main_region_draw(const struct bContext *C, struct ARegion *region);
+/**
+ * Information drawn on top of the solid plates and composed data.
+ */
void view3d_draw_region_info(const struct bContext *C, struct ARegion *region);
/* view3d_draw_legacy.c */
+
void ED_view3d_draw_select_loop(struct Depsgraph *depsgraph,
ViewContext *vc,
Scene *scene,
@@ -139,6 +155,9 @@ void ED_view3d_draw_depth_loop(struct Depsgraph *depsgraph,
View3D *v3d);
void view3d_depths_rect_create(struct ARegion *region, struct rcti *rect, struct ViewDepths *r_d);
+/**
+ * Utility function to find the closest Z value, use for auto-depth.
+ */
float view3d_depth_near(struct ViewDepths *d);
/* view3d_select.c */
@@ -175,6 +194,9 @@ typedef struct V3D_SmoothParams {
const float *dyn_ofs;
} V3D_SmoothParams;
+/**
+ * The arguments are the desired situation.
+ */
void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
struct wmWindowManager *wm,
struct wmWindow *win,
@@ -190,20 +212,41 @@ void ED_view3d_smooth_view(struct bContext *C,
const int smooth_viewtx,
const V3D_SmoothParams *sview);
+/**
+ * Apply the smooth-view immediately, use when we need to start a new view operation.
+ * (so we don't end up half-applying a view operation when pressing keys quickly).
+ */
void ED_view3d_smooth_view_force_finish(struct bContext *C,
struct View3D *v3d,
struct ARegion *region);
+/**
+ * \param rect: optional for picking (can be NULL).
+ */
void view3d_winmatrix_set(struct Depsgraph *depsgraph,
struct ARegion *region,
const View3D *v3d,
const rcti *rect);
+/**
+ * Sets #RegionView3D.viewmat
+ *
+ * \param depsgraph: Depsgraph.
+ * \param scene: Scene for camera and cursor location.
+ * \param v3d: View 3D space data.
+ * \param rv3d: 3D region which stores the final matrices.
+ * \param rect_scale: Optional 2D scale argument,
+ * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument.
+ *
+ * \note don't set windows active in here, is used by renderwin too.
+ */
void view3d_viewmatrix_set(struct Depsgraph *depsgraph,
const struct Scene *scene,
const View3D *v3d,
RegionView3D *rv3d,
const float rect_scale[2]);
+/* Called in transform_ops.c, on each regeneration of key-maps. */
+
void fly_modal_keymap(struct wmKeyConfig *keyconf);
void walk_modal_keymap(struct wmKeyConfig *keyconf);
void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
@@ -213,23 +256,46 @@ void viewdolly_modal_keymap(struct wmKeyConfig *keyconf);
void viewplace_modal_keymap(struct wmKeyConfig *keyconf);
/* view3d_buttons.c */
+
void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot);
void view3d_buttons_register(struct ARegionType *art);
/* view3d_camera_control.c */
+
+/**
+ * Creates a #View3DCameraControl handle and sets up
+ * the view for first-person style navigation.
+ */
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(struct Depsgraph *depsgraph,
Scene *scene,
View3D *v3d,
RegionView3D *rv3d);
+/**
+ * Updates cameras from the `rv3d` values, optionally auto-keyframing.
+ */
void ED_view3d_cameracontrol_update(struct View3DCameraControl *vctrl,
const bool use_autokey,
struct bContext *C,
const bool do_rotate,
const bool do_translate);
+/**
+ * Release view control.
+ *
+ * \param restore: Sets the view state to the values that were set
+ * before #ED_view3d_control_acquire was called.
+ */
void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, const bool restore);
+/**
+ * Returns the object which is being manipulated or NULL.
+ */
struct Object *ED_view3d_cameracontrol_object_get(struct View3DCameraControl *vctrl);
/* view3d_snap.c */
+
+/**
+ * Calculates the bounding box corners (min and max) for \a obedit.
+ * The returned values are in global space.
+ */
bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]);
void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 20e00356152..16d9b9182cf 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -486,10 +486,6 @@ static void mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void *userData,
data->func(data->userData, eed, screen_co_a, screen_co_b, index);
}
-/**
- * A version of #mesh_foreachScreenEdge that clips the segment when
- * there is a clipping bounding box.
- */
void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
void (*func)(void *userData,
BMEdge *eed,
@@ -691,7 +687,6 @@ void nurbs_foreachScreenVert(ViewContext *vc,
/** \name Edit-Meta: For Each Screen Meta-Element
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
void mball_foreachScreenElem(struct ViewContext *vc,
void (*func)(void *userData,
struct MetaElem *ml,
@@ -756,7 +751,6 @@ void lattice_foreachScreenVert(ViewContext *vc,
/** \name Edit-Armature: For Each Screen Bone
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
void armature_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct EditBone *ebone,
@@ -824,8 +818,6 @@ void armature_foreachScreenBone(struct ViewContext *vc,
/** \name Pose: For Each Screen Bone
* \{ */
-/* ED_view3d_init_mats_rv3d must be called first */
-/* almost _exact_ copy of #armature_foreachScreenBone */
void pose_foreachScreenBone(struct ViewContext *vc,
void (*func)(void *userData,
struct bPoseChannel *pchan,
@@ -834,6 +826,8 @@ void pose_foreachScreenBone(struct ViewContext *vc,
void *userData,
const eV3DProjTest clip_flag)
{
+ /* Almost _exact_ copy of #armature_foreachScreenBone */
+
const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
const bArmature *arm_eval = ob_eval->data;
bPose *pose = vc->obact->pose;
diff --git a/source/blender/editors/space_view3d/view3d_navigate_fly.c b/source/blender/editors/space_view3d/view3d_navigate_fly.c
index f48e436e014..2e9cb419e2e 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_fly.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_fly.c
@@ -101,7 +101,6 @@ typedef enum eFlyPanState {
FLY_AXISLOCK_STATE_ACTIVE = 2,
} eFlyPanState;
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void fly_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 83b8c04acb6..ed76b10c95a 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -142,7 +142,6 @@ typedef enum eWalkLockState {
WALK_AXISLOCK_STATE_DONE = 3,
} eWalkLockState;
-/* Called in transform_ops.c, on each regeneration of key-maps. */
void walk_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 88efc530484..8c2e0df0275 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -43,9 +43,6 @@
/* Non Clipping Projection Functions
* ********************************* */
-/**
- * \note use #ED_view3d_ob_project_mat_get to get the projection matrix
- */
void ED_view3d_project_float_v2_m4(const ARegion *region,
const float co[3],
float r_co[2],
@@ -68,9 +65,6 @@ void ED_view3d_project_float_v2_m4(const ARegion *region,
}
}
-/**
- * \note use #ED_view3d_ob_project_mat_get to get projecting mat
- */
void ED_view3d_project_float_v3_m4(const ARegion *region,
const float co[3],
float r_co[3],
@@ -231,7 +225,6 @@ eV3DProjStatus ED_view3d_project_float_ex(const ARegion *region,
return ret;
}
-/* --- short --- */
eV3DProjStatus ED_view3d_project_short_global(const ARegion *region,
const float co[3],
short r_co[2],
@@ -240,7 +233,6 @@ eV3DProjStatus ED_view3d_project_short_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_short_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_short_object(const ARegion *region,
const float co[3],
short r_co[2],
@@ -251,7 +243,6 @@ eV3DProjStatus ED_view3d_project_short_object(const ARegion *region,
return ED_view3d_project_short_ex(region, rv3d->persmatob, true, co, r_co, flag);
}
-/* --- int --- */
eV3DProjStatus ED_view3d_project_int_global(const ARegion *region,
const float co[3],
int r_co[2],
@@ -260,7 +251,6 @@ eV3DProjStatus ED_view3d_project_int_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_int_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_int_object(const ARegion *region,
const float co[3],
int r_co[2],
@@ -271,7 +261,6 @@ eV3DProjStatus ED_view3d_project_int_object(const ARegion *region,
return ED_view3d_project_int_ex(region, rv3d->persmatob, true, co, r_co, flag);
}
-/* --- float --- */
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region,
const float co[3],
float r_co[2],
@@ -280,7 +269,6 @@ eV3DProjStatus ED_view3d_project_float_global(const ARegion *region,
RegionView3D *rv3d = region->regiondata;
return ED_view3d_project_float_ex(region, rv3d->persmat, false, co, r_co, flag);
}
-/* object space, use ED_view3d_init_mats_rv3d before calling */
eV3DProjStatus ED_view3d_project_float_object(const ARegion *region,
const float co[3],
float r_co[2],
@@ -304,9 +292,6 @@ float ED_view3d_pixel_size_no_ui_scale(const RegionView3D *rv3d, const float co[
return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize;
}
-/**
- * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
- */
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip)
{
float zfac = mul_project_m4_v3_zfac(rv3d->persmat, co);
@@ -330,9 +315,6 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
return zfac;
}
-/**
- * Calculate a depth value from `co` (result should only be used for comparison).
- */
float ED_view3d_calc_depth_for_comparison(const RegionView3D *rv3d, const float co[3])
{
if (rv3d->is_persp) {
@@ -388,22 +370,6 @@ bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float
return true;
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * ray_start is clipped by the view near limit so points in front of it are always in view.
- * In orthographic view the resulting ray_normal will match the view vector.
- * This version also returns the ray_co point of the ray on window plane, useful to fix precision
- * issues esp. with ortho view, where default ray_start is set rather far away.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near clipping value).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_co: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- * \param r_ray_start: The world-space starting point of the ray.
- * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
- * \return success, false if the ray is totally clipped.
- */
bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
@@ -426,19 +392,6 @@ bool ED_view3d_win_to_ray_clipped_ex(struct Depsgraph *depsgraph,
return true;
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * ray_start is clipped by the view near limit so points in front of it are always in view.
- * In orthographic view the resulting ray_normal will match the view vector.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near clipping value).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- * \param do_clip_planes: Optionally clip the start of the ray by the view clipping planes.
- * \return success, false if the ray is totally clipped.
- */
bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
@@ -451,17 +404,6 @@ bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
depsgraph, region, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes);
}
-/**
- * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space point where the ray intersects the window plane.
- * \param r_ray_normal: The normalized world-space direction of towards mval.
- *
- * \note Ignores view near/far clipping,
- * to take this into account use #ED_view3d_win_to_ray_clipped.
- */
void ED_view3d_win_to_ray(const ARegion *region,
const float mval[2],
float r_ray_start[3],
@@ -471,13 +413,6 @@ void ED_view3d_win_to_ray(const ARegion *region,
ED_view3d_win_to_vector(region, mval, r_ray_normal);
}
-/**
- * Calculate a normalized 3d direction vector from the viewpoint towards a global location.
- * In orthographic view the resulting vector will match the view vector.
- * \param rv3d: The region (used for the window width and height).
- * \param coord: The world-space location.
- * \param vec: The resulting normalized vector.
- */
void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float vec[3])
{
if (rv3d->is_persp) {
@@ -536,13 +471,6 @@ bool view3d_get_view_aligned_coordinate(ARegion *region,
}
#endif
-/**
- * Calculate a 3d location from 2d window coordinates.
- * \param region: The region (used for the window width and height).
- * \param depth_pt: The reference location used to calculate the Z depth.
- * \param mval: The area relative location (such as event->mval converted to floats).
- * \param r_out: The resulting world-space location.
- */
void ED_view3d_win_to_3d(const View3D *v3d,
const ARegion *region,
const float depth_pt[3],
@@ -636,13 +564,6 @@ bool ED_view3d_win_to_3d_on_plane_int(const ARegion *region,
return ED_view3d_win_to_3d_on_plane(region, plane, mval_fl, do_clip, r_out);
}
-/**
- * A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback
- * then maps this back to \a plane.
- *
- * This is intended to be used when \a plane is orthogonal to the views Z axis where
- * projecting the \a mval doesn't work well (or fail completely when exactly aligned).
- */
bool ED_view3d_win_to_3d_on_plane_with_fallback(const ARegion *region,
const float plane[4],
const float mval[2],
@@ -678,14 +599,6 @@ bool ED_view3d_win_to_3d_on_plane_with_fallback(const ARegion *region,
return true;
}
-/**
- * Calculate a 3d difference vector from 2d window offset.
- * note that #ED_view3d_calc_zfac() must be called first to determine
- * the depth used to calculate the delta.
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d difference (such as event->mval[0] - other_x).
- * \param out: The resulting world-space delta.
- */
void ED_view3d_win_to_delta(const ARegion *region,
const float mval[2],
float out[3],
@@ -702,16 +615,6 @@ void ED_view3d_win_to_delta(const ARegion *region,
out[2] = (rv3d->persinv[0][2] * dx + rv3d->persinv[1][2] * dy);
}
-/**
- * Calculate a 3d origin from 2d window coordinates.
- * \note Orthographic views have a less obvious origin,
- * Since far clip can be a very large value resulting in numeric precision issues,
- * the origin in this case is close to zero coordinate.
- *
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval converted to floats).
- * \param out: The resulting normalized world-space direction vector.
- */
void ED_view3d_win_to_origin(const ARegion *region, const float mval[2], float out[3])
{
RegionView3D *rv3d = region->regiondata;
@@ -733,19 +636,6 @@ void ED_view3d_win_to_origin(const ARegion *region, const float mval[2], float o
}
}
-/**
- * Calculate a 3d direction vector from 2d window coordinates.
- * This direction vector starts and the view in the direction of the 2d window coordinates.
- * In orthographic view all window coordinates yield the same vector.
- *
- * \note doesn't rely on ED_view3d_calc_zfac
- * for perspective view, get the vector direction to
- * the mouse cursor as a normalized vector.
- *
- * \param region: The region (used for the window width and height).
- * \param mval: The area relative 2d location (such as event->mval converted to floats).
- * \param out: The resulting normalized world-space direction vector.
- */
void ED_view3d_win_to_vector(const ARegion *region, const float mval[2], float out[3])
{
RegionView3D *rv3d = region->regiondata;
@@ -763,20 +653,6 @@ void ED_view3d_win_to_vector(const ARegion *region, const float mval[2], float o
normalize_v3(out);
}
-/**
- * Calculate a 3d segment from 2d window coordinates.
- * This ray_start is located at the viewpoint, ray_end is a far point.
- * ray_start and ray_end are clipped by the view near and far limits
- * so points along this line are always in view.
- * In orthographic view all resulting segments will be parallel.
- * \param region: The region (used for the window width and height).
- * \param v3d: The 3d viewport (used for near and far clipping range).
- * \param mval: The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start: The world-space starting point of the segment.
- * \param r_ray_end: The world-space end point of the segment.
- * \param do_clip_planes: Optionally clip the ray by the view clipping planes.
- * \return success, false if the segment is totally clipped.
- */
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
const ARegion *region,
View3D *v3d,
@@ -817,9 +693,6 @@ void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d,
mul_m4_m4m4(r_pmat, rv3d->winmat, vmat);
}
-/**
- * Convert between region relative coordinates (x,y) and depth component z and
- * a point in world space. */
void ED_view3d_project_v3(const struct ARegion *region, const float world[3], float r_region_co[3])
{
/* Viewport is set up to make coordinates relative to the region, not window. */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 18820039c7f..cc8aac21a6e 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -119,9 +119,10 @@ float ED_view3d_select_dist_px(void)
return 75.0f * U.pixelsize;
}
-/* TODO: should return whether there is valid context to continue */
void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
{
+ /* TODO: should return whether there is valid context to continue. */
+
memset(vc, 0, sizeof(ViewContext));
vc->C = C;
vc->region = CTX_wm_region(C);
@@ -1279,40 +1280,6 @@ static bool do_lasso_select_paintface(ViewContext *vc,
return changed;
}
-#if 0
-static void do_lasso_select_node(int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
-{
- SpaceNode *snode = area->spacedata.first;
-
- bNode *node;
- rcti rect;
- int node_cent[2];
- float node_centf[2];
- bool changed = false;
-
- BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
-
- /* store selection in temp test flag */
- for (node = snode->edittree->nodes.first; node; node = node->next) {
- node_centf[0] = BLI_RCT_CENTER_X(&node->totr);
- node_centf[1] = BLI_RCT_CENTER_Y(&node->totr);
-
- ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
- const bool is_select = node->flag & SELECT;
- const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) &&
- BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1]));
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT);
- changed = true;
- }
- }
- if (changed) {
- BIF_undo_push("Lasso select nodes");
- }
-}
-#endif
-
static bool view3d_lasso_select(bContext *C,
ViewContext *vc,
const int mcoords[][2],
@@ -2229,7 +2196,6 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
return basact;
}
-/* mval comes from event->mval, only use within region handlers */
Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
return ed_view3d_give_base_under_cursor_ex(C, mval, NULL);
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 583a9ad75c2..53bd181f544 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -1013,10 +1013,6 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
/** \name Min/Max Object Vertices Utility
* \{ */
-/**
- * Calculates the bounding box corners (min and max) for \a obedit.
- * The returned values are in global space.
- */
bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
{
TransVertStore tvs = {NULL};
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index d6a1cd930fc..8b75ce63cde 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -122,9 +122,6 @@ void ED_view3d_dist_range_get(const View3D *v3d, float r_dist_range[2])
r_dist_range[1] = v3d->clip_end * 10.0f;
}
-/**
- * \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
- */
bool ED_view3d_clip_range_get(Depsgraph *depsgraph,
const View3D *v3d,
const RegionView3D *rv3d,
@@ -191,10 +188,6 @@ bool ED_view3d_viewplane_get(Depsgraph *depsgraph,
/** \name View State/Context Utilities
* \{ */
-/**
- * Use this call when executing an operator,
- * event system doesn't set for each event the OpenGL drawing context.
- */
void view3d_operator_needs_opengl(const bContext *C)
{
wmWindow *win = CTX_wm_window(C);
@@ -218,9 +211,6 @@ void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *region)
}
}
-/**
- * Use instead of: `GPU_polygon_offset(rv3d->dist, ...)` see bug T37727.
- */
void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
{
if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
@@ -339,18 +329,6 @@ static void points_in_planes_minmax_fn(
minmax_v3v3_v3(user_data->min, user_data->max, co);
}
-/**
- * Clamp min/max by the viewport clipping.
- *
- * \note This is an approximation, with the limitation that the bounding box from the (mix, max)
- * calculation might not have any geometry inside the clipped region.
- * Performing a clipping test on each vertex would work well enough for most cases,
- * although it's not perfect either as edges/faces may intersect the clipping without having any
- * of their vertices inside it.
- * A more accurate result would be quite involved.
- *
- * \return True when the arguments were clamped.
- */
bool ED_view3d_clipping_clamp_minmax(const RegionView3D *rv3d, float min[3], float max[3])
{
/* 6 planes for the cube, 4..6 for the current view clipping planes. */
@@ -481,9 +459,6 @@ bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_center_cursor || v3d->ob_center);
}
-/**
- * Use to store the last view, before entering camera view.
- */
void ED_view3d_lastview_store(RegionView3D *rv3d)
{
copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
@@ -503,13 +478,6 @@ void ED_view3d_lock_clear(View3D *v3d)
v3d->flag2 &= ~V3D_LOCK_CAMERA;
}
-/**
- * For viewport operators that exit camera perspective.
- *
- * \note This differs from simply setting `rv3d->persp = persp` because it
- * sets the `ofs` and `dist` values of the viewport so it matches the camera,
- * otherwise switching out of camera view may jump to a different part of the scene.
- */
void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph,
View3D *v3d,
RegionView3D *rv3d,
@@ -528,12 +496,6 @@ void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph,
rv3d->persp = persp;
}
}
-/**
- * Action to take when rotating the view,
- * handle auto-perspective and logic for switching out of views.
- *
- * shared with NDOF.
- */
bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -569,19 +531,12 @@ bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *re
* Lock the camera to the 3D Viewport, allowing view manipulation to transform the camera.
* \{ */
-/**
- * \return true when the 3D Viewport is locked to its camera.
- */
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return ((v3d->camera) && (!ID_IS_LINKED(v3d->camera)) && (v3d->flag2 & V3D_LOCK_CAMERA) &&
(rv3d->persp == RV3D_CAMOB));
}
-/**
- * Apply the camera object transformation to the 3D Viewport.
- * (needed so we can use regular 3D Viewport manipulation operators, that sync back to the camera).
- */
void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph,
View3D *v3d,
RegionView3D *rv3d,
@@ -603,11 +558,6 @@ void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionV
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, true);
}
-/**
- * Apply the 3D Viewport transformation back to the camera object.
- *
- * \return true if the camera is moved.
- */
bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
{
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
@@ -701,12 +651,6 @@ bool ED_view3d_camera_autokey(const Scene *scene,
return false;
}
-/**
- * Call after modifying a locked view.
- *
- * \note Not every view edit currently auto-keys (num-pad for eg),
- * this is complicated because of smooth-view.
- */
bool ED_view3d_camera_lock_autokey(View3D *v3d,
RegionView3D *rv3d,
struct bContext *C,
@@ -885,7 +829,6 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_
}
}
-/* sync center/zoom view of region to others, for view transforms */
void view3d_boxview_sync(ScrArea *area, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -910,7 +853,6 @@ void view3d_boxview_sync(ScrArea *area, ARegion *region)
}
}
-/* for home, center etc */
void view3d_boxview_copy(ScrArea *area, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -935,7 +877,6 @@ void view3d_boxview_copy(ScrArea *area, ARegion *region)
}
}
-/* 'clip' is used to know if our clip setting has changed */
void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
{
ARegion *region_sync = NULL;
@@ -1023,14 +964,6 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int
return depth_close;
}
-/**
- * Get the world-space 3d location from a screen-space 2d point.
- * TODO: Implement #alphaoverride. We don't want to zoom into billboards.
- *
- * \param mval: Input screen-space pixel location.
- * \param mouse_worldloc: Output world-space location.
- * \param fallback_depth_pt: Use this points depth when no depth can be found.
- */
bool ED_view3d_autodist(Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
@@ -1069,7 +1002,6 @@ bool ED_view3d_autodist(Depsgraph *depsgraph,
return false;
}
-/* no 4x4 sampling, run #ED_view3d_depth_override first */
bool ED_view3d_autodist_simple(ARegion *region,
const int mval[2],
float mouse_worldloc[3],
@@ -1127,7 +1059,7 @@ bool ED_view3d_depth_read_cached_seg(
data.vd = vd;
data.margin = margin;
- data.depth = FLT_MAX;
+ data.depth = 1.0f;
copy_v2_v2_int(p1, mval_sta);
copy_v2_v2_int(p2, mval_end);
@@ -1136,7 +1068,7 @@ bool ED_view3d_depth_read_cached_seg(
*depth = data.depth;
- return (*depth != FLT_MAX);
+ return (*depth != 1.0f);
}
/** \} */
@@ -1157,31 +1089,6 @@ float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
return radius / (DEFAULT_SENSOR_WIDTH / lens);
}
-/**
- * Return a new RegionView3D.dist value to fit the \a radius.
- *
- * \note Depth isn't taken into account, this will fit a flat plane exactly,
- * but points towards the view (with a perspective projection),
- * may be within the radius but outside the view. eg:
- *
- * <pre>
- * +
- * pt --> + /^ radius
- * / |
- * / |
- * view + +
- * \ |
- * \ |
- * \|
- * +
- * </pre>
- *
- * \param region: Can be NULL if \a use_aspect is false.
- * \param persp: Allow the caller to tell what kind of perspective to use (ortho/view/camera)
- * \param use_aspect: Increase the distance to account for non 1:1 view aspect.
- * \param radius: The radius will be fitted exactly,
- * typically pre-scaled by a margin (#VIEW3D_MARGIN).
- */
float ED_view3d_radius_to_dist(const View3D *v3d,
const ARegion *region,
const struct Depsgraph *depsgraph,
@@ -1262,18 +1169,6 @@ float ED_view3d_radius_to_dist(const View3D *v3d,
/** \name View Distance Utilities
* \{ */
-/**
- * This function solves the problem of having to switch between camera and non-camera views.
- *
- * When viewing from the perspective of \a mat, and having the view center \a ofs,
- * this calculates a distance from \a ofs to the matrix \a mat.
- * Using \a fallback_dist when the distance would be too small.
- *
- * \param mat: A matrix use for the view-point (typically the camera objects matrix).
- * \param ofs: Orbit center (negated), matching #RegionView3D.ofs, which is typically passed in.
- * \param fallback_dist: The distance to use if the object is too near or in front of \a ofs.
- * \returns A newly calculated distance or the fallback.
- */
float ED_view3d_offset_distance(const float mat[4][4],
const float ofs[3],
const float fallback_dist)
@@ -1295,11 +1190,6 @@ float ED_view3d_offset_distance(const float mat[4][4],
return dist;
}
-/**
- * Set the dist without moving the view (compensate with #RegionView3D.ofs)
- *
- * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first.
- */
void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
{
float viewinv[4];
@@ -1320,13 +1210,6 @@ void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
rv3d->dist = dist;
}
-/**
- * Change the distance & offset to match the depth of \a dist_co along the view axis.
- *
- * \param dist_co: A world-space location to use for the new depth.
- * \param dist_min: Resulting distances below this will be ignored.
- * \return Success if the distance was set.
- */
bool ED_view3d_distance_set_from_location(RegionView3D *rv3d,
const float dist_co[3],
const float dist_min)
@@ -1485,14 +1368,6 @@ bool ED_view3d_lock(RegionView3D *rv3d)
/** \name View Transform Utilities
* \{ */
-/**
- * Set the view transformation from a 4x4 matrix.
- *
- * \param mat: The view 4x4 transformation matrix to assign.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
{
float nmat[3][3];
@@ -1519,14 +1394,6 @@ void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const
}
}
-/**
- * Calculate the view transformation matrix from RegionView3D input.
- * The resulting matrix is equivalent to RegionView3D.viewinv
- * \param mat: The view 4x4 transformation matrix to calculate.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
{
const float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
@@ -1537,14 +1404,6 @@ void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], c
sub_v3_v3v3(mat[3], dvec, ofs);
}
-/**
- * Set the RegionView3D members from an objects transformation and optionally lens.
- * \param ob: The object to set the view to.
- * \param ofs: The view offset to be set, normally from RegionView3D.ofs.
- * \param quat: The view rotation to be set, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs to be set, normally from RegionView3D.dist.
- * \param lens: The view lens angle set for cameras and lights, normally from View3D.lens.
- */
void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
{
ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
@@ -1558,15 +1417,6 @@ void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float
}
}
-/**
- * Set the object transformation from RegionView3D members.
- * \param depsgraph: The depsgraph to get the evaluated object parent
- * for the transformation calculation.
- * \param ob: The object which has the transformation assigned.
- * \param ofs: The view offset, normally from RegionView3D.ofs.
- * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat.
- * \param dist: The view distance from ofs, normally from RegionView3D.dist.
- */
void ED_view3d_to_object(const Depsgraph *depsgraph,
Object *ob,
const float ofs[3],
@@ -1647,6 +1497,9 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd,
int margin,
float *r_depth)
{
+ BLI_assert(1.0 <= vd->depth_range[1]);
+ *r_depth = 1.0f;
+
if (!vd || !vd->depths) {
return false;
}
@@ -1676,15 +1529,11 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd,
depth = vd->depths[y * vd->w + x];
}
- BLI_assert(1.0 <= vd->depth_range[1]);
if (depth != 1.0f) {
*r_depth = depth;
return true;
}
- /* Grease-pencil and annotations also need the returned depth value to be high
- * so the caller can detect it's invalid. */
- *r_depth = FLT_MAX;
return false;
}
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 6f0ce6c9326..165f931394d 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -123,7 +123,6 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms
}
/* will start timer if appropriate */
-/* the arguments are the desired situation */
void ED_view3d_smooth_view_ex(
/* avoid passing in the context */
const Depsgraph *depsgraph,
@@ -407,10 +406,6 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
return OPERATOR_FINISHED;
}
-/**
- * Apply the smooth-view immediately, use when we need to start a new view operation.
- * (so we don't end up half-applying a view operation when pressing keys quickly).
- */
void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *region)
{
RegionView3D *rv3d = region->regiondata;
@@ -696,21 +691,18 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
/** \name Window and View Matrix Calculation
* \{ */
-/**
- * \param rect: optional for picking (can be NULL).
- */
void view3d_winmatrix_set(Depsgraph *depsgraph,
ARegion *region,
const View3D *v3d,
const rcti *rect)
{
RegionView3D *rv3d = region->regiondata;
- rctf viewplane;
+ rctf full_viewplane;
float clipsta, clipend;
bool is_ortho;
is_ortho = ED_view3d_viewplane_get(
- depsgraph, v3d, rv3d, region->winx, region->winy, &viewplane, &clipsta, &clipend, NULL);
+ depsgraph, v3d, rv3d, region->winx, region->winy, &full_viewplane, &clipsta, &clipend, NULL);
rv3d->is_persp = !is_ortho;
#if 0
@@ -718,21 +710,29 @@ void view3d_winmatrix_set(Depsgraph *depsgraph,
__func__,
winx,
winy,
- viewplane.xmin,
- viewplane.ymin,
- viewplane.xmax,
- viewplane.ymax,
+ full_viewplane.xmin,
+ full_viewplane.ymin,
+ full_viewplane.xmax,
+ full_viewplane.ymax,
clipsta,
clipend);
#endif
- if (rect) { /* picking */
- rctf r;
- r.xmin = viewplane.xmin + (BLI_rctf_size_x(&viewplane) * (rect->xmin / (float)region->winx));
- r.ymin = viewplane.ymin + (BLI_rctf_size_y(&viewplane) * (rect->ymin / (float)region->winy));
- r.xmax = viewplane.xmin + (BLI_rctf_size_x(&viewplane) * (rect->xmax / (float)region->winx));
- r.ymax = viewplane.ymin + (BLI_rctf_size_y(&viewplane) * (rect->ymax / (float)region->winy));
- viewplane = r;
+ /* Note the code here was tweaked to avoid an apparent compiler bug in clang 13 (see T91680). */
+ rctf viewplane;
+ if (rect) {
+ /* Smaller viewplane subset for selection picking. */
+ viewplane.xmin = full_viewplane.xmin +
+ (BLI_rctf_size_x(&full_viewplane) * (rect->xmin / (float)region->winx));
+ viewplane.ymin = full_viewplane.ymin +
+ (BLI_rctf_size_y(&full_viewplane) * (rect->ymin / (float)region->winy));
+ viewplane.xmax = full_viewplane.xmin +
+ (BLI_rctf_size_x(&full_viewplane) * (rect->xmax / (float)region->winx));
+ viewplane.ymax = full_viewplane.ymin +
+ (BLI_rctf_size_y(&full_viewplane) * (rect->ymax / (float)region->winy));
+ }
+ else {
+ viewplane = full_viewplane;
}
if (is_ortho) {
@@ -761,18 +761,6 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat);
}
-/**
- * Sets #RegionView3D.viewmat
- *
- * \param depsgraph: Depsgraph.
- * \param scene: Scene for camera and cursor location.
- * \param v3d: View 3D space data.
- * \param rv3d: 3D region which stores the final matrices.
- * \param rect_scale: Optional 2D scale argument,
- * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument.
- *
- * \note don't set windows active in here, is used by renderwin too.
- */
void view3d_viewmatrix_set(Depsgraph *depsgraph,
const Scene *scene,
const View3D *v3d,
@@ -862,11 +850,6 @@ void view3d_viewmatrix_set(Depsgraph *depsgraph,
/** \name OpenGL Select Utilities
* \{ */
-/**
- * Optionally cache data for multiple calls to #view3d_opengl_select
- *
- * just avoid GPU_select headers outside this file
- */
void view3d_opengl_select_cache_begin(void)
{
GPU_select_cache_begin();
@@ -943,13 +926,6 @@ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void
return ob_pose_list && (BLI_linklist_index(ob_pose_list, DEG_get_original_object(ob)) != -1);
}
-/**
- * \warning be sure to account for a negative return value
- * This is an error, "Too many objects in select buffer"
- * and no action should be taken (can crash blender) if this happens
- *
- * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
- */
int view3d_opengl_select_ex(ViewContext *vc,
uint *buffer,
uint bufsize,
@@ -1621,11 +1597,6 @@ static void view3d_local_collections_reset(Main *bmain, const uint local_view_bi
}
}
-/**
- * See if current uuid is valid, otherwise set a valid uuid to v3d,
- * Try to keep the same uuid previously used to allow users to
- * quickly toggle back and forth.
- */
bool ED_view3d_local_collections_set(Main *bmain, struct View3D *v3d)
{
if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index ae4c3f02c46..386fd85213e 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -668,7 +668,6 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
return true;
}
-/* Called in transform_ops.c, on each regeneration of key-maps. */
wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
@@ -1449,9 +1448,6 @@ static void drawTransformPixel(const struct bContext *C, ARegion *region, void *
}
}
-/**
- * \see #initTransform which reads values from the operator.
- */
void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1670,11 +1666,6 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2])
}
}
-/**
- * \note caller needs to free 't' on a 0 return
- * \warning \a event might be NULL (when tweaking from redo panel)
- * \see #saveTransform which writes these values back.
- */
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
{
int options = 0;
@@ -1987,7 +1978,6 @@ int transformEnd(bContext *C, TransInfo *t)
return exit_code;
}
-/* TODO: move to: `transform_query.c`. */
bool checkUseAxisMatrix(TransInfo *t)
{
/* currently only checks for editmode */
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index d78cd13f8b8..3035d11d0e3 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -298,6 +298,10 @@ enum {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Transform Types
+ * \{ */
+
typedef struct TransSnapPoint {
struct TransSnapPoint *next, *prev;
float co[3];
@@ -608,7 +612,7 @@ typedef struct TransInfo {
* mouse button then.) */
bool is_launch_event_tweak;
- bool is_orient_set;
+ bool is_orient_default_overwrite;
struct {
short type;
@@ -687,11 +691,19 @@ typedef struct TransInfo {
/** \name Public Transform API
* \{ */
+/**
+ * \note caller needs to free `t` on a 0 return
+ * \warning \a event might be NULL (when tweaking from redo panel)
+ * \see #saveTransform which writes these values back.
+ */
bool initTransform(struct bContext *C,
struct TransInfo *t,
struct wmOperator *op,
const struct wmEvent *event,
int mode);
+/**
+ * \see #initTransform which reads values from the operator.
+ */
void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op);
int transformEvent(TransInfo *t, const struct wmEvent *event);
void transformApply(struct bContext *C, TransInfo *t);
@@ -708,6 +720,9 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float vec[2]);
void removeAspectRatio(TransInfo *t, float vec[2]);
+/**
+ * Called in transform_ops.c, on each regeneration of key-maps.
+ */
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
/** \} */
@@ -772,12 +787,28 @@ void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float val
/** \name Generics
* \{ */
+/**
+ * Setup internal data, mouse, vectors
+ *
+ * \note \a op and \a event can be NULL
+ *
+ * \see #saveTransform does the reverse.
+ */
void initTransInfo(struct bContext *C,
TransInfo *t,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Needed for mode switching.
+ */
void freeTransCustomDataForMode(TransInfo *t);
+/**
+ * Here I would suggest only #TransInfo related issues, like free data & reset vars. Not redraws.
+ */
void postTrans(struct bContext *C, TransInfo *t);
+/**
+ * Free data before switching to another mode.
+ */
void resetTransModal(TransInfo *t);
void resetTransRestrictions(TransInfo *t);
@@ -800,17 +831,25 @@ void calculateCenterMedian(TransInfo *t, float r_center[3]);
void calculateCenterCursor(TransInfo *t, float r_center[3]);
void calculateCenterCursor2D(TransInfo *t, float r_center[2]);
void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2]);
+/**
+ * \param select_only: only get active center from data being transformed.
+ */
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]);
void calculatePropRatio(TransInfo *t);
+/**
+ * Rotate an element, low level code, ignore protected channels.
+ * (use for objects or pose-bones)
+ * Similar to #ElementRotation.
+ */
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
struct Object *transform_object_deform_pose_armature_get(const TransInfo *t, struct Object *ob);
void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
-/* TODO: `transform_query.c`. */
+/* TODO: move to: `transform_query.c`. */
bool checkUseAxisMatrix(TransInfo *t);
#define TRANSFORM_SNAP_MAX_PX 100.0f
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index a24491119c6..ede4c3e458c 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -295,10 +295,6 @@ static void constraint_snap_plane_to_edge(const TransInfo *t, const float plane[
}
}
-/**
- * Snap to the nearest point between the snap point and the line that
- * intersects the face plane with the constraint plane.
- */
static void UNUSED_FUNCTION(constraint_snap_plane_to_face(const TransInfo *t,
const float plane[4],
float r_out[3]))
@@ -314,9 +310,6 @@ static void UNUSED_FUNCTION(constraint_snap_plane_to_face(const TransInfo *t,
}
}
-/**
- * Snap to the nearest point on the axis to the edge/line element.
- */
void transform_constraint_snap_axis_to_edge(const TransInfo *t,
const float axis[3],
float r_out[3])
@@ -331,9 +324,6 @@ void transform_constraint_snap_axis_to_edge(const TransInfo *t,
}
}
-/**
- * Snap to the intersection of the axis and the plane defined by the face.
- */
void transform_constraint_snap_axis_to_face(const TransInfo *t,
const float axis[3],
float r_out[3])
@@ -700,7 +690,6 @@ void setConstraint(TransInfo *t, int mode, const char text[])
t->redraw = TREDRAW_HARD;
}
-/* applies individual td->axismtx constraints */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
{
BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
@@ -728,12 +717,6 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
}
}
-/**
- * Set the constraint according to the user defined orientation
- *
- * `ftext` is a format string passed to #BLI_snprintf. It will add the name of
- * the orientation where %s is (logically).
- */
void setUserConstraint(TransInfo *t, int mode, const char ftext[])
{
char text[256];
@@ -842,7 +825,6 @@ void drawConstraint(TransInfo *t)
}
}
-/* called from drawview.c, as an extra per-window draw option */
void drawPropCircle(const struct bContext *C, TransInfo *t)
{
if (t->flag & T_PROP_EDIT) {
@@ -1200,13 +1182,6 @@ bool isLockConstraint(const TransInfo *t)
return false;
}
-/**
- * Returns the dimension of the constraint space.
- *
- * For that reason, the flags always needs to be set to properly evaluate here,
- * even if they aren't actually used in the callback function.
- * (Which could happen for weird constraints not yet designed. Along a path for example.)
- */
int getConstraintSpaceDimension(const TransInfo *t)
{
int n = 0;
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index 3632b352476..12151f9df07 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -26,17 +26,35 @@
struct TransInfo;
void constraintNumInput(TransInfo *t, float vec[3]);
+/**
+ * Snap to the nearest point on the axis to the edge/line element.
+ */
void transform_constraint_snap_axis_to_edge(const TransInfo *t,
const float axis[3],
float r_out[3]);
+/**
+ * Snap to the intersection of the axis and the plane defined by the face.
+ */
void transform_constraint_snap_axis_to_face(const TransInfo *t,
const float axis[3],
float r_out[3]);
void setConstraint(TransInfo *t, int mode, const char text[]);
+/**
+ * Applies individual `td->axismtx` constraints.
+ */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
void setLocalConstraint(TransInfo *t, int mode, const char text[]);
+/**
+ * Set the constraint according to the user defined orientation
+ *
+ * `ftext` is a format string passed to #BLI_snprintf. It will add the name of
+ * the orientation where %s is (logically).
+ */
void setUserConstraint(TransInfo *t, int mode, const char text[]);
void drawConstraint(TransInfo *t);
+/**
+ * Called from drawview.c, as an extra per-window draw option.
+ */
void drawPropCircle(const struct bContext *C, TransInfo *t);
void startConstraint(TransInfo *t);
void stopConstraint(TransInfo *t);
@@ -47,4 +65,11 @@ void setNearestAxis(TransInfo *t);
int constraintModeToIndex(const TransInfo *t);
char constraintModeToChar(const TransInfo *t);
bool isLockConstraint(const TransInfo *t);
+/**
+ * Returns the dimension of the constraint space.
+ *
+ * For that reason, the flags always needs to be set to properly evaluate here,
+ * even if they aren't actually used in the callback function.
+ * (Which could happen for weird constraints not yet designed. Along a path for example.)
+ */
int getConstraintSpaceDimension(const TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index ff20f569a71..8f3d13176a3 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -68,10 +68,6 @@ bool transform_mode_use_local_origins(const TransInfo *t)
return ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL);
}
-/**
- * Transforming around ourselves is no use, fallback to individual origins,
- * useful for curve/armatures.
- */
void transform_around_single_fallback_ex(TransInfo *t, int data_len_all)
{
if (data_len_all != 1) {
@@ -369,7 +365,6 @@ static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
return changed;
}
-/* change the chain-length of auto-ik */
void transform_autoik_update(TransInfo *t, short mode)
{
Main *bmain = CTX_data_main(t->context);
@@ -482,7 +477,6 @@ void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic)
BLI_LINKSTACK_FREE(queue);
}
-/* Utility function for getting the handle data from bezier's */
TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt)
{
TransDataCurveHandleFlags *hdata;
@@ -611,9 +605,6 @@ void clipUVData(TransInfo *t)
/** \name Animation Editors (General)
* \{ */
-/**
- * Used for `TFM_TIME_EXTEND`.
- */
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
{
char r_dir;
@@ -636,7 +627,6 @@ char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
return r_dir;
}
-/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
bool FrameOnMouseSide(char side, float frame, float cframe)
{
/* both sides, so it doesn't matter */
@@ -667,14 +657,6 @@ typedef struct tRetainedKeyframe {
size_t del_count; /* number of keyframes of this sort that have been deleted so far */
} tRetainedKeyframe;
-/**
- * Called during special_aftertrans_update to make sure selected keyframes replace
- * any other keyframes which may reside on that frame (that is not selected).
- *
- * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
- * but may want to use a different one at times (if caller does not operate on
- * selection).
- */
void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_handle)
{
/* NOTE: We assume that all keys are sorted */
@@ -798,12 +780,6 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand
/** \name Transform Utilities
* \{ */
-/* Little helper function for ObjectToTransData used to give certain
- * constraints (ChildOf, FollowPath, and others that may be added)
- * inverse corrections for transform, so that they aren't in CrazySpace.
- * These particular constraints benefit from this, but others don't, hence
- * this semi-hack ;-) - Aligorith
- */
bool constraints_list_needinv(TransInfo *t, ListBase *list)
{
bConstraint *con;
@@ -894,14 +870,12 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
/** \name Transform (After-Transform Update)
* \{ */
-/* inserting keys, pointcache, redraw events... */
-/**
- * \note Sequencer freeing has its own function now because of a conflict
- * with transform's order of freeing (campbell).
- * Order changed, the sequencer stuff should go back in here
- */
void special_aftertrans_update(bContext *C, TransInfo *t)
{
+ /* NOTE: Sequencer freeing has its own function now because of a conflict
+ * with transform's order of freeing (campbell).
+ * Order changed, the sequencer stuff should go back in here. */
+
/* early out when nothing happened */
if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
return;
@@ -1609,7 +1583,6 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
}
}
-/* for the realtime animation recording feature, handle overlapping data */
void animrecord_check_state(TransInfo *t, struct Object *ob)
{
Scene *scene = t->scene;
@@ -1708,7 +1681,6 @@ void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const fl
}
}
-/* called for updating while transform acts, once per redraw */
void recalcData(TransInfo *t)
{
switch (t->data_type) {
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index e4f2ab05bec..5ed8182857d 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -36,47 +36,101 @@ struct TransInfo;
struct bContext;
/* transform_convert.c */
+
+/**
+ * Change the chain-length of auto-IK.
+ */
void transform_autoik_update(TransInfo *t, short mode);
int special_transform_moving(TransInfo *t);
+/**
+ * Inserting keys, point-cache, redraw events.
+ */
void special_aftertrans_update(struct bContext *C, TransInfo *t);
void sort_trans_data_dist(TransInfo *t);
void createTransData(struct bContext *C, TransInfo *t);
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
void clipUVData(TransInfo *t);
void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac);
+/**
+ * Called for updating while transform acts, once per redraw.
+ */
void recalcData(TransInfo *t);
/* transform_convert_mesh.c */
+
void transform_convert_mesh_customdatacorrect_init(TransInfo *t);
/* transform_convert_sequencer.c */
+
void transform_convert_sequencer_channel_clamp(TransInfo *t, float r_val[2]);
/********************* intern **********************/
/* transform_convert.c */
+
bool transform_mode_use_local_origins(const TransInfo *t);
+/**
+ * Transforming around ourselves is no use, fallback to individual origins,
+ * useful for curve/armatures.
+ */
void transform_around_single_fallback_ex(TransInfo *t, int data_len_all);
void transform_around_single_fallback(TransInfo *t);
+/**
+ * Called during special_aftertrans_update to make sure selected keyframes replace
+ * any other keyframes which may reside on that frame (that is not selected).
+ *
+ * \param sel_flag: The flag (bezt.f1/2/3) value to use to determine selection. Usually `SELECT`,
+ * but may want to use a different one at times (if caller does not operate on
+ * selection).
+ */
void posttrans_fcurve_clean(struct FCurve *fcu, const int sel_flag, const bool use_handle);
+/**
+ * Little helper function for ObjectToTransData used to give certain
+ * constraints (ChildOf, FollowPath, and others that may be added)
+ * inverse corrections for transform, so that they aren't in CrazySpace.
+ * These particular constraints benefit from this, but others don't, hence
+ * this semi-hack ;-) - Aligorith
+ */
bool constraints_list_needinv(TransInfo *t, ListBase *list);
void calc_distanceCurveVerts(TransData *head, TransData *tail, bool cyclic);
+/**
+ * Utility function for getting the handle data from bezier's.
+ */
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
+/**
+ * Used for `TFM_TIME_EXTEND`.
+ */
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
+/**
+ * This function tests if a point is on the "mouse" side of the cursor/frame-marking.
+ */
bool FrameOnMouseSide(char side, float frame, float cframe);
void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
+/**
+ * For the realtime animation recording feature, handle overlapping data.
+ */
void animrecord_check_state(TransInfo *t, struct Object *ob);
/* transform_convert_action.c */
+
void createTransActionData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Action Editor transforms */
void recalcData_actedit(TransInfo *t);
void special_aftertrans_update__actedit(bContext *C, TransInfo *t);
/* transform_convert_armature.c */
+
+/**
+ * Sets transform flags in the bones.
+ * Returns total number of bones with #BONE_TRANSFORM.
+ */
int transform_convert_pose_transflags_update(Object *ob,
const int mode,
const short around,
bool has_translate_rotate[2]);
+/**
+ * When objects array is NULL, use 't->data_container' as is.
+ */
void createTransPose(TransInfo *t);
void createTransArmatureVerts(TransInfo *t);
void recalcData_edit_armature(TransInfo *t);
@@ -84,6 +138,7 @@ void recalcData_pose(TransInfo *t);
void special_aftertrans_update__pose(bContext *C, TransInfo *t);
/* transform_convert_cursor.c */
+
void createTransCursor_image(TransInfo *t);
void createTransCursor_sequencer(TransInfo *t);
void createTransCursor_view3d(TransInfo *t);
@@ -92,16 +147,28 @@ void recalcData_cursor_sequencer(TransInfo *t);
void recalcData_cursor_view3d(TransInfo *t);
/* transform_convert_curve.c */
+
void createTransCurveVerts(TransInfo *t);
void recalcData_curve(TransInfo *t);
/* transform_convert_graph.c */
+/**
+ * It is important to note that this doesn't always act on the selection (like it's usually done),
+ * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
+ * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
+ * selected left or right handles accordingly.
+ * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
+ * functions may need to be made aware of this. It's ugly that these act based on selection state
+ * anyway.
+ */
void createTransGraphEditData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Graph Editor transforms */
void recalcData_graphedit(TransInfo *t);
void special_aftertrans_update__graph(bContext *C, TransInfo *t);
/* transform_convert_gpencil.c */
void createTransGPencil(bContext *C, TransInfo *t);
+/* force recalculation of triangles during transformation */
void recalcData_gpencil_strokes(TransInfo *t);
/* transform_convert_lattice.c */
@@ -146,6 +213,11 @@ void transform_convert_mesh_islands_calc(struct BMEditMesh *em,
const bool calc_island_axismtx,
struct TransIslandData *r_island_data);
void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data);
+/**
+ * \param mtx: Measure distance in this space.
+ * \param dists: Store the closest connected distance to selected vertices.
+ * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
+ */
void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
const float mtx[3][3],
float *dists,
@@ -156,6 +228,10 @@ void transform_convert_mesh_mirrordata_calc(struct BMEditMesh *em,
const bool mirror_axis[3],
struct TransMirrorData *r_mirror_data);
void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data);
+/**
+ * Detect CrazySpace [tm].
+ * Vertices with space affected by quats are marked with #BM_ELEM_TAG.
+ */
void transform_convert_mesh_crazyspace_detect(TransInfo *t,
struct TransDataContainer *tc,
struct BMEditMesh *em,
@@ -181,10 +257,12 @@ void recalcData_mesh_skin(TransInfo *t);
/* transform_convert_mesh_uv.c */
void createTransUVs(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Image Editor transforms */
void recalcData_uv(TransInfo *t);
/* transform_convert_nla.c */
void createTransNlaData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for NLA Editor transforms */
void recalcData_nla(TransInfo *t);
void special_aftertrans_update__nla(bContext *C, TransInfo *t);
@@ -195,11 +273,13 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t);
/* transform_convert_object.c */
void createTransObject(bContext *C, TransInfo *t);
+/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_objects(TransInfo *t);
void special_aftertrans_update__object(bContext *C, TransInfo *t);
/* transform_convert_object_texspace.c */
void createTransTexspace(TransInfo *t);
+/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_texspace(TransInfo *t);
/* transform_convert_paintcurve.c */
@@ -217,6 +297,7 @@ void special_aftertrans_update__sculpt(bContext *C, TransInfo *t);
/* transform_convert_sequencer.c */
void createTransSeqData(TransInfo *t);
+/* helper for recalcData() - for sequencer transforms */
void recalcData_sequencer(TransInfo *t);
void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
@@ -226,5 +307,6 @@ void recalcData_sequencer_image(TransInfo *t);
/* transform_convert_tracking.c */
void createTransTrackingData(bContext *C, TransInfo *t);
+/* helper for recalcData() - for Movie Clip transforms */
void recalcData_tracking(TransInfo *t);
void special_aftertrans_update__movieclip(bContext *C, TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index 24d84bc2de8..69b4de48c56 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -580,7 +580,6 @@ static void flushTransIntFrameActionData(TransInfo *t)
}
}
-/* helper for recalcData() - for Action Editor transforms */
void recalcData_actedit(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 88790e9645c..63aada0f797 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -716,9 +716,6 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
td->con = pchan->constraints.first;
}
-/**
- * When objects array is NULL, use 't->data_container' as is.
- */
void createTransPose(TransInfo *t)
{
Main *bmain = CTX_data_main(t->context);
@@ -1502,10 +1499,6 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
}
}
-/**
- * Sets transform flags in the bones.
- * Returns total number of bones with #BONE_TRANSFORM.
- */
int transform_convert_pose_transflags_update(Object *ob,
const int mode,
const short around,
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index f7b78b10868..e52dcb17806 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -496,8 +496,8 @@ static void createTransGPencil_strokes(bContext *C,
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
bGPDframe *gpf = gpl->actframe;
- float diff_mat[4][4];
- float inverse_diff_mat[4][4];
+ float diff_mat[3][3];
+ float inverse_diff_mat[3][3];
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
/* Init multiframe falloff options. */
@@ -509,9 +509,14 @@ static void createTransGPencil_strokes(bContext *C,
}
/* Calculate difference matrix. */
- BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
- /* Undo matrix. */
- invert_m4_m4(inverse_diff_mat, diff_mat);
+ {
+ float diff_mat_tmp[4][4];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat_tmp);
+ copy_m3_m4(diff_mat, diff_mat_tmp);
+ }
+
+ /* Use safe invert for cases where the input matrix has zero axes. */
+ invert_m3_m3_safe_ortho(inverse_diff_mat, diff_mat);
/* Make a new frame to work on if the layer's frame
* and the current scene frame don't match up.
@@ -651,9 +656,9 @@ static void createTransGPencil_strokes(bContext *C,
}
}
/* apply parent transformations */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ copy_m3_m3(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m3(td->mtx, diff_mat); /* display position */
+ copy_m3_m3(td->axismtx, diff_mat); /* axis orientation */
/* Triangulation must be calculated again,
* so save the stroke for recalc function */
@@ -748,7 +753,6 @@ void createTransGPencil(bContext *C, TransInfo *t)
}
}
-/* force recalculation of triangles during transformation */
void recalcData_gpencil_strokes(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index d22277f9d91..40c226b8f7c 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -218,15 +218,6 @@ static void graph_key_shortest_dist(
}
}
-/**
- * It is important to note that this doesn't always act on the selection (like it's usually done),
- * it acts on a subset of it. E.g. the selection code may leave a hint that we just dragged on a
- * left or right handle (SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT/RIGHT) and then we only transform the
- * selected left or right handles accordingly.
- * The points to be transformed are tagged with BEZT_FLAG_TEMP_TAG; some lower level curve
- * functions may need to be made aware of this. It's ugly that these act based on selection state
- * anyway.
- */
void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
@@ -913,7 +904,6 @@ static void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
}
}
-/* helper for recalcData() - for Graph Editor transforms */
void recalcData_graphedit(TransInfo *t)
{
SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 7377e47da3d..c3d95e1ad98 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1000,11 +1000,6 @@ static bool bmesh_test_loose_edge(BMEdge *edge)
return true;
}
-/**
- * \param mtx: Measure distance in this space.
- * \param dists: Store the closest connected distance to selected vertices.
- * \param index: Optionally store the original index we're measuring the distance to (can be NULL).
- */
void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
const float mtx[3][3],
float *dists,
@@ -1307,8 +1302,6 @@ void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data)
/** \name Crazy Space
* \{ */
-/* Detect CrazySpace [tm].
- * Vertices with space affected by quats are marked with #BM_ELEM_TAG */
void transform_convert_mesh_crazyspace_detect(TransInfo *t,
struct TransDataContainer *tc,
struct BMEditMesh *em,
@@ -2099,6 +2092,7 @@ void recalcData_mesh(TransInfo *t)
tc_mesh_partial_update(t, tc, &partial_state);
}
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2164,4 +2158,5 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
break;
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh_skin.c b/source/blender/editors/transform/transform_convert_mesh_skin.c
index 69b44998980..7c742f29c86 100644
--- a/source/blender/editors/transform/transform_convert_mesh_skin.c
+++ b/source/blender/editors/transform/transform_convert_mesh_skin.c
@@ -303,4 +303,5 @@ void recalcData_mesh_skin(TransInfo *t)
BKE_editmesh_looptri_and_normals_calc(em);
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index 61397b6ef4b..69f29389b31 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -464,7 +464,6 @@ static void flushTransUVs(TransInfo *t)
}
}
-/* helper for recalcData() - for Image Editor transforms */
void recalcData_uv(TransInfo *t)
{
SpaceImage *sima = t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index acef8a666e3..d19698a4f61 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -266,7 +266,6 @@ void createTransNlaData(bContext *C, TransInfo *t)
ANIM_animdata_freelist(&anim_data);
}
-/* helper for recalcData() - for NLA Editor transforms */
void recalcData_nla(TransInfo *t)
{
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 4a8ebf3fc6e..52365e4e519 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -874,7 +874,6 @@ static bool motionpath_need_update_object(Scene *scene, Object *ob)
/** \name Recalc Data object
* \{ */
-/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_objects(TransInfo *t)
{
bool motionpath_update = false;
diff --git a/source/blender/editors/transform/transform_convert_object_texspace.c b/source/blender/editors/transform/transform_convert_object_texspace.c
index 371a5b48818..3e434da66ec 100644
--- a/source/blender/editors/transform/transform_convert_object_texspace.c
+++ b/source/blender/editors/transform/transform_convert_object_texspace.c
@@ -51,7 +51,7 @@ void createTransTexspace(TransInfo *t)
TransData *td;
Object *ob;
ID *id;
- short *texflag;
+ char *texflag;
ob = OBACT(view_layer);
@@ -102,7 +102,6 @@ void createTransTexspace(TransInfo *t)
/** \name Recalc Data object
* \{ */
-/* helper for recalcData() - for object transforms, typically in the 3D view */
void recalcData_texspace(TransInfo *t)
{
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 70089164d8a..88c01321785 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -789,7 +789,6 @@ static void flushTransSeq(TransInfo *t)
SEQ_collection_free(transformed_strips);
}
-/* helper for recalcData() - for sequencer transforms */
void recalcData_sequencer(TransInfo *t)
{
TransData *td;
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index e8af1680a41..d5a59885014 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -118,16 +118,17 @@ static void freeSeqData(TransInfo *UNUSED(t),
void createTransSeqImageData(TransInfo *t)
{
Editing *ed = SEQ_editing_get(t->scene);
+ const SpaceSeq *sseq = t->area->spacedata.first;
+ const ARegion *region = t->region;
if (ed == NULL) {
return;
}
-
- {
- const SpaceSeq *sseq = t->area->spacedata.first;
- if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
- return;
- }
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return;
+ }
+ if (region->regiontype == RGN_TYPE_PREVIEW && sseq->view == SEQ_VIEW_SEQUENCE_PREVIEW) {
+ return;
}
ListBase *seqbase = SEQ_active_seqbase_get(ed);
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index 211dec3c4e8..dc37f2796bf 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -707,7 +707,6 @@ static void flushTransTracking(TransInfo *t)
}
}
-/* helper for recalcData() - for Movie Clip transforms */
void recalcData_tracking(TransInfo *t)
{
SpaceClip *sc = t->area->spacedata.first;
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
index af1f3cb72a4..13127ae06bb 100644
--- a/source/blender/editors/transform/transform_draw_cursors.c
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -88,20 +88,12 @@ static void drawArrow(const uint pos_id, const enum eArrowDirection dir)
immEnd();
}
-/**
- * Poll callback for cursor drawing:
- * #WM_paint_cursor_activate
- */
bool transform_draw_cursor_poll(bContext *C)
{
ARegion *region = CTX_wm_region(C);
return (region && ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_PREVIEW)) ? 1 : 0;
}
-/**
- * Cursor and help-line drawing, callback for:
- * #WM_paint_cursor_activate
- */
void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customdata)
{
TransInfo *t = (TransInfo *)customdata;
diff --git a/source/blender/editors/transform/transform_draw_cursors.h b/source/blender/editors/transform/transform_draw_cursors.h
index 0f626c9039b..b520cd1d4f8 100644
--- a/source/blender/editors/transform/transform_draw_cursors.h
+++ b/source/blender/editors/transform/transform_draw_cursors.h
@@ -24,5 +24,14 @@
#pragma once
/* Callbacks for #WM_paint_cursor_activate */
+
+/**
+ * Poll callback for cursor drawing:
+ * #WM_paint_cursor_activate
+ */
bool transform_draw_cursor_poll(struct bContext *C);
+/**
+ * Cursor and help-line drawing, callback for:
+ * #WM_paint_cursor_activate
+ */
void transform_draw_cursor_draw(struct bContext *C, int x, int y, void *customdata);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 4194fb2a0ad..43d894d60f2 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -125,9 +125,6 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
GPU_matrix_pop();
}
-/**
- * Free data before switching to another mode.
- */
void resetTransModal(TransInfo *t)
{
freeTransCustomDataForMode(t);
@@ -144,7 +141,7 @@ static void *t_view_get(TransInfo *t)
View3D *v3d = t->area->spacedata.first;
return (void *)v3d;
}
- else if (t->region) {
+ if (t->region) {
return (void *)&t->region->v2d;
}
return NULL;
@@ -158,41 +155,39 @@ static int t_around_get(TransInfo *t)
}
ScrArea *area = t->area;
- if (t->spacetype == SPACE_VIEW3D) {
- /* Bend always uses the cursor. */
- if (t->mode == TFM_BEND) {
- return V3D_AROUND_CURSOR;
- }
- else {
+ switch (t->spacetype) {
+ case SPACE_VIEW3D: {
+ if (t->mode == TFM_BEND) {
+ /* Bend always uses the cursor. */
+ return V3D_AROUND_CURSOR;
+ }
return t->settings->transform_pivot_point;
}
- }
- else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
- return sima->around;
- }
- else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = area->spacedata.first;
- return sipo->around;
- }
- else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = area->spacedata.first;
- return sclip->around;
- }
- else if (t->spacetype == SPACE_SEQ && t->region->regiontype == RGN_TYPE_PREVIEW) {
- return SEQ_tool_settings_pivot_point_get(t->scene);
+ case SPACE_IMAGE: {
+ SpaceImage *sima = area->spacedata.first;
+ return sima->around;
+ }
+ case SPACE_GRAPH: {
+ SpaceGraph *sipo = area->spacedata.first;
+ return sipo->around;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sclip = area->spacedata.first;
+ return sclip->around;
+ }
+ case SPACE_SEQ: {
+ if (t->region->regiontype == RGN_TYPE_PREVIEW) {
+ return SEQ_tool_settings_pivot_point_get(t->scene);
+ }
+ break;
+ }
+ default:
+ break;
}
return V3D_AROUND_CENTER_BOUNDS;
}
-/**
- * Setup internal data, mouse, vectors
- *
- * \note \a op and \a event can be NULL
- *
- * \see #saveTransform does the reverse.
- */
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
Scene *sce = CTX_data_scene(C);
@@ -219,7 +214,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->flag = 0;
- if (obact && ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
+ if (obact && !(t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) &&
+ ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
t->obedit_type = obact->type;
}
else {
@@ -398,11 +394,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
RNA_property_is_set(op->ptr, prop)) {
float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory. */
if (RNA_property_array_check(prop)) {
- RNA_float_get_array(op->ptr, "value", values);
+ RNA_property_float_get_array(op->ptr, prop, values);
t_values_set_is_array = true;
}
else {
- values[0] = RNA_float_get(op->ptr, "value");
+ values[0] = RNA_property_float_get(op->ptr, prop);
}
if (t->flag & T_MODAL) {
@@ -488,25 +484,31 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ orient_type_default = orient_type_scene;
+
if (orient_type_set != -1) {
- orient_type_default = orient_type_set;
- t->is_orient_set = true;
+ if (!(t->con.mode & CON_APPLY)) {
+ /* Only overwrite default if not constrained. */
+ orient_type_default = orient_type_set;
+ t->is_orient_default_overwrite = true;
+ }
}
else if (orient_type_matrix_set != -1) {
- orient_type_default = orient_type_set = orient_type_matrix_set;
- t->is_orient_set = true;
+ orient_type_set = orient_type_matrix_set;
+ if (!(t->con.mode & CON_APPLY)) {
+ /* Only overwrite default if not constrained. */
+ orient_type_default = orient_type_set;
+ t->is_orient_default_overwrite = true;
+ }
}
else if (t->con.mode & CON_APPLY) {
- orient_type_default = orient_type_set = orient_type_scene;
+ orient_type_set = orient_type_scene;
+ }
+ else if (orient_type_scene == V3D_ORIENT_GLOBAL) {
+ orient_type_set = V3D_ORIENT_LOCAL;
}
else {
- orient_type_default = orient_type_scene;
- if (orient_type_scene == V3D_ORIENT_GLOBAL) {
- orient_type_set = V3D_ORIENT_LOCAL;
- }
- else {
- orient_type_set = V3D_ORIENT_GLOBAL;
- }
+ orient_type_set = V3D_ORIENT_GLOBAL;
}
BLI_assert(!ELEM(-1, orient_type_default, orient_type_set));
@@ -708,9 +710,6 @@ static void freeTransCustomDataContainer(TransInfo *t,
}
}
-/**
- * Needed for mode switching.
- */
void freeTransCustomDataForMode(TransInfo *t)
{
freeTransCustomData(t, NULL, &t->custom.mode);
@@ -719,7 +718,6 @@ void freeTransCustomDataForMode(TransInfo *t)
}
}
-/* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
void postTrans(bContext *C, TransInfo *t)
{
if (t->draw_handle_view) {
@@ -1057,9 +1055,6 @@ void calculateCenterBound(TransInfo *t, float r_center[3])
}
}
-/**
- * \param select_only: only get active center from data being transformed.
- */
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
@@ -1313,11 +1308,6 @@ void calculatePropRatio(TransInfo *t)
}
}
-/**
- * Rotate an element, low level code, ignore protected channels.
- * (use for objects or pose-bones)
- * Similar to #ElementRotation.
- */
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot)
{
float totmat[3][3];
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 7a23a4a92ce..c3a0e4b1163 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -286,7 +286,14 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
* In addition to this, the rotation of the bounding box can not currently be hooked up
* properly to read the result from the transform system (when transforming multiple strips).
*/
- mid_v2_v2v2(r_center, r_min, r_max);
+ const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
+ if (pivot_point == V3D_AROUND_CURSOR) {
+ SpaceSeq *sseq = area->spacedata.first;
+ SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_center);
+ }
+ else {
+ mid_v2_v2v2(r_center, r_min, r_max);
+ }
zero_v2(r_min);
zero_v2(r_max);
return has_select;
@@ -353,39 +360,59 @@ static float gizmo2d_calc_rotation(const bContext *C)
return 0.0f;
}
-static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
+static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
+{
+ zero_v2(r_pivot);
+
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ bool has_select = SEQ_collection_len(strips) != 0;
+
+ if (has_select) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ float origin[2];
+ SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
+ add_v2_v2(r_pivot, origin);
+ }
+ mul_v2_fl(r_pivot, 1.0f / SEQ_collection_len(strips));
+ }
+
+ SEQ_collection_free(strips);
+ return has_select;
+}
+
+static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
{
ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
bool has_select = false;
- zero_v2(r_center);
+
if (area->spacetype == SPACE_IMAGE) {
SpaceImage *sima = area->spacedata.first;
ViewLayer *view_layer = CTX_data_view_layer(C);
- ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select);
+ ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_pivot, sima->around, &has_select);
}
else if (area->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = area->spacedata.first;
const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
- SEQ_filter_selected_strips(strips);
- has_select = SEQ_collection_len(strips) != 0;
if (pivot_point == V3D_AROUND_CURSOR) {
- SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_center);
+ SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_pivot);
+
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ has_select = SEQ_collection_len(strips) != 0;
+ SEQ_collection_free(strips);
}
- else if (has_select) {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- float origin[2];
- SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
- add_v2_v2(r_center, origin);
- }
- mul_v2_fl(r_center, 1.0f / SEQ_collection_len(strips));
+ else {
+ has_select = seq_get_strip_pivot_median(scene, r_pivot);
}
-
- SEQ_collection_free(strips);
+ }
+ else {
+ BLI_assert_msg(0, "Unhandled space type!");
}
return has_select;
}
@@ -409,7 +436,7 @@ static int gizmo2d_modal(bContext *C,
ARegion *region = CTX_wm_region(C);
float origin[3];
- gizmo2d_calc_center(C, origin);
+ gizmo2d_calc_transform_pivot(C, origin);
gizmo2d_origin_to_region(region, origin);
WM_gizmo_set_matrix_location(widget, origin);
@@ -541,7 +568,7 @@ static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
GizmoGroup2D *ggd = gzgroup->customdata;
bool has_select;
if (ggd->no_cage) {
- has_select = gizmo2d_calc_center(C, ggd->origin);
+ has_select = gizmo2d_calc_transform_pivot(C, ggd->origin);
}
else {
has_select = gizmo2d_calc_bounds(C, ggd->origin, ggd->min, ggd->max);
@@ -597,7 +624,8 @@ static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
ScrArea *area = CTX_wm_area(C);
if (area->spacetype == SPACE_SEQ) {
- gizmo2d_calc_center(C, origin);
+ Scene *scene = CTX_data_scene(C);
+ seq_get_strip_pivot_median(scene, origin);
float matrix_rotate[4][4];
unit_m4(matrix_rotate);
@@ -660,7 +688,8 @@ static void gizmo2d_xform_invoke_prepare(const bContext *C,
if (ggd->rotation != 0.0f && area->spacetype == SPACE_SEQ) {
float origin[3];
- gizmo2d_calc_center(C, origin);
+ Scene *scene = CTX_data_scene(C);
+ seq_get_strip_pivot_median(scene, origin);
/* We need to rotate the cardinal points so they align with the rotated bounding box. */
rotate_around_center_v2(n, origin, ggd->rotation);
@@ -781,7 +810,7 @@ static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup_Resize2D *ggd = gzgroup->customdata;
float origin[3];
- const bool has_select = gizmo2d_calc_center(C, origin);
+ const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
if (has_select == false) {
for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
@@ -941,7 +970,7 @@ static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
float origin[3];
- const bool has_select = gizmo2d_calc_center(C, origin);
+ const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
if (has_select == false) {
ggd->gizmo->flag |= WM_GIZMO_HIDDEN;
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 6a2353d403f..9bd55d78039 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -623,8 +623,6 @@ bool gimbal_axis_object(Object *ob, float gmat[3][3])
return 1;
}
-/* centroid, boundbox, of selection */
-/* returns total items selected */
int ED_transform_calc_gizmo_stats(const bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds)
@@ -2005,7 +2003,6 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
"");
}
-/** Only poll, flag & gzmap_params differ. */
void VIEW3D_GGT_xform_gizmo_context(wmGizmoGroupType *gzgt)
{
gzgt->name = "3D View: Transform Gizmo Context";
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 5e0abbc1a08..d2e7f9f83df 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -78,7 +78,6 @@ bool transdata_check_local_center(const TransInfo *t, short around)
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE | CTX_SEQUENCER_IMAGE))));
}
-/* Informs if the mode can be switched during modal. */
bool transform_mode_is_changeable(const int mode)
{
return ELEM(mode,
@@ -520,10 +519,12 @@ void constraintSizeLim(const TransInfo *t, TransData *td)
}
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Transform (Rotation Utils)
* \{ */
-/* Used by Transform Rotation and Transform Normal Rotation */
+
void headerRotation(TransInfo *t, char *str, const int str_size, float final)
{
size_t ofs = 0;
@@ -551,12 +552,6 @@ void headerRotation(TransInfo *t, char *str, const int str_size, float final)
}
}
-/**
- * Applies values of rotation to `td->loc` and `td->ext->quat`
- * based on a rotation matrix (mat) and a pivot (center).
- *
- * Protected axis and other transform settings are taken into account.
- */
void ElementRotation_ex(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
@@ -828,11 +823,13 @@ void ElementRotation(const TransInfo *t,
ElementRotation_ex(t, tc, td, mat, center);
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Transform (Resize Utils)
* \{ */
+
void headerResize(TransInfo *t, const float vec[3], char *str, const int str_size)
{
char tvec[NUM_STR_REP_LEN * 3];
@@ -1232,15 +1229,12 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
* BLI_assert(t->mode == mode); */
}
-/**
- * When in modal and not set, initializes a default orientation for the mode.
- */
void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
{
/* Currently only these types are supported. */
BLI_assert(ELEM(type, V3D_ORIENT_GLOBAL, V3D_ORIENT_VIEW));
- if (t->is_orient_set) {
+ if (t->is_orient_default_overwrite) {
return;
}
@@ -1276,4 +1270,5 @@ void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
transform_orientations_current_set(t, O_DEFAULT);
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index c561d1c8a4f..ec3d5b8d0fe 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -42,12 +42,24 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
int transform_mode_really_used(struct bContext *C, int mode);
bool transdata_check_local_center(const TransInfo *t, short around);
+/**
+ * Informs if the mode can be switched during modal.
+ */
bool transform_mode_is_changeable(const int mode);
void protectedTransBits(short protectflag, float vec[3]);
void protectedSizeBits(short protectflag, float size[3]);
void constraintTransLim(const TransInfo *t, TransData *td);
void constraintSizeLim(const TransInfo *t, TransData *td);
+/**
+ * Used by Transform Rotation and Transform Normal Rotation.
+ */
void headerRotation(TransInfo *t, char *str, int str_size, float final);
+/**
+ * Applies values of rotation to `td->loc` and `td->ext->quat`
+ * based on a rotation matrix (mat) and a pivot (center).
+ *
+ * Protected axis and other transform settings are taken into account.
+ */
void ElementRotation_ex(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
@@ -64,6 +76,9 @@ void ElementResize(const TransInfo *t,
TransData *td,
const float mat[3][3]);
void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode);
+/**
+ * When in modal and not set, initializes a default orientation for the mode.
+ */
void transform_mode_default_modal_orientation_set(TransInfo *t, int type);
/* transform_mode_align.c */
diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c
index 1a1d84699f4..f27a194dda0 100644
--- a/source/blender/editors/transform/transform_mode_align.c
+++ b/source/blender/editors/transform/transform_mode_align.c
@@ -89,4 +89,5 @@ void initAlign(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_NONE);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c
index 653944b56a7..46d6e5c5983 100644
--- a/source/blender/editors/transform/transform_mode_baketime.c
+++ b/source/blender/editors/transform/transform_mode_baketime.c
@@ -132,4 +132,5 @@ void initBakeTime(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE; /* Don't think this uses units? */
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c
index 95e2d944b9b..ce2f3c15651 100644
--- a/source/blender/editors/transform/transform_mode_bbone_resize.c
+++ b/source/blender/editors/transform/transform_mode_bbone_resize.c
@@ -123,6 +123,7 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
float ratio = t->values[0];
copy_v3_fl(t->values_final, ratio);
+ add_v3_v3(t->values_final, t->values_modal_offset);
transform_snap_increment(t, t->values_final);
@@ -184,4 +185,5 @@ void initBoneSize(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
t->num.unit_type[2] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c
index 6d84c397fa6..a1bcd3aeb50 100644
--- a/source/blender/editors/transform/transform_mode_bend.c
+++ b/source/blender/editors/transform/transform_mode_bend.c
@@ -393,4 +393,5 @@ void initBend(TransInfo *t)
t->custom.mode.data = data;
t->custom.mode.use_free = true;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c
index da7393ab42e..bb7bd81f7bd 100644
--- a/source/blender/editors/transform/transform_mode_boneenvelope.c
+++ b/source/blender/editors/transform/transform_mode_boneenvelope.c
@@ -51,7 +51,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c
index cd04ca2b844..00629b13ede 100644
--- a/source/blender/editors/transform/transform_mode_boneroll.c
+++ b/source/blender/editors/transform/transform_mode_boneroll.c
@@ -52,7 +52,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
float final;
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &final);
@@ -107,4 +107,5 @@ void initBoneRoll(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index 9433502ef55..c4c33c881ed 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -51,7 +51,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -115,4 +115,5 @@ void initCurveShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
index 5466ba3e91f..8aa7955bc2a 100644
--- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c
+++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
@@ -96,7 +96,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- weight = t->values[0];
+ weight = t->values[0] + t->values_modal_offset[0];
CLAMP_MAX(weight, 1.0f);
@@ -174,4 +174,5 @@ void initBevelWeight(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index 1d3b4dbb4f0..debc2a1be3e 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -97,7 +97,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- crease = t->values[0];
+ crease = t->values[0] + t->values_modal_offset[0];
CLAMP_MAX(crease, 1.0f);
diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
index 1f57bacf78f..edba9809207 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -95,7 +95,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
float axis[3];
float mat[3][3];
- float angle = t->values[0];
+ float angle = t->values[0] + t->values_modal_offset[0];
copy_v3_v3(axis, axis_final);
transform_snap_increment(t, &angle);
@@ -152,4 +152,5 @@ void initNormalRotation(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index cfcb17b8da0..7a0f2743a98 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -1458,7 +1458,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
applySnapping(t, &final);
if (!validSnap(t)) {
@@ -1567,4 +1567,5 @@ void initEdgeSlide(TransInfo *t)
{
initEdgeSlide_ex(t, true, false, false, true);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
index 748769491f1..5772c6b4717 100644
--- a/source/blender/editors/transform/transform_mode_gpopacity.c
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -53,7 +53,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -125,4 +125,5 @@ void initGPOpacity(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
index bc081edd597..f4a0c3c659c 100644
--- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -53,7 +53,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -127,4 +127,5 @@ void initGPShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index 327a639773c..a1a8bed59b3 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -52,7 +52,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
bool initial_feather = false;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -141,4 +141,5 @@ void initMaskShrinkFatten(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
index 2ae32f3545a..ee584cb9833 100644
--- a/source/blender/editors/transform/transform_mode_mirror.c
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -238,4 +238,5 @@ void initMirror(TransInfo *t)
t->flag |= T_NULL_ONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c
index 0527d1bc08e..8577a0a5e11 100644
--- a/source/blender/editors/transform/transform_mode_push_pull.c
+++ b/source/blender/editors/transform/transform_mode_push_pull.c
@@ -124,7 +124,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- distance = t->values[0];
+ distance = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &distance);
@@ -199,4 +199,5 @@ void initPushPull(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_LENGTH;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index 28323460626..3d7f0aa6d67 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -267,4 +267,5 @@ void initResize(TransInfo *t, float mouse_dir_constraint[3])
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_GLOBAL);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index bfbdaa389f4..e8ef71a6639 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -363,4 +363,5 @@ void initRotation(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
index 018725ec6dd..9369cb2e62b 100644
--- a/source/blender/editors/transform/transform_mode_shear.c
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -199,7 +199,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
const bool is_local_center = transdata_check_local_center(t, t->around);
- value = t->values[0];
+ value = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &value);
@@ -289,4 +289,5 @@ void initShear(TransInfo *t)
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c
index b18e0aa0c7f..01dd1b701a5 100644
--- a/source/blender/editors/transform/transform_mode_shrink_fatten.c
+++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c
@@ -110,7 +110,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
size_t ofs = 0;
UnitSettings *unit = &t->scene->unit;
- distance = t->values[0];
+ distance = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &distance);
@@ -216,4 +216,5 @@ void initShrinkFatten(TransInfo *t)
}
}
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
index 236c9024201..f5e502fed4f 100644
--- a/source/blender/editors/transform/transform_mode_skin_resize.c
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -107,6 +107,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
}
else {
copy_v3_fl(t->values_final, t->values[0]);
+ add_v3_v3(t->values_final, t->values_modal_offset);
transform_snap_increment(t, t->values_final);
@@ -179,4 +180,5 @@ void initSkinResize(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
t->num.unit_type[2] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c
index b48f474e16e..6451a7d77d5 100644
--- a/source/blender/editors/transform/transform_mode_tilt.c
+++ b/source/blender/editors/transform/transform_mode_tilt.c
@@ -52,7 +52,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
float final;
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &final);
@@ -111,4 +111,5 @@ void initTilt(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c
index 0a7ae54982e..c198f235cf8 100644
--- a/source/blender/editors/transform/transform_mode_timescale.c
+++ b/source/blender/editors/transform/transform_mode_timescale.c
@@ -151,4 +151,5 @@ void initTimeScale(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timeslide.c b/source/blender/editors/transform/transform_mode_timeslide.c
index 5cc53eb08ce..98abab0fd6b 100644
--- a/source/blender/editors/transform/transform_mode_timeslide.c
+++ b/source/blender/editors/transform/transform_mode_timeslide.c
@@ -232,4 +232,5 @@ void initTimeSlide(TransInfo *t)
/* No time unit supporting frames currently... */
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
index 294040946bd..5f2a2e472c5 100644
--- a/source/blender/editors/transform/transform_mode_timetranslate.c
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -157,4 +157,5 @@ void initTimeTranslate(TransInfo *t)
/* No time unit supporting frames currently... */
t->num.unit_type[0] = B_UNIT_NONE;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c
index bfc85b2fe44..2062f78c326 100644
--- a/source/blender/editors/transform/transform_mode_tosphere.c
+++ b/source/blender/editors/transform/transform_mode_tosphere.c
@@ -194,7 +194,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
- ratio = t->values[0];
+ ratio = t->values[0] + t->values_modal_offset[0];
transform_snap_increment(t, &ratio);
@@ -277,4 +277,5 @@ void initToSphere(TransInfo *t)
to_sphere_radius_update(t);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
index aa8b0783d0a..ddffc4f8438 100644
--- a/source/blender/editors/transform/transform_mode_trackball.c
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -218,4 +218,5 @@ void initTrackball(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 233e32c0e48..19d0c6d39a3 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -579,4 +579,5 @@ void initTranslation(TransInfo *t)
t->custom.mode.data = custom_data;
t->custom.mode.use_free = true;
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
index def5f911c6f..48a8fcf60eb 100644
--- a/source/blender/editors/transform/transform_mode_vert_slide.c
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -582,7 +582,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
- final = t->values[0];
+ final = t->values[0] + t->values_modal_offset[0];
applySnapping(t, &final);
if (!validSnap(t)) {
@@ -687,4 +687,5 @@ void initVertSlide(TransInfo *t)
{
initVertSlide_ex(t, false, false, true);
}
+
/** \} */
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 61bbe722d71..fa2485c33c2 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -315,11 +315,6 @@ bool createSpaceNormal(float mat[3][3], const float normal[3])
return true;
}
-/**
- * \note To recreate an orientation from the matrix:
- * - (plane == mat[1])
- * - (normal == mat[2])
- */
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3])
{
if (normalize_v3_v3(mat[2], normal) == 0.0f) {
@@ -503,15 +498,6 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3
scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, r_mat);
}
-/**
- * \note The resulting matrix may not be orthogonal,
- * callers that depend on `r_mat` to be orthogonal should use #orthogonalize_m3.
- *
- * A non orthogonal matrix may be returned when:
- * - #V3D_ORIENT_GIMBAL the result won't be orthogonal unless the object has no rotation.
- * - #V3D_ORIENT_LOCAL may contain shear from non-uniform scale in parent/child relationships.
- * - #V3D_ORIENT_CUSTOM may have been created from #V3D_ORIENT_LOCAL.
- */
short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
ViewLayer *view_layer,
const View3D *v3d,
@@ -602,9 +588,6 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
return orientation_index;
}
-/* Sets the matrix of the specified space orientation.
- * If the matrix cannot be obtained, an orientation different from the one
- * informed is returned */
short transform_orientation_matrix_get(bContext *C,
TransInfo *t,
short orient_index,
diff --git a/source/blender/editors/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h
index 1da369c8307..6e0e3d9f8c7 100644
--- a/source/blender/editors/transform/transform_orientations.h
+++ b/source/blender/editors/transform/transform_orientations.h
@@ -25,6 +25,10 @@
struct TransInfo;
+/**
+ * Sets the matrix of the specified space orientation.
+ * If the matrix cannot be obtained, an orientation different from the one informed is returned.
+ */
short transform_orientation_matrix_get(struct bContext *C,
struct TransInfo *t,
short orient_index,
@@ -33,12 +37,19 @@ short transform_orientation_matrix_get(struct bContext *C,
const char *transform_orientations_spacename_get(struct TransInfo *t, const short orient_type);
void transform_orientations_current_set(struct TransInfo *t, const short orient_index);
-/* Those two fill in mat and return non-zero on success */
+/**
+ * Those two fill in mat and return non-zero on success.
+ */
bool transform_orientations_create_from_axis(float mat[3][3],
const float x[3],
const float y[3],
const float z[3]);
bool createSpaceNormal(float mat[3][3], const float normal[3]);
+/**
+ * \note To recreate an orientation from the matrix:
+ * - (plane == mat[1])
+ * - (normal == mat[2])
+ */
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3]);
struct TransformOrientation *addMatrixSpace(struct bContext *C,
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 71f26ef0594..9cdec357afd 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -499,7 +499,9 @@ void applySnapping(TransInfo *t, float *vec)
/* Time base quirky code to go around find-nearest slowness. */
/* TODO: add exception for object mode, no need to slow it down then. */
if (current - t->tsnap.last >= 0.01) {
- t->tsnap.calcSnap(t, vec);
+ if (t->tsnap.calcSnap) {
+ t->tsnap.calcSnap(t, vec);
+ }
if (t->tsnap.targetSnap) {
t->tsnap.targetSnap(t);
}
@@ -708,33 +710,39 @@ void initSnapping(TransInfo *t, wmOperator *op)
resetSnapping(t);
/* if snap property exists */
- if (op && RNA_struct_find_property(op->ptr, "snap") &&
- RNA_struct_property_is_set(op->ptr, "snap")) {
- if (RNA_boolean_get(op->ptr, "snap")) {
+ PropertyRNA *prop;
+ if (op && (prop = RNA_struct_find_property(op->ptr, "snap")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
t->modifiers |= MOD_SNAP;
- if (RNA_struct_property_is_set(op->ptr, "snap_target")) {
- snap_target = RNA_enum_get(op->ptr, "snap_target");
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_target")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ snap_target = RNA_property_enum_get(op->ptr, prop);
}
- if (RNA_struct_property_is_set(op->ptr, "snap_point")) {
- RNA_float_get_array(op->ptr, "snap_point", t->tsnap.snapPoint);
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, t->tsnap.snapPoint);
t->tsnap.status |= SNAP_FORCED | POINT_INIT;
}
/* snap align only defined in specific cases */
- if (RNA_struct_find_property(op->ptr, "snap_align")) {
- t->tsnap.align = RNA_boolean_get(op->ptr, "snap_align");
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_align")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.align = RNA_property_boolean_get(op->ptr, prop);
RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
normalize_v3(t->tsnap.snapNormal);
}
- if (RNA_struct_find_property(op->ptr, "use_snap_project")) {
- t->tsnap.project = RNA_boolean_get(op->ptr, "use_snap_project");
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_project")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.project = RNA_property_boolean_get(op->ptr, prop);
}
- if (RNA_struct_find_property(op->ptr, "use_snap_self")) {
- t->tsnap.snap_self = RNA_boolean_get(op->ptr, "use_snap_self");
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_self")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.snap_self = RNA_property_boolean_get(op->ptr, prop);
}
}
}
@@ -777,8 +785,15 @@ static void setSnappingCallback(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
t->tsnap.calcSnap = snap_calc_view3d_fn;
}
- else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
- t->tsnap.calcSnap = snap_calc_uv_fn;
+ else if (t->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = t->area->spacedata.first;
+ Object *obact = t->view_layer->basact ? t->view_layer->basact->object : NULL;
+
+ const bool is_uv_editor = sima->mode == SI_MODE_UV;
+ const bool has_edit_object = obact && BKE_object_is_in_editmode(obact);
+ if (is_uv_editor && has_edit_object) {
+ t->tsnap.calcSnap = snap_calc_uv_fn;
+ }
}
else if (t->spacetype == SPACE_NODE) {
t->tsnap.calcSnap = snap_calc_node_fn;
@@ -953,7 +968,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
{
- BLI_assert(t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH);
+ BLI_assert(t->spacetype == SPACE_IMAGE);
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
float co[2];
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index ed7f93304bc..bc89c7a8cda 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -76,18 +76,30 @@ void removeSnapPoint(TransInfo *t);
float transform_snap_distance_len_squared_fn(TransInfo *t, const float p1[3], const float p2[3]);
/* transform_snap_sequencer.c */
+
struct TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t);
void transform_snap_sequencer_data_free(struct TransSeqSnapData *data);
bool transform_snap_sequencer_calc(struct TransInfo *t);
void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec);
/* transform_snap_animation.c */
+
+/**
+ * This function returns the snapping 'mode' for Animation Editors only.
+ * We cannot use the standard snapping due to NLA-strip scaling complexities.
+ *
+ * TODO: these modifier checks should be accessible from the key-map.
+ */
short getAnimEdit_SnapMode(TransInfo *t);
void snapFrameTransform(TransInfo *t,
const eAnimEdit_AutoSnap autosnap,
const float val_initial,
const float val_final,
float *r_val_final);
+/**
+ * This function is used by Animation Editor specific transform functions to do
+ * the Snap Keyframe to Nearest Frame/Marker
+ */
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
const eAnimEdit_AutoSnap autosnap,
diff --git a/source/blender/editors/transform/transform_snap_animation.c b/source/blender/editors/transform/transform_snap_animation.c
index 8828f96247d..6ca16c171e2 100644
--- a/source/blender/editors/transform/transform_snap_animation.c
+++ b/source/blender/editors/transform/transform_snap_animation.c
@@ -38,12 +38,6 @@
/** \name Snapping in Anim Editors
* \{ */
-/**
- * This function returns the snapping 'mode' for Animation Editors only.
- * We cannot use the standard snapping due to NLA-strip scaling complexities.
- *
- * TODO: these modifier checks should be accessible from the key-map.
- */
short getAnimEdit_SnapMode(TransInfo *t)
{
short autosnap = SACTSNAP_OFF;
@@ -128,9 +122,6 @@ void snapFrameTransform(TransInfo *t,
}
}
-/* This function is used by Animation Editor specific transform functions to do
- * the Snap Keyframe to Nearest Frame/Marker
- */
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
const eAnimEdit_AutoSnap autosnap,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 4b981e763f1..350d3a2676c 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -125,8 +125,6 @@ struct SnapObjectContext {
const ARegion *region;
const View3D *v3d;
- const struct SnapObjectParams *params;
-
float mval[2];
float pmat[4][4]; /* perspective matrix */
float win_size[2]; /* win x and y */
@@ -444,6 +442,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
* \{ */
typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
float obmat[4][4],
bool is_object_active,
@@ -453,16 +452,17 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
* Walks through all objects in the scene to create the list of objects to snap.
*/
static void iter_snap_objects(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
IterSnapObjsCallback sob_callback,
void *data)
{
ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph);
- const eSnapSelect snap_select = sctx->runtime.params->snap_select;
+ const eSnapSelect snap_select = params->snap_select;
Base *base_act = view_layer->basact;
if (snap_select == SNAP_ONLY_ACTIVE) {
Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base_act->object);
- sob_callback(sctx, obj_eval, obj_eval->obmat, true, data);
+ sob_callback(sctx, params, obj_eval, obj_eval->obmat, true, data);
return;
}
@@ -500,12 +500,12 @@ static void iter_snap_objects(SnapObjectContext *sctx,
ListBase *lb = object_duplilist(sctx->runtime.depsgraph, sctx->scene, obj_eval);
for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
BLI_assert(DEG_is_evaluated_object(dupli_ob->ob));
- sob_callback(sctx, dupli_ob->ob, dupli_ob->mat, is_object_active, data);
+ sob_callback(sctx, params, dupli_ob->ob, dupli_ob->mat, is_object_active, data);
}
free_object_duplilist(lb);
}
- sob_callback(sctx, obj_eval, obj_eval->obmat, is_object_active, data);
+ sob_callback(sctx, params, obj_eval, obj_eval->obmat, is_object_active, data);
}
}
@@ -665,6 +665,7 @@ static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
}
static bool raycastMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
Object *ob_eval,
@@ -773,7 +774,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- sctx->runtime.params->use_backface_culling ?
+ params->use_backface_culling ?
mesh_looptri_raycast_backface_culling_cb :
treedata->raycast_callback,
treedata) != -1) {
@@ -805,6 +806,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
}
static bool raycastEditMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
Object *ob_eval,
@@ -943,7 +945,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- sctx->runtime.params->use_backface_culling ?
+ params->use_backface_culling ?
editmesh_looptri_raycast_backface_culling_cb :
treedata->raycast_callback,
treedata) != -1) {
@@ -994,12 +996,14 @@ struct RaycastObjUserData {
};
/**
- * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
- *
* \note Duplicate args here are documented at #snapObjectsRay
*/
-static void raycast_obj_fn(
- SnapObjectContext *sctx, Object *ob_eval, float obmat[4][4], bool is_object_active, void *data)
+static void raycast_obj_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ float obmat[4][4],
+ bool is_object_active,
+ void *data)
{
struct RaycastObjUserData *dt = data;
const uint ob_index = dt->ob_index++;
@@ -1018,13 +1022,14 @@ static void raycast_obj_fn(
switch (ob_eval->type) {
case OB_MESH: {
- const eSnapEditType edit_mode_type = sctx->runtime.params->edit_mode_type;
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
bool use_hide = false;
Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
retval = raycastEditMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
@@ -1039,6 +1044,7 @@ static void raycast_obj_fn(
break;
}
retval = raycastMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
@@ -1060,6 +1066,7 @@ static void raycast_obj_fn(
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
retval = raycastMesh(sctx,
+ params,
dt->ray_start,
dt->ray_dir,
ob_eval,
@@ -1115,6 +1122,7 @@ static void raycast_obj_fn(
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
*/
static bool raycastObjects(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
/* read/write args */
@@ -1129,7 +1137,6 @@ static bool raycastObjects(SnapObjectContext *sctx,
float r_obmat[4][4],
ListBase *r_hit_list)
{
- const struct SnapObjectParams *params = sctx->runtime.params;
const View3D *v3d = sctx->runtime.v3d;
if (params->use_occlusion_test && v3d && XRAY_FLAG_ENABLED(v3d)) {
/* General testing of occlusion geometry is disabled if the snap is not intended for the edit
@@ -1154,7 +1161,7 @@ static bool raycastObjects(SnapObjectContext *sctx,
.ret = false,
};
- iter_snap_objects(sctx, raycast_obj_fn, &data);
+ iter_snap_objects(sctx, params, raycast_obj_fn, &data);
return data.ret;
}
@@ -1531,6 +1538,7 @@ static void cb_snap_tri_verts(void *userdata,
* \{ */
static short snap_mesh_polygon(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
/* read/write args */
@@ -1564,10 +1572,8 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BLI_assert(sod != NULL);
Nearest2dUserData nearest2d;
- nearest2d_data_init(sod,
- sctx->runtime.view_proj == VIEW_PROJ_PERSP,
- sctx->runtime.params->use_backface_culling,
- &nearest2d);
+ nearest2d_data_init(
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
if (sod->type == SNAP_MESH) {
BVHTreeFromMesh *treedata = &sod->treedata_mesh;
@@ -1657,6 +1663,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
}
static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
float original_dist_px,
@@ -1678,10 +1685,8 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
BLI_assert(sod != NULL);
Nearest2dUserData nearest2d;
- nearest2d_data_init(sod,
- sctx->runtime.view_proj == VIEW_PROJ_PERSP,
- sctx->runtime.params->use_backface_culling,
- &nearest2d);
+ nearest2d_data_init(
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
int vindex[2];
nearest2d.get_edge_verts_index(*r_index, nearest2d.userdata, vindex);
@@ -1806,6 +1811,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
}
static short snapArmature(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
/* read/write args */
@@ -1849,7 +1855,7 @@ static short snapArmature(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]);
}
- const eSnapSelect snap_select = sctx->runtime.params->snap_select;
+ const eSnapSelect snap_select = params->snap_select;
bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
bArmature *arm = ob_eval->data;
@@ -1963,6 +1969,7 @@ static short snapArmature(SnapObjectContext *sctx,
}
static short snapCurve(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
const float obmat[4][4],
/* read/write args */
@@ -2022,7 +2029,7 @@ static short snapCurve(SnapObjectContext *sctx,
}
bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
- bool skip_selected = sctx->runtime.params->snap_select == SNAP_NOT_SELECTED;
+ bool skip_selected = params->snap_select == SNAP_NOT_SELECTED;
for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (int u = 0; u < nu->pntsu; u++) {
@@ -2284,6 +2291,7 @@ static short snapCamera(const SnapObjectContext *sctx,
}
static short snapMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
Mesh *me_eval,
const float obmat[4][4],
@@ -2358,10 +2366,8 @@ static short snapMesh(SnapObjectContext *sctx,
}
Nearest2dUserData nearest2d;
- nearest2d_data_init(sod,
- sctx->runtime.view_proj == VIEW_PROJ_PERSP,
- sctx->runtime.params->use_backface_culling,
- &nearest2d);
+ nearest2d_data_init(
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2476,6 +2482,7 @@ static short snapMesh(SnapObjectContext *sctx,
}
static short snapEditMesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
@@ -2579,10 +2586,8 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
Nearest2dUserData nearest2d;
- nearest2d_data_init(sod,
- sctx->runtime.view_proj == VIEW_PROJ_PERSP,
- sctx->runtime.params->use_backface_culling,
- &nearest2d);
+ nearest2d_data_init(
+ sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2670,11 +2675,10 @@ struct SnapObjUserData {
};
/**
- * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
- *
* \note Duplicate args here are documented at #snapObjectsRay
*/
static void snap_obj_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
Object *ob_eval,
float obmat[4][4],
bool UNUSED(is_object_active),
@@ -2685,14 +2689,14 @@ static void snap_obj_fn(SnapObjectContext *sctx,
switch (ob_eval->type) {
case OB_MESH: {
- const eSnapEditType edit_mode_type = sctx->runtime.params->edit_mode_type;
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
bool use_hide;
Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
if (me_eval == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
retval = snapEditMesh(
- sctx, ob_eval, em_orig, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ sctx, params, ob_eval, em_orig, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
}
if (ob_eval->dt == OB_BOUNDBOX) {
@@ -2700,22 +2704,40 @@ static void snap_obj_fn(SnapObjectContext *sctx,
return;
}
- retval = snapMesh(
- sctx, ob_eval, me_eval, obmat, use_hide, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapMesh(sctx,
+ params,
+ ob_eval,
+ me_eval,
+ obmat,
+ use_hide,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
break;
}
case OB_ARMATURE:
- retval = snapArmature(sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapArmature(
+ sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CURVE:
- retval = snapCurve(sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapCurve(
+ sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
case OB_FONT: {
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
- retval |= snapMesh(
- sctx, ob_eval, mesh_eval, obmat, false, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval |= snapMesh(sctx,
+ params,
+ ob_eval,
+ mesh_eval,
+ obmat,
+ false,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
}
break;
}
@@ -2765,6 +2787,7 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
static short snapObjectsRay(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
/* read/write args */
/* Parameters below cannot be const, because they are assigned to a
* non-const variable (readability-non-const-parameter). */
@@ -2786,7 +2809,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
.ret = 0,
};
- iter_snap_objects(sctx, snap_obj_fn, &data);
+ iter_snap_objects(sctx, params, snap_obj_fn, &data);
return data.ret;
}
@@ -2857,21 +2880,13 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,
Object **r_ob,
float r_obmat[4][4])
{
- sctx->runtime.params = params;
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.v3d = v3d;
return raycastObjects(
- sctx, ray_start, ray_normal, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
+ sctx, params, ray_start, ray_normal, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
-/**
- * Fill in a list of all hits.
- *
- * \param ray_depth: Only depths in this range are considered, -1.0 for maximum.
- * \param sort: Optionally sort the hits by depth.
- * \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
- */
bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
Depsgraph *depsgraph,
const View3D *v3d,
@@ -2882,7 +2897,6 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
bool sort,
ListBase *r_hit_list)
{
- sctx->runtime.params = params;
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.v3d = v3d;
@@ -2895,7 +2909,7 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
#endif
bool retval = raycastObjects(
- sctx, ray_start, ray_normal, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list);
+ sctx, params, ray_start, ray_normal, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list);
/* meant to be readonly for 'all' hits, ensure it is */
#ifdef DEBUG
@@ -2982,7 +2996,6 @@ static short transform_snap_context_project_view3d_mixed_impl(
float r_obmat[4][4],
float r_face_nor[3])
{
- sctx->runtime.params = params;
sctx->runtime.depsgraph = depsgraph;
sctx->runtime.region = region;
sctx->runtime.v3d = v3d;
@@ -3015,8 +3028,17 @@ static short transform_snap_context_project_view3d_mixed_impl(
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
- has_hit = raycastObjects(
- sctx, ray_start, ray_normal, &dummy_ray_depth, loc, no, &index, &ob_eval, obmat, NULL);
+ has_hit = raycastObjects(sctx,
+ params,
+ ray_start,
+ ray_normal,
+ &dummy_ray_depth,
+ loc,
+ no,
+ &index,
+ &ob_eval,
+ obmat,
+ NULL);
if (has_hit) {
if (r_face_nor) {
@@ -3086,7 +3108,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem_test = snap_mesh_polygon(sctx, ob_eval, obmat, &dist_px_tmp, loc, no, &index);
+ elem_test = snap_mesh_polygon(sctx, params, ob_eval, obmat, &dist_px_tmp, loc, no, &index);
if (elem_test) {
elem = elem_test;
}
@@ -3100,7 +3122,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
sctx->runtime.has_occlusion_plane = true;
}
- elem_test = snapObjectsRay(sctx, &dist_px_tmp, loc, no, &index, &ob_eval, obmat);
+ elem_test = snapObjectsRay(sctx, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat);
if (elem_test) {
elem = elem_test;
}
@@ -3110,7 +3132,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
SCE_SNAP_MODE_EDGE_PERPENDICULAR))) {
sctx->runtime.snap_to_flag = snap_to_flag;
elem = snap_mesh_edge_verts_mixed(
- sctx, ob_eval, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
+ sctx, params, ob_eval, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
}
if (elem & snap_to_flag) {
@@ -3174,19 +3196,6 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
r_face_nor);
}
-/**
- * Convenience function for performing snapping.
- *
- * Given a 2D region value, snap to vert/edge/face.
- *
- * \param sctx: Snap context.
- * \param mval: Screenspace coordinate.
- * \param prev_co: Coordinate for perpendicular point calculation (optional).
- * \param dist_px: Maximum distance to snap (in pixels).
- * \param r_loc: hit location.
- * \param r_no: hit normal (optional).
- * \return Snap success
- */
short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
Depsgraph *depsgraph,
const ARegion *region,
@@ -3216,9 +3225,6 @@ short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
NULL);
}
-/**
- * see: #ED_transform_snap_object_project_ray_all
- */
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
Depsgraph *depsgraph,
const ARegion *region,
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index fa722d0646a..c6fa5acfff5 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -64,6 +64,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -77,9 +78,6 @@ static CLG_LogRef LOG = {"ed.undo"};
* Non-operator undo editor functions.
* \{ */
-/**
- * Run from the main event loop, basic checks that undo is left in a correct state.
- */
bool ED_undo_is_state_valid(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -377,6 +375,9 @@ static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *
wmWindowManager *wm = CTX_wm_manager(C);
const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
+ if (undo_index == active_step_index) {
+ return OPERATOR_CANCELLED;
+ }
const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO;
CLOG_INFO(&LOG,
@@ -438,7 +439,6 @@ void ED_undo_pop_op(bContext *C, wmOperator *op)
ed_undo_step_by_name(C, op->type->name, op->reports);
}
-/* name optionally, function used to check for operator redo panel */
bool ED_undo_is_valid(const bContext *C, const char *undoname)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -461,14 +461,6 @@ bool ED_undo_is_memfile_compatible(const bContext *C)
return true;
}
-/**
- * When a property of ID changes, return false.
- *
- * This is to avoid changes to a property making undo pushes
- * which are ignored by the undo-system.
- * For example, changing a brush property isn't stored by sculpt-mode undo steps.
- * This workaround is needed until the limitation is removed, see: T61948.
- */
bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -494,13 +486,6 @@ bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
return true;
}
-/**
- * Ideally we won't access the stack directly,
- * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
- *
- * Using global isn't great, this just avoids doing inline,
- * causing 'BKE_global.h' & 'BKE_main.h' includes.
- */
UndoStack *ED_undo_stack_get(void)
{
wmWindowManager *wm = G_MAIN->wm.first;
@@ -513,17 +498,28 @@ UndoStack *ED_undo_stack_get(void)
/** \name Undo, Undo Push & Redo Operators
* \{ */
+/**
+ * Refresh to run after user activated undo/redo actions.
+ */
+static void ed_undo_refresh_for_op(bContext *C)
+{
+ /* The "last operator" should disappear, later we can tie this with undo stack nicer. */
+ WM_operator_stack_clear(CTX_wm_manager(C));
+
+ /* Keep button under the cursor active. */
+ WM_event_add_mousemove(CTX_wm_window(C));
+
+ ED_outliner_select_sync_from_all_tag(C);
+}
+
static int ed_undo_exec(bContext *C, wmOperator *op)
{
/* "last operator" should disappear, later we can tie this with undo stack nicer */
WM_operator_stack_clear(CTX_wm_manager(C));
int ret = ed_undo_step_direction(C, STEP_UNDO, op->reports);
if (ret & OPERATOR_FINISHED) {
- /* Keep button under the cursor active. */
- WM_event_add_mousemove(CTX_wm_window(C));
+ ed_undo_refresh_for_op(C);
}
-
- ED_outliner_select_sync_from_all_tag(C);
return ret;
}
@@ -548,11 +544,8 @@ static int ed_redo_exec(bContext *C, wmOperator *op)
{
int ret = ed_undo_step_direction(C, STEP_REDO, op->reports);
if (ret & OPERATOR_FINISHED) {
- /* Keep button under the cursor active. */
- WM_event_add_mousemove(CTX_wm_window(C));
+ ed_undo_refresh_for_op(C);
}
-
- ED_outliner_select_sync_from_all_tag(C);
return ret;
}
@@ -682,7 +675,6 @@ void ED_OT_undo_redo(wmOperatorType *ot)
/** \name Operator Repeat
* \{ */
-/* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
int ED_undo_operator_repeat(bContext *C, wmOperator *op)
{
int ret = 0;
@@ -768,97 +760,36 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_un
/* -------------------------------------------------------------------- */
/** \name Undo History Operator
+ *
+ * See `TOPBAR_MT_undo_history` which is used to access this operator.
* \{ */
-/* create enum based on undo items */
-static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
-{
- EnumPropertyItem item_tmp = {0}, *item = NULL;
- int i = 0;
-
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->undo_stack == NULL) {
- return NULL;
- }
-
- for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
- if (us->skip == false) {
- item_tmp.identifier = us->name;
- item_tmp.name = IFACE_(us->name);
- if (us == wm->undo_stack->step_active) {
- item_tmp.icon = ICON_LAYER_ACTIVE;
- }
- else {
- item_tmp.icon = ICON_NONE;
- }
- item_tmp.value = i;
- RNA_enum_item_add(&item, totitem, &item_tmp);
- }
- }
- RNA_enum_item_end(&item, totitem);
-
- return item;
-}
-
-static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
+static int undo_history_exec(bContext *C, wmOperator *op)
{
- int totitem = 0;
-
- {
- const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
-
- if (totitem > 0) {
- uiPopupMenu *pup = UI_popup_menu_begin(
- C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
- uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
- uiLayout *column = NULL;
- const int col_size = 20 + totitem / 12;
- int i, c;
- bool add_col = true;
-
- for (c = 0, i = totitem; i--;) {
- if (add_col && !(c % col_size)) {
- column = uiLayoutColumn(split, false);
- add_col = false;
- }
- if (item[i].identifier) {
- uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
- c++;
- add_col = true;
- }
- }
-
- MEM_freeN((void *)item);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ const int item = RNA_property_int_get(op->ptr, prop);
+ const int ret = ed_undo_step_by_index(C, item, op->reports);
+ if (ret & OPERATOR_FINISHED) {
+ ed_undo_refresh_for_op(C);
- UI_popup_menu_end(C, pup);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ return OPERATOR_FINISHED;
}
}
return OPERATOR_CANCELLED;
}
-/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
-static int undo_history_exec(bContext *C, wmOperator *op)
+static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
if (RNA_property_is_set(op->ptr, prop)) {
- int item = RNA_property_int_get(op->ptr, prop);
- WM_operator_stack_clear(CTX_wm_manager(C));
- ed_undo_step_by_index(C, item, op->reports);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- return OPERATOR_FINISHED;
+ return undo_history_exec(C, op);
}
- return OPERATOR_CANCELLED;
-}
-static bool undo_history_poll(bContext *C)
-{
- if (!ed_undo_is_init_and_screenactive_poll(C)) {
- return false;
- }
- UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
- /* More than just original state entry. */
- return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1;
+ WM_menu_name_call(C, "TOPBAR_MT_undo_history", WM_OP_INVOKE_DEFAULT);
+ return OPERATOR_FINISHED;
}
void ED_OT_undo_history(wmOperatorType *ot)
@@ -871,7 +802,7 @@ void ED_OT_undo_history(wmOperatorType *ot)
/* api callbacks */
ot->invoke = undo_history_invoke;
ot->exec = undo_history_exec;
- ot->poll = undo_history_poll;
+ ot->poll = ed_undo_is_init_and_screenactive_poll;
RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
}
@@ -899,9 +830,6 @@ void ED_undo_object_set_active_or_warn(
}
}
-/**
- * Load all our objects from `object_array` into edit-mode, clear everything else.
- */
void ED_undo_object_editmode_restore_helper(struct bContext *C,
Object **object_array,
uint object_array_len,
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
index 1bdc2b2251e..b6ad5603808 100644
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -35,6 +35,7 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
+#include "BKE_icons.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@@ -48,6 +49,7 @@
#include "WM_types.h"
#include "ED_object.h"
+#include "ED_render.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -142,6 +144,32 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_NOP;
}
+/**
+ * ID previews may be generated in a parallel job. So whatever operation generates the preview
+ * likely does the undo push before the preview is actually done and stored in the ID. Hence they
+ * get some extra treatment here:
+ * When undoing back to the moment the preview generation was triggered, this function schedules
+ * the preview for regeneration.
+ */
+static void memfile_undosys_unfinished_id_previews_restart(ID *id)
+{
+ PreviewImage *preview = BKE_previewimg_id_get(id);
+ if (!preview) {
+ return;
+ }
+
+ for (int i = 0; i < NUM_ICON_SIZES; i++) {
+ if (preview->flag[i] & PRV_USER_EDITED) {
+ /* Don't modify custom previews. */
+ continue;
+ }
+
+ if (!BKE_previewimg_is_finished(preview, i)) {
+ ED_preview_restart_queue_add(id, i);
+ }
+ }
+}
+
static void memfile_undosys_step_decode(struct bContext *C,
struct Main *bmain,
UndoStep *us_p,
@@ -188,6 +216,9 @@ static void memfile_undosys_step_decode(struct bContext *C,
}
ED_editors_exit(bmain, false);
+ /* Ensure there's no preview job running. Unfinished previews will be scheduled for regeneration
+ * via #memfile_undosys_unfinished_id_previews_restart(). */
+ ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
MemFileUndoStep *us = (MemFileUndoStep *)us_p;
BKE_memfile_undo_decode(us->data, undo_direction, use_old_bmain_data, C);
@@ -239,6 +270,9 @@ static void memfile_undosys_step_decode(struct bContext *C,
bmain, &scene->master_collection->id, scene->master_collection->id.recalc);
}
}
+
+ /* Restart preview generation if the undo state was generating previews. */
+ memfile_undosys_unfinished_id_previews_restart(id);
}
FOREACH_MAIN_ID_END;
@@ -263,6 +297,14 @@ static void memfile_undosys_step_decode(struct bContext *C,
}
FOREACH_MAIN_ID_END;
}
+ else {
+ ID *id = NULL;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ /* Restart preview generation if the undo state was generating previews. */
+ memfile_undosys_unfinished_id_previews_restart(id);
+ }
+ FOREACH_MAIN_ID_END;
+ }
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
}
@@ -283,7 +325,6 @@ static void memfile_undosys_step_free(UndoStep *us_p)
BKE_memfile_undo_free(us->data);
}
-/* Export for ED_undo_sys. */
void ED_memfile_undosys_type(UndoType *ut)
{
ut->name = "Global Undo";
@@ -322,21 +363,6 @@ struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack)
return NULL;
}
-/**
- * If the last undo step is a memfile one, find the first #MemFileChunk matching given ID
- * (using its session UUID), and tag it as "changed in the future".
- *
- * Since non-memfile undo-steps cannot automatically set this flag in the previous step as done
- * with memfile ones, this has to be called manually by relevant undo code.
- *
- * \note Only current known case for this is undoing a switch from Object to Sculpt mode (see
- * T82388).
- *
- * \note Calling this ID by ID is not optimal, as it will loop over all #MemFile.chunks until it
- * finds the expected one. If this becomes an issue we'll have to add a mapping from session UUID
- * to first #MemFileChunk in #MemFile itself
- * (currently we only do that in #MemFileWriteData when writing a new step).
- */
void ED_undosys_stack_memfile_id_changed_tag(UndoStack *ustack, ID *id)
{
UndoStep *us = ustack->step_active;
diff --git a/source/blender/editors/undo/undo_intern.h b/source/blender/editors/undo/undo_intern.h
index 660f1a5b57d..d27bc1c8c0a 100644
--- a/source/blender/editors/undo/undo_intern.h
+++ b/source/blender/editors/undo/undo_intern.h
@@ -25,4 +25,6 @@
struct UndoType;
/* memfile_undo.c */
+
+/** Export for ED_undo_sys. */
void ED_memfile_undosys_type(struct UndoType *ut);
diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c
index 721e32a3051..ccbde07f5b1 100644
--- a/source/blender/editors/util/ed_draw.c
+++ b/source/blender/editors/util/ed_draw.c
@@ -397,17 +397,11 @@ tSlider *ED_slider_create(struct bContext *C)
return slider;
}
-/**
- * For modal operations so the percentage doesn't pop on the first mouse movement.
- */
void ED_slider_init(struct tSlider *slider, const wmEvent *event)
{
copy_v2fl_v2i(slider->last_cursor, event->xy);
}
-/**
- * Calculate slider factor based on mouse position.
- */
bool ED_slider_modal(tSlider *slider, const wmEvent *event)
{
bool event_handled = true;
@@ -441,9 +435,6 @@ bool ED_slider_modal(tSlider *slider, const wmEvent *event)
return event_handled;
}
-/**
- * Return string based on the current state of the slider.
- */
void ED_slider_status_string_get(const struct tSlider *slider,
char *status_string,
const size_t size_of_status_string)
@@ -523,9 +514,6 @@ void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value)
/** \} */
-/**
- * Callback that draws a line between the mouse and a position given as the initial argument.
- */
void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_info)
{
wmWindow *win = CTX_wm_window(C);
@@ -776,9 +764,6 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
return 0;
}
-/**
- * \note Keep in sync with #BKE_image_stamp_buf.
- */
void ED_region_image_metadata_draw(
int x, int y, ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy)
{
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 348deec1166..882f140c063 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -195,7 +195,6 @@ void ED_editors_init(bContext *C)
wm->op_undo_depth--;
}
-/* frees all editmode stuff */
void ED_editors_exit(Main *bmain, bool do_undo_system)
{
if (!bmain) {
@@ -291,8 +290,6 @@ bool ED_editors_flush_edits_for_object(Main *bmain, Object *ob)
return ED_editors_flush_edits_for_object_ex(bmain, ob, false, false);
}
-/* flush any temp data from object editing to DNA before writing files,
- * rendering, copying, etc. */
bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_flush)
{
bool has_edited = false;
@@ -317,11 +314,6 @@ bool ED_editors_flush_edits(Main *bmain)
/* ***** XXX: functions are using old blender names, cleanup later ***** */
-/**
- * Now only used in 2D spaces, like time, f-curve, NLA, image, etc.
- *
- * \note Shift/Control are not configurable key-bindings.
- */
void apply_keyb_grid(
int shift, int ctrl, float *val, float fac1, float fac2, float fac3, int invert)
{
@@ -360,6 +352,7 @@ void unpack_menu(bContext *C,
uiLayout *layout;
char line[FILE_MAX + 100];
wmOperatorType *ot = WM_operatortype_find(opname, 1);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
pup = UI_popup_menu_begin(C, IFACE_("Unpack File"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
@@ -369,13 +362,13 @@ void unpack_menu(bContext *C,
RNA_enum_set(&props_ptr, "method", PF_REMOVE);
RNA_string_set(&props_ptr, "id", id_name);
- if (G.relbase_valid) {
+ if (blendfile_path[0] != '\0') {
char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
BLI_split_file_part(abs_name, fi, sizeof(fi));
BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi);
if (!STREQ(abs_name, local_name)) {
- switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), local_name, pf)) {
+ switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) {
case PF_CMP_NOFILE:
BLI_snprintf(line, sizeof(line), TIP_("Create %s"), local_name);
uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr);
@@ -408,7 +401,7 @@ void unpack_menu(bContext *C,
}
}
- switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), abs_name, pf)) {
+ switch (BKE_packedfile_compare_to_file(blendfile_path, abs_name, pf)) {
case PF_CMP_NOFILE:
BLI_snprintf(line, sizeof(line), TIP_("Create %s"), abs_name);
// uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
@@ -441,11 +434,6 @@ void unpack_menu(bContext *C,
UI_popup_menu_end(C, pup);
}
-/**
- * Use to free ID references within runtime data (stored outside of DNA)
- *
- * \param new_id: may be NULL to unlink \a old_id.
- */
void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc
index 7d32d252718..a1b17d799bc 100644
--- a/source/blender/editors/util/ed_util_ops.cc
+++ b/source/blender/editors/util/ed_util_ops.cc
@@ -110,7 +110,7 @@ static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
ot->invoke = WM_operator_filesel;
/* flags */
- ot->flag = OPTYPE_INTERNAL;
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE,
@@ -276,7 +276,7 @@ static void ED_OT_flush_edits(wmOperatorType *ot)
/** \} */
-void ED_operatortypes_edutils(void)
+void ED_operatortypes_edutils()
{
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
WM_operatortype_append(ED_OT_lib_id_generate_preview);
diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c
index 08e7b3a9a0a..99df194f0eb 100644
--- a/source/blender/editors/util/gizmo_utils.c
+++ b/source/blender/editors/util/gizmo_utils.c
@@ -70,7 +70,6 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C,
return true;
}
-/** Can use this as poll function directly. */
bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupType *gzgt)
{
return ED_gizmo_poll_or_unlink_delayed_from_tool_ex(C, gzgt, gzgt->idname);
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index d0f27770d9b..583e4060a9a 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -98,7 +98,6 @@ void initNumInput(NumInput *n)
n->str_cur = 0;
}
-/* str must be NUM_STR_REP_LEN * (idx_max + 1) length. */
void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
{
short j;
@@ -201,9 +200,6 @@ bool hasNumInput(const NumInput *n)
return false;
}
-/**
- * \warning \a vec must be set beforehand otherwise we risk uninitialized vars.
- */
bool applyNumInput(NumInput *n, float *vec)
{
short i, j;
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
index 99412079adf..c7bb26db1bd 100644
--- a/source/blender/editors/util/select_utils.c
+++ b/source/blender/editors/util/select_utils.c
@@ -26,7 +26,6 @@
#include "ED_select_utils.h"
-/** 1: select, 0: deselect, -1: pass. */
int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside)
{
switch (sel_op) {
@@ -44,12 +43,6 @@ int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool
BLI_assert_msg(0, "invalid sel_op");
return -1;
}
-/**
- * Use when we've de-selected all items first (for modes that need it).
- *
- * \note In some cases changing selection needs to perform other checks,
- * so it's more straightforward to deselect all, then select.
- */
int ED_select_op_action_deselected(const eSelectOp sel_op,
const bool is_select,
const bool is_inside)
@@ -71,9 +64,6 @@ int ED_select_op_action_deselected(const eSelectOp sel_op,
return -1;
}
-/**
- * Utility to use for selection operations that run multiple times (circle select).
- */
eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
{
if (sel_op == SEL_OP_SET) {
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 9bc8a165b1f..0a0dd9a133b 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -95,6 +95,15 @@ bool uv_find_nearest_edge_multi(struct Scene *scene,
const float penalty,
struct UvNearestHit *hit);
+/**
+ * \param only_in_face: when true, only hit faces which `co` is inside.
+ * This gives users a result they might expect, especially when zoomed in.
+ *
+ * \note Concave faces can cause odd behavior, although in practice this isn't often an issue.
+ * The center can be outside the face, in this case the distance to the center
+ * could cause the face to be considered too far away.
+ * If this becomes an issue we could track the distance to the faces closest edge.
+ */
bool uv_find_nearest_face_ex(struct Scene *scene,
struct Object *obedit,
const float co[2],
@@ -167,6 +176,10 @@ bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit);
bool uvedit_select_is_any_selected_multi(struct Scene *scene,
struct Object **objects,
const uint objects_len);
+/**
+ * \warning This returns first selected UV,
+ * not ideal in many cases since there could be multiple.
+ */
const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene,
struct BMVert *eve,
const int cd_loop_uv_offset);
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
index 6159758dbcd..63a7ab6ab2d 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -237,9 +237,6 @@ static void bm_face_array_uv_scale_y(BMFace **faces,
/** \name UDIM packing helper functions
* \{ */
-/**
- * Returns true if UV coordinates lie on a valid tile in UDIM grid or tiled image.
- */
bool uv_coords_isect_udim(const Image *image, const int udim_grid[2], const float coords[2])
{
const float coords_floor[2] = {floorf(coords[0]), floorf(coords[1])};
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index acdffd5ff98..342afa847b4 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -253,7 +253,6 @@ bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float
return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max);
}
-/* Be careful when using this, it bypasses all synchronization options */
void ED_uvedit_select_all(BMesh *bm)
{
BMFace *efa;
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 83e8259f693..22467c7391f 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -166,10 +166,6 @@ BMLoop *ED_uvedit_active_edge_loop_get(BMesh *bm)
/** \name Visibility and Selection Utilities
* \{ */
-/**
- * Intentionally don't return #UV_SELECT_ISLAND as it's not an element type.
- * In this case return #UV_SELECT_VERTEX as a fallback.
- */
char ED_uvedit_select_mode_get(const Scene *scene)
{
const ToolSettings *ts = scene->toolsettings;
@@ -946,15 +942,6 @@ bool uv_find_nearest_edge_multi(Scene *scene,
return found;
}
-/**
- * \param only_in_face: when true, only hit faces which `co` is inside.
- * This gives users a result they might expect, especially when zoomed in.
- *
- * \note Concave faces can cause odd behavior, although in practice this isn't often an issue.
- * The center can be outside the face, in this case the distance to the center
- * could cause the face to be considered too far away.
- * If this becomes an issue we could track the distance to the faces closest edge.
- */
bool uv_find_nearest_face_ex(
Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face)
{
@@ -2082,10 +2069,6 @@ static void uv_select_linked_multi(Scene *scene,
}
}
-/**
- * \warning This returns first selected UV,
- * not ideal in many cases since there could be multiple.
- */
const float *uvedit_first_selected_uv_from_vertex(Scene *scene,
BMVert *eve,
const int cd_loop_uv_offset)
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index db838bf353b..362e020f306 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -2826,6 +2826,8 @@ void UV_OT_cylinder_project(wmOperatorType *ot)
uv_map_clip_correct_properties(ot);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Cube UV Project Operator
* \{ */
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index bc5e9d49bee..77e906c6ea5 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -59,6 +59,10 @@ void FRS_exit(void);
void FRS_copy_active_lineset(struct FreestyleConfig *config);
void FRS_paste_active_lineset(struct FreestyleConfig *config);
void FRS_delete_active_lineset(struct FreestyleConfig *config);
+/**
+ * Reinsert the active lineset at an offset \a direction from current position.
+ * \return if position of active lineset has changed.
+ */
bool FRS_move_active_lineset(struct FreestyleConfig *config, int direction);
/* Testing */
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index b31f4fd2303..ce80ed78594 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -769,10 +769,6 @@ void FRS_delete_active_lineset(FreestyleConfig *config)
}
}
-/**
- * Reinsert the active lineset at an offset \a direction from current position.
- * \return if position of active lineset has changed.
- */
bool FRS_move_active_lineset(FreestyleConfig *config, int direction)
{
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h
index 2cb3e7d7ac5..af537cf2d86 100644
--- a/source/blender/freestyle/intern/image/GaussianFilter.h
+++ b/source/blender/freestyle/intern/image/GaussianFilter.h
@@ -37,14 +37,16 @@ namespace Freestyle {
class GaussianFilter {
protected:
/* The mask is a symmetrical 2d array (with respect to the middle point).
- * Thus, M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j).
- * For this reason, to represent a NxN array (N odd), we only store a ((N+1)/2)x((N+1)/2) array.
- */
+ * Thus: `M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j)`.
+ * For this reason, to represent a NxN array (N odd),
+ * we only store a `((N+1)/2)x((N+1)/2)` array. */
+
+ /** The sigma value of the gaussian function. */
float _sigma;
float *_mask;
int _bound;
- // the real mask size (must be odd)(the size of the mask we store is
- // ((_maskSize+1)/2)*((_maskSize+1)/2))
+ /* the real mask size (must be odd)(the size of the mask we store is:
+ * `((_maskSize+1)/2)*((_maskSize+1)/2))`. */
int _maskSize;
int _storedMaskSize; // (_maskSize+1)/2)
@@ -65,8 +67,6 @@ class GaussianFilter {
* The abscissa of the pixel where we want to evaluate the gaussian blur.
* \param y:
* The ordinate of the pixel where we want to evaluate the gaussian blur.
- * \param sigma:
- * The sigma value of the gaussian function.
*/
template<class Map> float getSmoothedPixel(Map *map, int x, int y);
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
index 52cd037a73a..b41beb356c4 100644
--- a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
+++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
@@ -119,7 +119,7 @@ class SmoothingShader : public StrokeShader {
* 0.2
* \param iAnisoPoint:
* 0
- * \param iAnisNormal:
+ * \param iAnisoNormal:
* 0
* \param iAnisoCurvature:
* 0
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 50ebacbd6e8..90dbc259038 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -71,7 +71,7 @@ class PythonInterpreter : public Interpreter {
bool ok = BPY_run_filepath(_context, fn, reports);
#else
bool ok;
- Text *text = BKE_text_load(&_freestyle_bmain, fn, G_MAIN->name);
+ Text *text = BKE_text_load(&_freestyle_bmain, fn, G_MAIN->filepath);
if (text) {
ok = BPY_run_text(_context, text, reports, false);
BKE_id_delete(&_freestyle_bmain, text);
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 411685bd921..ec07a124808 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -104,27 +104,6 @@ static real angle_from_cotan(WVertex *vo, WVertex *v1, WVertex *v2)
return (fabs(atan2(denom, udotv)));
}
-/** gts_vertex_mean_curvature_normal:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kh: the Mean Curvature Normal at \a v.
- *
- * Computes the Discrete Mean Curvature Normal approximation at \a v.
- * The mean curvature at \a v is half the magnitude of the vector \a Kh.
- *
- * NOTE: the normal computed is not unit length, and may point either into or out of the surface,
- * depending on the curvature at \a v. It is the responsibility of the caller of the function to
- * use the mean curvature normal appropriately.
- *
- * This approximation is from the paper:
- * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
- * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
- * VisMath '02, Berlin (Germany)
- * http://www-grail.usc.edu/pubs.html
- *
- * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
- * reason (@v is boundary or is the endpoint of a non-manifold edge.)
- */
bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
{
real area = 0.0;
@@ -175,22 +154,6 @@ bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
return true;
}
-/** gts_vertex_gaussian_curvature:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kg: the Discrete Gaussian Curvature approximation at \a v.
- *
- * Computes the Discrete Gaussian Curvature approximation at \a v.
- *
- * This approximation is from the paper:
- * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
- * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
- * VisMath '02, Berlin (Germany)
- * http://www-grail.usc.edu/pubs.html
- *
- * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
- * reason (@v is boundary or is the endpoint of a non-manifold edge.)
- */
bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg)
{
real area = 0.0;
@@ -226,20 +189,6 @@ bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg)
return true;
}
-/** gts_vertex_principal_curvatures:
- * @Kh: mean curvature.
- * @Kg: Gaussian curvature.
- * @K1: first principal curvature.
- * @K2: second principal curvature.
- *
- * Computes the principal curvatures at a point given the mean and Gaussian curvatures at that
- * point.
- *
- * The mean curvature can be computed as one-half the magnitude of the vector computed by
- * gts_vertex_mean_curvature_normal().
- *
- * The Gaussian curvature can be computed with gts_vertex_gaussian_curvature().
- */
void gts_vertex_principal_curvatures(real Kh, real Kg, real *K1, real *K2)
{
real temp = Kh * Kh - Kg;
@@ -279,21 +228,6 @@ static void eigenvector(real a, real b, real c, Vec3r e)
e[2] = 0.0;
}
-/** gts_vertex_principal_directions:
- * \param v: a #WVertex.
- * \param s: a #GtsSurface.
- * \param Kh: mean curvature normal (a #Vec3r).
- * \param Kg: Gaussian curvature (a real).
- * \param e1: first principal curvature direction (direction of largest curvature).
- * \param e2: second principal curvature direction.
- *
- * Computes the principal curvature directions at a point given \a Kh and \a Kg,
- * the mean curvature normal and Gaussian curvatures at that point, computed with
- * gts_vertex_mean_curvature_normal() and gts_vertex_gaussian_curvature(), respectively.
- *
- * Note that this computation is very approximate and tends to be unstable. Smoothing of the
- * surface or the principal directions may be necessary to achieve reasonable results.
- */
void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2)
{
Vec3r N;
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.h b/source/blender/freestyle/intern/winged_edge/Curvature.h
index 0eefc57c3a2..acbe4e8daf6 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.h
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.h
@@ -122,12 +122,75 @@ class Face_Curvature_Info {
#endif
};
+/**
+ * \param v: a #WVertex.
+ * \param Kh: the Mean Curvature Normal at \a v.
+ *
+ * Computes the Discrete Mean Curvature Normal approximation at \a v.
+ * The mean curvature at \a v is half the magnitude of the vector \a Kh.
+ *
+ * \note the normal computed is not unit length, and may point either into or out of the surface,
+ * depending on the curvature at \a v. It is the responsibility of the caller of the function to
+ * use the mean curvature normal appropriately.
+ *
+ * This approximation is from the paper:
+ * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
+ * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
+ * VisMath '02, Berlin (Germany)
+ * http://www-grail.usc.edu/pubs.html
+ *
+ * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
+ * reason (`v` is boundary or is the endpoint of a non-manifold edge.)
+ */
bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh);
+/**
+ * \param v: a #WVertex.
+ * \param Kg: the Discrete Gaussian Curvature approximation at \a v.
+ *
+ * Computes the Discrete Gaussian Curvature approximation at \a v.
+ *
+ * This approximation is from the paper:
+ * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
+ * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
+ * VisMath '02, Berlin (Germany)
+ * http://www-grail.usc.edu/pubs.html
+ *
+ * Returns: %true if the operator could be evaluated, %false if the evaluation failed for some
+ * reason (`v` is boundary or is the endpoint of a non-manifold edge.)
+ */
bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg);
+/**
+ * \param Kh: mean curvature.
+ * \param Kg: Gaussian curvature.
+ * \param K1: first principal curvature.
+ * \param K2: second principal curvature.
+ *
+ * Computes the principal curvatures at a point given the mean and Gaussian curvatures at that
+ * point.
+ *
+ * The mean curvature can be computed as one-half the magnitude of the vector computed by
+ * #gts_vertex_mean_curvature_normal().
+ *
+ * The Gaussian curvature can be computed with gts_vertex_gaussian_curvature().
+ */
void gts_vertex_principal_curvatures(real Kh, real Kg, real *K1, real *K2);
+/**
+ * \param v: a #WVertex.
+ * \param Kh: mean curvature normal (a #Vec3r).
+ * \param Kg: Gaussian curvature (a real).
+ * \param e1: first principal curvature direction (direction of largest curvature).
+ * \param e2: second principal curvature direction.
+ *
+ * Computes the principal curvature directions at a point given \a Kh and \a Kg,
+ * the mean curvature normal and Gaussian curvatures at that point, computed with
+ * #gts_vertex_mean_curvature_normal() and #gts_vertex_gaussian_curvature(), respectively.
+ *
+ * Note that this computation is very approximate and tends to be unstable. Smoothing of the
+ * surface or the principal directions may be necessary to achieve reasonable results.
+ */
void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2);
namespace OGF {
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 54670c0d1b3..9cfaf3eabea 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -34,10 +34,11 @@ set(SRC
intern/generic_virtual_vector_array.cc
intern/multi_function.cc
intern/multi_function_builder.cc
- intern/multi_function_parallel.cc
+ intern/multi_function_params.cc
intern/multi_function_procedure.cc
intern/multi_function_procedure_builder.cc
intern/multi_function_procedure_executor.cc
+ intern/multi_function_procedure_optimization.cc
FN_cpp_type.hh
FN_cpp_type_make.hh
@@ -54,12 +55,12 @@ set(SRC
FN_multi_function_builder.hh
FN_multi_function_context.hh
FN_multi_function_data_type.hh
- FN_multi_function_parallel.hh
FN_multi_function_param_type.hh
FN_multi_function_params.hh
FN_multi_function_procedure.hh
FN_multi_function_procedure_builder.hh
FN_multi_function_procedure_executor.hh
+ FN_multi_function_procedure_optimization.hh
FN_multi_function_signature.hh
)
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index 643b2fc1f28..7ddb5bf1f46 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -207,6 +207,18 @@ class CPPType : NonCopyable, NonMovable {
return is_trivially_destructible_;
}
+ /**
+ * When true, the value is like a normal C type, it can be copied around with #memcpy and does
+ * not have to be destructed.
+ *
+ * C++ equivalent:
+ * std::is_trivial_v<T>;
+ */
+ bool is_trivial() const
+ {
+ return is_trivial_;
+ }
+
bool is_default_constructible() const
{
return default_construct_ != nullptr;
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index fb488fdbfa9..a591aaed34a 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -49,16 +49,15 @@
#include "BLI_function_ref.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
#include "FN_generic_virtual_array.hh"
#include "FN_multi_function_builder.hh"
-#include "FN_multi_function_procedure.hh"
-#include "FN_multi_function_procedure_builder.hh"
-#include "FN_multi_function_procedure_executor.hh"
namespace blender::fn {
class FieldInput;
+struct FieldInputs;
/**
* A node in a field-tree. It has at least one output that can be referenced by fields.
@@ -66,18 +65,18 @@ class FieldInput;
class FieldNode {
private:
bool is_input_;
+
+ protected:
/**
- * True when this node is a #FieldInput or (potentially indirectly) depends on one. This could
- * always be derived again later by traversing the field-tree, but keeping track of it while the
- * field is built is cheaper.
- *
- * If this is false, the field is constant. Note that even when this is true, the field may be
- * constant when all inputs are constant.
+ * Keeps track of the inputs that this node depends on. This avoids recomputing it every time the
+ * data is required. It is a shared pointer, because very often multiple nodes depend on the same
+ * inputs.
+ * Might contain null.
*/
- bool depends_on_input_;
+ std::shared_ptr<const FieldInputs> field_inputs_;
public:
- FieldNode(bool is_input, bool depends_on_input);
+ FieldNode(bool is_input);
virtual ~FieldNode() = default;
@@ -87,11 +86,7 @@ class FieldNode {
bool is_operation() const;
bool depends_on_input() const;
- /**
- * Invoke callback for every field input. It might be called multiple times for the same input.
- * The caller is responsible for deduplication if required.
- */
- virtual void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const = 0;
+ const std::shared_ptr<const FieldInputs> &field_inputs() const;
virtual uint64_t hash() const;
virtual bool is_equal_to(const FieldNode &other) const;
@@ -178,11 +173,19 @@ class GFieldRef : public GFieldBase<const FieldNode *> {
}
};
+namespace detail {
+/* Utility class to make #is_field_v work. */
+struct TypedFieldBase {
+};
+} // namespace detail
+
/**
* A typed version of #GField. It has the same memory layout as #GField.
*/
-template<typename T> class Field : public GField {
+template<typename T> class Field : public GField, detail::TypedFieldBase {
public:
+ using base_type = T;
+
Field() = default;
Field(GField field) : GField(std::move(field))
@@ -196,6 +199,11 @@ template<typename T> class Field : public GField {
}
};
+/** True when T is any Field<...> type. */
+template<typename T>
+static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> &&
+ !std::is_same_v<detail::TypedFieldBase, T>;
+
/**
* A #FieldNode that allows composing existing fields into new fields.
*/
@@ -218,7 +226,6 @@ class FieldOperation : public FieldNode {
const MultiFunction &multi_function() const;
const CPPType &output_cpp_type(int output_index) const override;
- void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const override;
};
class FieldContext;
@@ -258,7 +265,19 @@ class FieldInput : public FieldNode {
Category category() const;
const CPPType &output_cpp_type(int output_index) const override;
- void foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const override;
+};
+
+/**
+ * Keeps track of the inputs of a field.
+ */
+struct FieldInputs {
+ /** All #FieldInput nodes that a field (possibly indirectly) depends on. */
+ VectorSet<const FieldInput *> nodes;
+ /**
+ * Same as above but the inputs are deduplicated. For example, when there are two separate index
+ * input nodes, only one will show up in this list.
+ */
+ VectorSet<std::reference_wrapper<const FieldInput>> deduplicated_nodes;
};
/**
@@ -294,6 +313,9 @@ class FieldEvaluator : NonMovable, NonCopyable {
Vector<OutputPointerInfo> output_pointer_infos_;
bool is_evaluated_ = false;
+ Field<bool> selection_field_;
+ IndexMask selection_mask_;
+
public:
/** Takes #mask by pointer because the mask has to live longer than the evaluator. */
FieldEvaluator(const FieldContext &context, const IndexMask *mask)
@@ -314,6 +336,18 @@ class FieldEvaluator : NonMovable, NonCopyable {
}
/**
+ * The selection field is evaluated first to determine which indices of the other fields should
+ * be evaluated. Calling this method multiple times will just replace the previously set
+ * selection field. Only the elements selected by both this selection and the selection provided
+ * in the constructor are calculated. If no selection field is set, it is assumed that all
+ * indices passed to the constructor are selected.
+ */
+ void set_selection(Field<bool> selection)
+ {
+ selection_field_ = std::move(selection);
+ }
+
+ /**
* \param field: Field to add to the evaluator.
* \param dst: Mutable virtual array that the evaluated result for this field is be written into.
*/
@@ -384,6 +418,8 @@ class FieldEvaluator : NonMovable, NonCopyable {
return this->get_evaluated(field_index).typed<T>();
}
+ IndexMask get_evaluated_selection_as_mask();
+
/**
* Retrieve the output of an evaluated boolean field and convert it to a mask, which can be used
* to avoid calculations for unnecessary elements later on. The evaluator will own the indices in
@@ -392,6 +428,24 @@ class FieldEvaluator : NonMovable, NonCopyable {
IndexMask get_evaluated_as_mask(const int field_index);
};
+/**
+ * Evaluate fields in the given context. If possible, multiple fields should be evaluated together,
+ * because that can be more efficient when they share common sub-fields.
+ *
+ * \param scope: The resource scope that owns data that makes up the output virtual arrays. Make
+ * sure the scope is not destructed when the output virtual arrays are still used.
+ * \param fields_to_evaluate: The fields that should be evaluated together.
+ * \param mask: Determines which indices are computed. The mask may be referenced by the returned
+ * virtual arrays. So the underlying indices (if applicable) should live longer then #scope.
+ * \param context: The context that the field is evaluated in. Used to retrieve data from each
+ * #FieldInput in the field network.
+ * \param dst_varrays: If provided, the computed data will be written into those virtual arrays
+ * instead of into newly created ones. That allows making the computed data live longer than
+ * #scope and is more efficient when the data will be written into those virtual arrays
+ * later anyway.
+ * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the
+ * provided virtual arrays are returned.
+ */
Vector<GVArray> evaluate_fields(ResourceScope &scope,
Span<GFieldRef> fields_to_evaluate,
IndexMask mask,
@@ -419,13 +473,24 @@ template<typename T> Field<T> make_constant_field(T value)
return Field<T>{GField{std::move(operation), 0}};
}
+GField make_constant_field(const CPPType &type, const void *value);
+
+/**
+ * If the field depends on some input, the same field is returned.
+ * Otherwise the field is evaluated and a new field is created that just computes this constant.
+ *
+ * Making the field constant has two benefits:
+ * - The field-tree becomes a single node, which is more efficient when the field is evaluated many
+ * times.
+ * - Memory of the input fields may be freed.
+ */
GField make_field_constant_if_possible(GField field);
class IndexFieldInput final : public FieldInput {
public:
IndexFieldInput();
- static GVArray get_index_varray(IndexMask mask, ResourceScope &scope);
+ static GVArray get_index_varray(IndexMask mask);
GVArray get_varray_for_context(const FieldContext &context,
IndexMask mask,
@@ -438,11 +503,56 @@ class IndexFieldInput final : public FieldInput {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Value or Field Class
+ *
+ * Utility class that wraps a single value and a field, to simplify accessing both of the types.
+ * \{ */
+
+template<typename T> struct ValueOrField {
+ /** Value that is used when the field is empty. */
+ T value{};
+ Field<T> field;
+
+ ValueOrField() = default;
+
+ ValueOrField(T value) : value(std::move(value))
+ {
+ }
+
+ ValueOrField(Field<T> field) : field(std::move(field))
+ {
+ }
+
+ bool is_field() const
+ {
+ return (bool)this->field;
+ }
+
+ Field<T> as_field() const
+ {
+ if (this->field) {
+ return this->field;
+ }
+ return make_constant_field(this->value);
+ }
+
+ T as_value() const
+ {
+ if (this->field) {
+ /* This returns a default value when the field is not constant. */
+ return evaluate_constant_field(this->field);
+ }
+ return this->value;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name #FieldNode Inline Methods
* \{ */
-inline FieldNode::FieldNode(bool is_input, bool depends_on_input)
- : is_input_(is_input), depends_on_input_(depends_on_input)
+inline FieldNode::FieldNode(bool is_input) : is_input_(is_input)
{
}
@@ -458,7 +568,12 @@ inline bool FieldNode::is_operation() const
inline bool FieldNode::depends_on_input() const
{
- return depends_on_input_;
+ return field_inputs_ && !field_inputs_->nodes.is_empty();
+}
+
+inline const std::shared_ptr<const FieldInputs> &FieldNode::field_inputs() const
+{
+ return field_inputs_;
}
inline uint64_t FieldNode::hash() const
diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh
index 5e6f1b5a585..940faba6d70 100644
--- a/source/blender/functions/FN_field_cpp_type.hh
+++ b/source/blender/functions/FN_field_cpp_type.hh
@@ -30,19 +30,19 @@ template<typename T> struct FieldCPPTypeParam {
class FieldCPPType : public CPPType {
private:
- const CPPType &field_type_;
+ const CPPType &base_type_;
public:
template<typename T>
FieldCPPType(FieldCPPTypeParam<Field<T>> /* unused */, StringRef debug_name)
: CPPType(CPPTypeParam<Field<T>, CPPTypeFlags::None>(), debug_name),
- field_type_(CPPType::get<T>())
+ base_type_(CPPType::get<T>())
{
}
- const CPPType &field_type() const
+ const CPPType &base_type() const
{
- return field_type_;
+ return base_type_;
}
/* Ensure that #GField and #Field<T> have the same layout, to enable casting between the two. */
@@ -60,6 +60,84 @@ class FieldCPPType : public CPPType {
}
};
+class ValueOrFieldCPPType : public CPPType {
+ private:
+ const CPPType &base_type_;
+ void (*construct_from_value_)(void *dst, const void *value);
+ void (*construct_from_field_)(void *dst, GField field);
+ const void *(*get_value_ptr_)(const void *value_or_field);
+ const GField *(*get_field_ptr_)(const void *value_or_field);
+ bool (*is_field_)(const void *value_or_field);
+ GField (*as_field_)(const void *value_or_field);
+
+ public:
+ template<typename T>
+ ValueOrFieldCPPType(FieldCPPTypeParam<ValueOrField<T>> /* unused */, StringRef debug_name)
+ : CPPType(CPPTypeParam<ValueOrField<T>, CPPTypeFlags::None>(), debug_name),
+ base_type_(CPPType::get<T>())
+ {
+ construct_from_value_ = [](void *dst, const void *value_or_field) {
+ new (dst) ValueOrField<T>(*(const T *)value_or_field);
+ };
+ construct_from_field_ = [](void *dst, GField field) {
+ new (dst) ValueOrField<T>(Field<T>(std::move(field)));
+ };
+ get_value_ptr_ = [](const void *value_or_field) {
+ return (const void *)&((ValueOrField<T> *)value_or_field)->value;
+ };
+ get_field_ptr_ = [](const void *value_or_field) -> const GField * {
+ return &((ValueOrField<T> *)value_or_field)->field;
+ };
+ is_field_ = [](const void *value_or_field) {
+ return ((ValueOrField<T> *)value_or_field)->is_field();
+ };
+ as_field_ = [](const void *value_or_field) -> GField {
+ return ((ValueOrField<T> *)value_or_field)->as_field();
+ };
+ }
+
+ const CPPType &base_type() const
+ {
+ return base_type_;
+ }
+
+ void construct_from_value(void *dst, const void *value) const
+ {
+ construct_from_value_(dst, value);
+ }
+
+ void construct_from_field(void *dst, GField field) const
+ {
+ construct_from_field_(dst, field);
+ }
+
+ const void *get_value_ptr(const void *value_or_field) const
+ {
+ return get_value_ptr_(value_or_field);
+ }
+
+ void *get_value_ptr(void *value_or_field) const
+ {
+ /* Use `const_cast` to avoid duplicating the callback for the non-const case. */
+ return const_cast<void *>(get_value_ptr_(value_or_field));
+ }
+
+ const GField *get_field_ptr(const void *value_or_field) const
+ {
+ return get_field_ptr_(value_or_field);
+ }
+
+ bool is_field(const void *value_or_field) const
+ {
+ return is_field_(value_or_field);
+ }
+
+ GField as_field(const void *value_or_field) const
+ {
+ return as_field_(value_or_field);
+ }
+};
+
} // namespace blender::fn
#define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \
@@ -69,4 +147,13 @@ class FieldCPPType : public CPPType {
static blender::fn::FieldCPPType cpp_type{ \
blender::fn::FieldCPPTypeParam<blender::fn::Field<FIELD_TYPE>>(), STRINGIFY(DEBUG_NAME)}; \
return cpp_type; \
+ } \
+ template<> \
+ const blender::fn::CPPType & \
+ blender::fn::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \
+ { \
+ static blender::fn::ValueOrFieldCPPType cpp_type{ \
+ blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \
+ STRINGIFY(DEBUG_NAME##OrValue)}; \
+ return cpp_type; \
}
diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/functions/FN_generic_span.hh
index e2c49697ba9..6f0147b7fb3 100644
--- a/source/blender/functions/FN_generic_span.hh
+++ b/source/blender/functions/FN_generic_span.hh
@@ -93,6 +93,11 @@ class GSpan {
const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
return GSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
}
+
+ GSpan slice(const IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
};
/**
@@ -169,6 +174,11 @@ class GMutableSpan {
const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
return GMutableSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
}
+
+ GMutableSpan slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index b822f3a7c33..fc8612d6f87 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -148,14 +148,37 @@ class GVArrayCommon {
void materialize_to_uninitialized(void *dst) const;
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
+ /**
+ * Returns true when the virtual array is stored as a span internally.
+ */
bool is_span() const;
+ /**
+ * Returns the internally used span of the virtual array. This invokes undefined behavior is the
+ * virtual array is not stored as a span internally.
+ */
GSpan get_internal_span() const;
+ /**
+ * Returns true when the virtual array returns the same value for every index.
+ */
bool is_single() const;
+ /**
+ * Copies the value that is used for every element into `r_value`, which is expected to point to
+ * initialized memory. This invokes undefined behavior if the virtual array would not return the
+ * same value for every index.
+ */
void get_internal_single(void *r_value) const;
+ /**
+ * Same as `get_internal_single`, but `r_value` points to initialized memory.
+ */
void get_internal_single_to_uninitialized(void *r_value) const;
void get(const int64_t index, void *r_value) const;
+ /**
+ * Returns a copy of the value at the given index. Usually a typed virtual array should
+ * be used instead, but sometimes this is simpler when only a few indices are needed.
+ */
+ template<typename T> T get(const int64_t index) const;
void get_to_uninitialized(const int64_t index, void *r_value) const;
};
@@ -226,6 +249,9 @@ class GVMutableArray : public GVArrayCommon {
void set_by_relocate(const int64_t index, void *value);
void fill(const void *value);
+ /**
+ * Copy the values from the source buffer to all elements in the virtual array.
+ */
void set_all(const void *src);
GVMutableArrayImpl *get_implementation() const;
@@ -555,37 +581,19 @@ template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutabl
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArrayImpl_For_GSpan and #GVMutableArrayImpl_For_GMutableSpan.
+/** \name #GVArrayImpl_For_GSpan.
* \{ */
-class GVArrayImpl_For_GSpan : public GVArrayImpl {
- protected:
- const void *data_ = nullptr;
- const int64_t element_size_;
-
- public:
- GVArrayImpl_For_GSpan(const GSpan span);
-
- protected:
- GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size);
-
- void get(const int64_t index, void *r_value) const override;
- void get_to_uninitialized(const int64_t index, void *r_value) const override;
-
- bool is_span() const override;
- GSpan get_internal_span() const override;
-};
-
-class GVMutableArrayImpl_For_GMutableSpan : public GVMutableArrayImpl {
+class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
protected:
void *data_ = nullptr;
const int64_t element_size_;
public:
- GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span);
+ GVArrayImpl_For_GSpan(const GMutableSpan span);
protected:
- GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, const int64_t size);
+ GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size);
public:
void get(const int64_t index, void *r_value) const override;
@@ -688,6 +696,16 @@ inline void GVArrayCommon::get(const int64_t index, void *r_value) const
impl_->get(index, r_value);
}
+template<typename T> inline T GVArrayCommon::get(const int64_t index) const
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size());
+ BLI_assert(this->type().is<T>());
+ T value{};
+ impl_->get(index, &value);
+ return value;
+}
+
/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */
inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const
{
diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh
index c57f6cf574e..1e36d87668a 100644
--- a/source/blender/functions/FN_multi_function.hh
+++ b/source/blender/functions/FN_multi_function.hh
@@ -60,6 +60,13 @@ class MultiFunction {
{
}
+ /**
+ * The result is the same as using #call directly but this method has some additional features.
+ * - Automatic multi-threading when possible and appropriate.
+ * - Automatic index mask offsetting to avoid large temporary intermediate arrays that are mostly
+ * unused.
+ */
+ void call_auto(IndexMask mask, MFParams params, MFContext context) const;
virtual void call(IndexMask mask, MFParams params, MFContext context) const = 0;
virtual uint64_t hash() const
@@ -97,6 +104,8 @@ class MultiFunction {
return signature_ref_->function_name;
}
+ virtual std::string debug_name() const;
+
bool depends_on_context() const
{
return signature_ref_->depends_on_context;
@@ -108,6 +117,31 @@ class MultiFunction {
return *signature_ref_;
}
+ /**
+ * Information about how the multi-function behaves that help a caller to execute it efficiently.
+ */
+ struct ExecutionHints {
+ /**
+ * Suggested minimum workload under which multi-threading does not really help.
+ * This should be lowered when the multi-function is doing something computationally expensive.
+ */
+ int64_t min_grain_size = 10000;
+ /**
+ * Indicates that the multi-function will allocate an array large enough to hold all indices
+ * passed in as mask. This tells the caller that it would be preferable to pass in smaller
+ * indices. Also maybe the full mask should be split up into smaller segments to decrease peak
+ * memory usage.
+ */
+ bool allocates_array = false;
+ /**
+ * Tells the caller that every execution takes about the same time. This helps making a more
+ * educated guess about a good grain size.
+ */
+ bool uniform_execution_time = true;
+ };
+
+ ExecutionHints execution_hints() const;
+
protected:
/* Make the function use the given signature. This should be called once in the constructor of
* child classes. No copy of the signature is made, so the caller has to make sure that the
@@ -119,6 +153,8 @@ class MultiFunction {
BLI_assert(signature != nullptr);
signature_ref_ = signature;
}
+
+ virtual ExecutionHints get_execution_hints() const;
};
inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, int64_t mask_size)
diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh
index 0ce05cbca30..eaf9e5ce70f 100644
--- a/source/blender/functions/FN_multi_function_builder.hh
+++ b/source/blender/functions/FN_multi_function_builder.hh
@@ -43,7 +43,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
MFSignature signature_;
public:
- CustomMF_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -53,7 +53,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio
}
template<typename ElementFuncT>
- CustomMF_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SO(name, CustomMF_SI_SO::create_function(element_fn))
{
}
@@ -92,7 +92,7 @@ class CustomMF_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -103,7 +103,7 @@ class CustomMF_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SO(name, CustomMF_SI_SI_SO::create_function(element_fn))
{
}
@@ -150,7 +150,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -162,7 +162,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SO::create_function(element_fn))
{
}
@@ -211,7 +211,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SI_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_input<In1>("In1");
@@ -224,7 +224,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn)
+ CustomMF_SI_SI_SI_SI_SO(const char *name, ElementFuncT element_fn)
: CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn))
{
}
@@ -265,7 +265,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_SM(StringRef name, FunctionT function) : function_(std::move(function))
+ CustomMF_SM(const char *name, FunctionT function) : function_(std::move(function))
{
MFSignatureBuilder signature{name};
signature.single_mutable<Mut1>("Mut1");
@@ -274,7 +274,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction {
}
template<typename ElementFuncT>
- CustomMF_SM(StringRef name, ElementFuncT element_fn)
+ CustomMF_SM(const char *name, ElementFuncT element_fn)
: CustomMF_SM(name, CustomMF_SM::create_function(element_fn))
{
}
@@ -306,8 +306,8 @@ template<typename From, typename To> class CustomMF_Convert : public MultiFuncti
static MFSignature create_signature()
{
- std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
- MFSignatureBuilder signature{std::move(name)};
+ static std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name();
+ MFSignatureBuilder signature{name.c_str()};
signature.single_input<From>("Input");
signature.single_output<To>("Output");
return signature.build();
@@ -372,9 +372,7 @@ template<typename T> class CustomMF_Constant : public MultiFunction {
template<typename U> CustomMF_Constant(U &&value) : value_(std::forward<U>(value))
{
MFSignatureBuilder signature{"Constant"};
- std::stringstream ss;
- ss << value_;
- signature.single_output<T>(ss.str());
+ signature.single_output<T>("Value");
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -414,9 +412,7 @@ class CustomMF_DefaultOutput : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_DefaultOutput(StringRef name,
- Span<MFDataType> input_types,
- Span<MFDataType> output_types);
+ CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types);
void call(IndexMask mask, MFParams params, MFContext context) const override;
};
@@ -425,7 +421,7 @@ class CustomMF_GenericCopy : public MultiFunction {
MFSignature signature_;
public:
- CustomMF_GenericCopy(StringRef name, MFDataType data_type);
+ CustomMF_GenericCopy(MFDataType data_type);
void call(IndexMask mask, MFParams params, MFContext context) const override;
};
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 5c7e75230f3..f4ddc4f2881 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -25,6 +25,8 @@
* the function. `MFParams` is then used inside the called function to access the parameters.
*/
+#include <mutex>
+
#include "BLI_resource_scope.hh"
#include "FN_generic_pointer.hh"
@@ -45,6 +47,9 @@ class MFParamsBuilder {
Vector<const GVVectorArray *> virtual_vector_arrays_;
Vector<GVectorArray *> vector_arrays_;
+ std::mutex mutex_;
+ Vector<std::pair<int, GMutableSpan>> dummy_output_spans_;
+
friend class MFParams;
MFParamsBuilder(const MFSignature &signature, const IndexMask mask)
@@ -62,8 +67,8 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input_value(T value, StringRef expected_name = "")
{
- T *value_ptr = &scope_.add_value<T>(std::move(value));
- this->add_readonly_single_input(value_ptr, expected_name);
+ this->add_readonly_single_input(VArray<T>::ForSingle(std::move(value), min_array_size_),
+ expected_name);
}
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
@@ -254,20 +259,12 @@ class MFParams {
this->assert_correct_param(param_index, name, MFParamType::SingleOutput);
int data_index = builder_->signature_->data_index(param_index);
GMutableSpan span = builder_->mutable_spans_[data_index];
- if (span.is_empty()) {
- /* The output is ignored by the caller, but the multi-function does not handle this case. So
- * create a temporary buffer that the multi-function can write to. */
- const CPPType &type = span.type();
- void *buffer = builder_->scope_.linear_allocator().allocate(
- builder_->min_array_size_ * type.size(), type.alignment());
- if (!type.is_trivially_destructible()) {
- /* Make sure the temporary elements will be destructed in the end. */
- builder_->scope_.add_destruct_call(
- [&type, buffer, mask = builder_->mask_]() { type.destruct_indices(buffer, mask); });
- }
- span = GMutableSpan{type, buffer, builder_->min_array_size_};
+ if (!span.is_empty()) {
+ return span;
}
- return span;
+ /* The output is ignored by the caller, but the multi-function does not handle this case. So
+ * create a temporary buffer that the multi-function can write to. */
+ return this->ensure_dummy_single_output(data_index);
}
/**
@@ -356,6 +353,8 @@ class MFParams {
}
#endif
}
+
+ GMutableSpan ensure_dummy_single_output(int data_index);
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_procedure_executor.hh b/source/blender/functions/FN_multi_function_procedure_executor.hh
index 9c8b59739b8..409a031e7ed 100644
--- a/source/blender/functions/FN_multi_function_procedure_executor.hh
+++ b/source/blender/functions/FN_multi_function_procedure_executor.hh
@@ -31,9 +31,12 @@ class MFProcedureExecutor : public MultiFunction {
const MFProcedure &procedure_;
public:
- MFProcedureExecutor(std::string name, const MFProcedure &procedure);
+ MFProcedureExecutor(const MFProcedure &procedure);
void call(IndexMask mask, MFParams params, MFContext context) const override;
+
+ private:
+ ExecutionHints get_execution_hints() const override;
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_procedure_optimization.hh b/source/blender/functions/FN_multi_function_procedure_optimization.hh
new file mode 100644
index 00000000000..e5ffc12b241
--- /dev/null
+++ b/source/blender/functions/FN_multi_function_procedure_optimization.hh
@@ -0,0 +1,61 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup fn
+ *
+ * A #MFProcedure optimization pass takes an existing procedure and changes it in a way that
+ * improves its performance when executed.
+ *
+ * Oftentimes it would also be possible to implement a specific optimization directly during
+ * construction of the initial #MFProcedure. There is a trade-off between doing that or just
+ * building a "simple" procedure and then optimizing it uses separate optimization passes.
+ * - Doing optimizations directly during construction is typically faster than doing it as a
+ * separate pass. However, it would be much harder to turn the optimization off when it is not
+ * necessary, making the construction potentially slower in those cases.
+ * - Doing optimizations directly would also make code more complex, because it mixes the logic
+ * that generates the procedure from some other data with optimization decisions.
+ * - Having a separate pass allows us to use it in different places when necessary.
+ * - Having a separate pass allows us to enable and disable it easily to better understand its
+ * impact on performance.
+ */
+
+#include "FN_multi_function_procedure.hh"
+
+namespace blender::fn::procedure_optimization {
+
+/**
+ * When generating a procedure, destruct instructions (#MFDestructInstruction) have to be inserted
+ * for all variables that are not outputs. Often the simplest approach is to add these instructions
+ * at the very end. However, when the procedure is executed this is not optimal, because many more
+ * variables are initialized at the same time than necessary. This inhibits the reuse of memory
+ * buffers which decreases performance and increases memory use.
+ *
+ * This optimization pass moves destruct instructions up in the procedure. The goal is to destruct
+ * each variable right after its last use.
+ *
+ * For simplicity, and because this is the most common use case, this optimization currently only
+ * works on a single chain of instructions. Destruct instructions are not moved across branches.
+ *
+ * \param procedure The procedure that should be optimized.
+ * \param block_end_instr The instruction that points to the last instruction within a linear chain
+ * of instructions. The algorithm moves instructions backward starting at this instruction.
+ */
+void move_destructs_up(MFProcedure &procedure, MFInstruction &block_end_instr);
+
+} // namespace blender::fn::procedure_optimization
diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh
index d05948cc645..3c991bc9c56 100644
--- a/source/blender/functions/FN_multi_function_signature.hh
+++ b/source/blender/functions/FN_multi_function_signature.hh
@@ -30,8 +30,15 @@
namespace blender::fn {
struct MFSignature {
- std::string function_name;
- Vector<std::string> param_names;
+ /**
+ * The name should be statically allocated so that it lives longer than this signature. This is
+ * used instead of an #std::string because of the overhead when many functions are created.
+ * If the name of the function has to be more dynamic for debugging purposes, override
+ * #MultiFunction::debug_name() instead. Then the dynamic name will only be computed when it is
+ * actually needed.
+ */
+ const char *function_name;
+ Vector<const char *> param_names;
Vector<MFParamType> param_types;
Vector<int> param_data_indices;
bool depends_on_context = false;
@@ -51,9 +58,9 @@ class MFSignatureBuilder {
int vector_array_count_ = 0;
public:
- MFSignatureBuilder(std::string function_name)
+ MFSignatureBuilder(const char *function_name)
{
- signature_.function_name = std::move(function_name);
+ signature_.function_name = function_name;
}
MFSignature build() const
@@ -63,23 +70,23 @@ class MFSignatureBuilder {
/* Input Parameter Types */
- template<typename T> void single_input(StringRef name)
+ template<typename T> void single_input(const char *name)
{
this->single_input(name, CPPType::get<T>());
}
- void single_input(StringRef name, const CPPType &type)
+ void single_input(const char *name, const CPPType &type)
{
this->input(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_input(StringRef name)
+ template<typename T> void vector_input(const char *name)
{
this->vector_input(name, CPPType::get<T>());
}
- void vector_input(StringRef name, const CPPType &base_type)
+ void vector_input(const char *name, const CPPType &base_type)
{
this->input(name, MFDataType::ForVector(base_type));
}
- void input(StringRef name, MFDataType data_type)
+ void input(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Input, data_type));
@@ -96,23 +103,23 @@ class MFSignatureBuilder {
/* Output Parameter Types */
- template<typename T> void single_output(StringRef name)
+ template<typename T> void single_output(const char *name)
{
this->single_output(name, CPPType::get<T>());
}
- void single_output(StringRef name, const CPPType &type)
+ void single_output(const char *name, const CPPType &type)
{
this->output(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_output(StringRef name)
+ template<typename T> void vector_output(const char *name)
{
this->vector_output(name, CPPType::get<T>());
}
- void vector_output(StringRef name, const CPPType &base_type)
+ void vector_output(const char *name, const CPPType &base_type)
{
this->output(name, MFDataType::ForVector(base_type));
}
- void output(StringRef name, MFDataType data_type)
+ void output(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Output, data_type));
@@ -129,23 +136,23 @@ class MFSignatureBuilder {
/* Mutable Parameter Types */
- template<typename T> void single_mutable(StringRef name)
+ template<typename T> void single_mutable(const char *name)
{
this->single_mutable(name, CPPType::get<T>());
}
- void single_mutable(StringRef name, const CPPType &type)
+ void single_mutable(const char *name, const CPPType &type)
{
this->mutable_(name, MFDataType::ForSingle(type));
}
- template<typename T> void vector_mutable(StringRef name)
+ template<typename T> void vector_mutable(const char *name)
{
this->vector_mutable(name, CPPType::get<T>());
}
- void vector_mutable(StringRef name, const CPPType &base_type)
+ void vector_mutable(const char *name, const CPPType &base_type)
{
this->mutable_(name, MFDataType::ForVector(base_type));
}
- void mutable_(StringRef name, MFDataType data_type)
+ void mutable_(const char *name, MFDataType data_type)
{
signature_.param_names.append(name);
signature_.param_types.append(MFParamType(MFParamType::Mutable, data_type));
@@ -160,7 +167,7 @@ class MFSignatureBuilder {
}
}
- void add(StringRef name, const MFParamType &param_type)
+ void add(const char *name, const MFParamType &param_type)
{
switch (param_type.interface_type()) {
case MFParamType::Input:
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 68a8446e6ae..604e5c6d13f 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -21,7 +21,10 @@
#include "BLI_vector_set.hh"
#include "FN_field.hh"
-#include "FN_multi_function_parallel.hh"
+#include "FN_multi_function_procedure.hh"
+#include "FN_multi_function_procedure_builder.hh"
+#include "FN_multi_function_procedure_executor.hh"
+#include "FN_multi_function_procedure_optimization.hh"
namespace blender::fn {
@@ -237,8 +240,7 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
if (!already_output_variables.add(variable)) {
/* One variable can be output at most once. To output the same value twice, we have to make
* a copy first. */
- const MultiFunction &copy_fn = scope.construct<CustomMF_GenericCopy>("copy",
- variable->data_type());
+ const MultiFunction &copy_fn = scope.construct<CustomMF_GenericCopy>(variable->data_type());
variable = builder.add_call<1>(copy_fn, {variable})[0];
}
builder.add_output_parameter(*variable);
@@ -253,30 +255,14 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
builder.add_destruct(*variable);
}
- builder.add_return();
+ MFReturnInstruction &return_instr = builder.add_return();
+
+ procedure_optimization::move_destructs_up(procedure, return_instr);
// std::cout << procedure.to_dot() << "\n";
BLI_assert(procedure.validate());
}
-/**
- * Evaluate fields in the given context. If possible, multiple fields should be evaluated together,
- * because that can be more efficient when they share common sub-fields.
- *
- * \param scope: The resource scope that owns data that makes up the output virtual arrays. Make
- * sure the scope is not destructed when the output virtual arrays are still used.
- * \param fields_to_evaluate: The fields that should be evaluated together.
- * \param mask: Determines which indices are computed. The mask may be referenced by the returned
- * virtual arrays. So the underlying indices (if applicable) should live longer then #scope.
- * \param context: The context that the field is evaluated in. Used to retrieve data from each
- * #FieldInput in the field network.
- * \param dst_varrays: If provided, the computed data will be written into those virtual arrays
- * instead of into newly created ones. That allows making the computed data live longer than
- * #scope and is more efficient when the data will be written into those virtual arrays
- * later anyway.
- * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the
- * provided virtual arrays are returned.
- */
Vector<GVArray> evaluate_fields(ResourceScope &scope,
Span<GFieldRef> fields_to_evaluate,
IndexMask mask,
@@ -358,14 +344,9 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
MFProcedure procedure;
build_multi_function_procedure_for_fields(
procedure, scope, field_tree_info, varying_fields_to_evaluate);
- MFProcedureExecutor procedure_executor{"Procedure", procedure};
- /* Add multi threading capabilities to the field evaluation. */
- const int grain_size = 10000;
- fn::ParallelMultiFunction parallel_procedure_executor{procedure_executor, grain_size};
- /* Utility variable to make easy to switch the executor. */
- const MultiFunction &executor_fn = parallel_procedure_executor;
-
- MFParamsBuilder mf_params{executor_fn, &mask};
+ MFProcedureExecutor procedure_executor{procedure};
+
+ MFParamsBuilder mf_params{procedure_executor, &mask};
MFContextBuilder mf_context;
/* Provide inputs to the procedure executor. */
@@ -406,7 +387,7 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
mf_params.add_uninitialized_single_output(span);
}
- executor_fn.call(mask, mf_params, mf_context);
+ procedure_executor.call_auto(mask, mf_params, mf_context);
}
/* Evaluate constant fields if necessary. */
@@ -415,7 +396,7 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
MFProcedure procedure;
build_multi_function_procedure_for_fields(
procedure, scope, field_tree_info, constant_fields_to_evaluate);
- MFProcedureExecutor procedure_executor{"Procedure", procedure};
+ MFProcedureExecutor procedure_executor{procedure};
MFParamsBuilder mf_params{procedure_executor, 1};
MFContextBuilder mf_context;
@@ -495,15 +476,6 @@ void evaluate_constant_field(const GField &field, void *r_value)
varrays[0].get_to_uninitialized(0, r_value);
}
-/**
- * If the field depends on some input, the same field is returned.
- * Otherwise the field is evaluated and a new field is created that just computes this constant.
- *
- * Making the field constant has two benefits:
- * - The field-tree becomes a single node, which is more efficient when the field is evaluated many
- * times.
- * - Memory of the input fields may be freed.
- */
GField make_field_constant_if_possible(GField field)
{
if (field.node().depends_on_input()) {
@@ -512,10 +484,16 @@ GField make_field_constant_if_possible(GField field)
const CPPType &type = field.cpp_type();
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
evaluate_constant_field(field, buffer);
- auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, buffer, true);
+ GField new_field = make_constant_field(type, buffer);
type.destruct(buffer);
+ return new_field;
+}
+
+GField make_constant_field(const CPPType &type, const void *value)
+{
+ auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, value, true);
auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
- return GField{operation, 0};
+ return GField{std::move(operation), 0};
}
GVArray FieldContext::get_varray_for_input(const FieldInput &field_input,
@@ -532,7 +510,7 @@ IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index")
category_ = Category::Generated;
}
-GVArray IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &UNUSED(scope))
+GVArray IndexFieldInput::get_index_varray(IndexMask mask)
{
auto index_func = [](int i) { return i; };
return VArray<int>::ForFunc(mask.min_array_size(), index_func);
@@ -540,10 +518,10 @@ GVArray IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &UNUSED(
GVArray IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context),
IndexMask mask,
- ResourceScope &scope) const
+ ResourceScope &UNUSED(scope)) const
{
/* TODO: Investigate a similar method to IndexRange::as_span() */
- return get_index_varray(mask, scope);
+ return get_index_varray(mask);
}
uint64_t IndexFieldInput::hash() const
@@ -568,28 +546,65 @@ FieldOperation::FieldOperation(std::shared_ptr<const MultiFunction> function,
owned_function_ = std::move(function);
}
-static bool any_field_depends_on_input(Span<GField> fields)
+/**
+ * Returns the field inputs used by all the provided fields.
+ * This tries to reuse an existing #FieldInputs whenever possible to avoid copying it.
+ */
+static std::shared_ptr<const FieldInputs> combine_field_inputs(Span<GField> fields)
{
+ /* The #FieldInputs that we try to reuse if possible. */
+ const std::shared_ptr<const FieldInputs> *field_inputs_candidate = nullptr;
for (const GField &field : fields) {
- if (field.node().depends_on_input()) {
- return true;
+ const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
+ /* Only try to reuse non-empty #FieldInputs. */
+ if (field_inputs && !field_inputs->nodes.is_empty()) {
+ if (field_inputs_candidate == nullptr) {
+ field_inputs_candidate = &field_inputs;
+ }
+ else if ((*field_inputs_candidate)->nodes.size() < field_inputs->nodes.size()) {
+ /* Always try to reuse the #FieldInputs that has the most nodes already. */
+ field_inputs_candidate = &field_inputs;
+ }
+ }
+ }
+ if (field_inputs_candidate == nullptr) {
+ /* None of the field depends on an input. */
+ return {};
+ }
+ /* Check if all inputs are in the candidate. */
+ Vector<const FieldInput *> inputs_not_in_candidate;
+ for (const GField &field : fields) {
+ const std::shared_ptr<const FieldInputs> &field_inputs = field.node().field_inputs();
+ if (!field_inputs) {
+ continue;
+ }
+ if (&field_inputs == field_inputs_candidate) {
+ continue;
}
+ for (const FieldInput *field_input : field_inputs->nodes) {
+ if (!(*field_inputs_candidate)->nodes.contains(field_input)) {
+ inputs_not_in_candidate.append(field_input);
+ }
+ }
+ }
+ if (inputs_not_in_candidate.is_empty()) {
+ /* The existing #FieldInputs can be reused, because no other field has additional inputs. */
+ return *field_inputs_candidate;
}
- return false;
+ /* Create new #FieldInputs that contains all of the inputs that the fields depend on. */
+ std::shared_ptr<FieldInputs> new_field_inputs = std::make_shared<FieldInputs>(
+ **field_inputs_candidate);
+ for (const FieldInput *field_input : inputs_not_in_candidate) {
+ new_field_inputs->nodes.add(field_input);
+ new_field_inputs->deduplicated_nodes.add(*field_input);
+ }
+ return new_field_inputs;
}
FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inputs)
- : FieldNode(false, any_field_depends_on_input(inputs)),
- function_(&function),
- inputs_(std::move(inputs))
+ : FieldNode(false), function_(&function), inputs_(std::move(inputs))
{
-}
-
-void FieldOperation::foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const
-{
- for (const GField &field : inputs_) {
- field.node().foreach_field_input(foreach_fn);
- }
+ field_inputs_ = combine_field_inputs(inputs_);
}
/* --------------------------------------------------------------------
@@ -597,20 +612,19 @@ void FieldOperation::foreach_field_input(FunctionRef<void(const FieldInput &)> f
*/
FieldInput::FieldInput(const CPPType &type, std::string debug_name)
- : FieldNode(true, true), type_(&type), debug_name_(std::move(debug_name))
-{
-}
-
-void FieldInput::foreach_field_input(FunctionRef<void(const FieldInput &)> foreach_fn) const
+ : FieldNode(true), type_(&type), debug_name_(std::move(debug_name))
{
- foreach_fn(*this);
+ std::shared_ptr<FieldInputs> field_inputs = std::make_shared<FieldInputs>();
+ field_inputs->nodes.add_new(this);
+ field_inputs->deduplicated_nodes.add_new(*this);
+ field_inputs_ = std::move(field_inputs);
}
/* --------------------------------------------------------------------
* FieldEvaluator.
*/
-static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
+static Vector<int64_t> indices_from_selection(IndexMask mask, const VArray<bool> &selection)
{
/* If the selection is just a single value, it's best to avoid calling this
* function when constructing an IndexMask and use an IndexRange instead. */
@@ -619,14 +633,14 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
Vector<int64_t> indices;
if (selection.is_span()) {
Span<bool> span = selection.get_internal_span();
- for (const int64_t i : span.index_range()) {
+ for (const int64_t i : mask) {
if (span[i]) {
indices.append(i);
}
}
}
else {
- for (const int i : selection.index_range()) {
+ for (const int i : mask) {
if (selection[i]) {
indices.append(i);
}
@@ -667,14 +681,36 @@ int FieldEvaluator::add(GField field)
return field_index;
}
+static IndexMask evaluate_selection(const Field<bool> &selection_field,
+ const FieldContext &context,
+ IndexMask full_mask,
+ ResourceScope &scope)
+{
+ if (selection_field) {
+ VArray<bool> selection =
+ evaluate_fields(scope, {selection_field}, full_mask, context)[0].typed<bool>();
+ if (selection.is_single()) {
+ if (selection.get_internal_single()) {
+ return full_mask;
+ }
+ return IndexRange(0);
+ }
+ return scope.add_value(indices_from_selection(full_mask, selection)).as_span();
+ }
+ return full_mask;
+}
+
void FieldEvaluator::evaluate()
{
BLI_assert_msg(!is_evaluated_, "Cannot evaluate fields twice.");
+
+ selection_mask_ = evaluate_selection(selection_field_, context_, mask_, scope_);
+
Array<GFieldRef> fields(fields_to_evaluate_.size());
for (const int i : fields_to_evaluate_.index_range()) {
fields[i] = fields_to_evaluate_[i];
}
- evaluated_varrays_ = evaluate_fields(scope_, fields, mask_, context_, dst_varrays_);
+ evaluated_varrays_ = evaluate_fields(scope_, fields, selection_mask_, context_, dst_varrays_);
BLI_assert(fields_to_evaluate_.size() == evaluated_varrays_.size());
for (const int i : fields_to_evaluate_.index_range()) {
OutputPointerInfo &info = output_pointer_infos_[i];
@@ -696,7 +732,13 @@ IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index)
return IndexRange(0);
}
- return scope_.add_value(indices_from_selection(varray)).as_span();
+ return scope_.add_value(indices_from_selection(mask_, varray)).as_span();
+}
+
+IndexMask FieldEvaluator::get_evaluated_selection_as_mask()
+{
+ BLI_assert(is_evaluated_);
+ return selection_mask_;
}
} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc
index 1fe1c2fc229..b4180a885e7 100644
--- a/source/blender/functions/intern/generic_virtual_array.cc
+++ b/source/blender/functions/intern/generic_virtual_array.cc
@@ -139,107 +139,56 @@ bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const
/** \name #GVArrayImpl_For_GSpan
* \{ */
-GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GSpan span)
- : GVArrayImpl(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
-{
-}
-
-GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size)
- : GVArrayImpl(type, size), element_size_(type.size())
-{
-}
-
-void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
-{
- type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
-}
-
-void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const
-{
- type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
-}
-
-bool GVArrayImpl_For_GSpan::is_span() const
-{
- return true;
-}
-
-GSpan GVArrayImpl_For_GSpan::get_internal_span() const
-{
- return GSpan(*type_, data_, size_);
-}
-
-/** See #VArrayImpl_For_Span_final. */
-class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
- public:
- using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
-
- private:
- bool may_have_ownership() const override
- {
- return false;
- }
-};
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name #GVMutableArrayImpl_For_GMutableSpan
- * \{ */
-
-GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span)
+GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GMutableSpan span)
: GVMutableArrayImpl(span.type(), span.size()),
data_(span.data()),
element_size_(span.type().size())
{
}
-GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const CPPType &type,
- const int64_t size)
+GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size)
: GVMutableArrayImpl(type, size), element_size_(type.size())
{
}
-void GVMutableArrayImpl_For_GMutableSpan::get(const int64_t index, void *r_value) const
+void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
{
type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVMutableArrayImpl_For_GMutableSpan::get_to_uninitialized(const int64_t index,
- void *r_value) const
+void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const
{
type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVMutableArrayImpl_For_GMutableSpan::set_by_copy(const int64_t index, const void *value)
+void GVArrayImpl_For_GSpan::set_by_copy(const int64_t index, const void *value)
{
type_->copy_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-void GVMutableArrayImpl_For_GMutableSpan::set_by_move(const int64_t index, void *value)
+void GVArrayImpl_For_GSpan::set_by_move(const int64_t index, void *value)
{
type_->move_construct(value, POINTER_OFFSET(data_, element_size_ * index));
}
-void GVMutableArrayImpl_For_GMutableSpan::set_by_relocate(const int64_t index, void *value)
+void GVArrayImpl_For_GSpan::set_by_relocate(const int64_t index, void *value)
{
type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-bool GVMutableArrayImpl_For_GMutableSpan::is_span() const
+bool GVArrayImpl_For_GSpan::is_span() const
{
return true;
}
-GSpan GVMutableArrayImpl_For_GMutableSpan::get_internal_span() const
+GSpan GVArrayImpl_For_GSpan::get_internal_span() const
{
return GSpan(*type_, data_, size_);
}
-class GVMutableArrayImpl_For_GMutableSpan_final final
- : public GVMutableArrayImpl_For_GMutableSpan {
+class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
public:
- using GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan;
+ using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
private:
bool may_have_ownership() const override
@@ -337,6 +286,57 @@ class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SmallTrivialSingleValue
+ * \{ */
+
+/**
+ * Contains an inline buffer that can store a single value of a trivial type.
+ * This avoids the allocation that would be done by #GVArrayImpl_For_SingleValue.
+ */
+template<int BufferSize> class GVArrayImpl_For_SmallTrivialSingleValue : public GVArrayImpl {
+ private:
+ AlignedBuffer<BufferSize, 8> buffer_;
+
+ public:
+ GVArrayImpl_For_SmallTrivialSingleValue(const CPPType &type,
+ const int64_t size,
+ const void *value)
+ : GVArrayImpl(type, size)
+ {
+ BLI_assert(type.is_trivial());
+ BLI_assert(type.alignment() <= 8);
+ BLI_assert(type.size() <= BufferSize);
+ type.copy_construct(value, &buffer_);
+ }
+
+ private:
+ void get(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+ void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+
+ bool is_single() const override
+ {
+ return true;
+ }
+ void get_internal_single(void *r_value) const override
+ {
+ this->copy_value_to(r_value);
+ }
+
+ void copy_value_to(void *dst) const
+ {
+ memcpy(dst, &buffer_, type_->size());
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name #GVArray_GSpan
* \{ */
@@ -426,12 +426,14 @@ class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
protected:
GVArray varray_;
int64_t offset_;
+ IndexRange slice_;
public:
GVArrayImpl_For_SlicedGVArray(GVArray varray, const IndexRange slice)
: GVArrayImpl(varray.type(), slice.size()),
varray_(std::move(varray)),
- offset_(slice.start())
+ offset_(slice.start()),
+ slice_(slice)
{
BLI_assert(slice.one_after_last() <= varray_.size());
}
@@ -445,6 +447,24 @@ class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
{
varray_.get_to_uninitialized(index + offset_, r_value);
}
+
+ bool is_span() const override
+ {
+ return varray_.is_span();
+ }
+ GSpan get_internal_span() const override
+ {
+ return varray_.get_internal_span().slice(slice_);
+ }
+
+ bool is_single() const override
+ {
+ return varray_.is_single();
+ }
+ void get_internal_single(void *r_value) const override
+ {
+ varray_.get_internal_single(r_value);
+ }
};
/** \} */
@@ -527,49 +547,28 @@ void GVArrayCommon::move_from(GVArrayCommon &&other) noexcept
other.impl_ = nullptr;
}
-/* Returns true when the virtual array is stored as a span internally. */
bool GVArrayCommon::is_span() const
{
- if (this->is_empty()) {
- return true;
- }
return impl_->is_span();
}
-/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
- * virtual array is not stored as a span internally. */
GSpan GVArrayCommon::get_internal_span() const
{
BLI_assert(this->is_span());
- if (this->is_empty()) {
- return GSpan(impl_->type());
- }
return impl_->get_internal_span();
}
-/* Returns true when the virtual array returns the same value for every index. */
bool GVArrayCommon::is_single() const
{
- if (impl_->size() == 1) {
- return true;
- }
return impl_->is_single();
}
-/* Copies the value that is used for every element into `r_value`, which is expected to point to
- * initialized memory. This invokes undefined behavior if the virtual array would not return the
- * same value for every index. */
void GVArrayCommon::get_internal_single(void *r_value) const
{
BLI_assert(this->is_single());
- if (impl_->size() == 1) {
- impl_->get(0, r_value);
- return;
- }
impl_->get_internal_single(r_value);
}
-/* Same as `get_internal_single`, but `r_value` points to initialized memory. */
void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const
{
impl_->type().default_construct(r_value);
@@ -606,6 +605,9 @@ GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::m
GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
{
+ if (type.is_trivial() && type.size() <= 16 && type.alignment() <= 8) {
+ return GVArray::For<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value);
+ }
return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value);
}
@@ -621,7 +623,10 @@ GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size)
GVArray GVArray::ForSpan(GSpan span)
{
- return GVArray::For<GVArrayImpl_For_GSpan_final>(span);
+ /* Use const-cast because the underlying virtual array implementation is shared between const
+ * and non const data. */
+ GMutableSpan mutable_span{span.type(), const_cast<void *>(span.data()), span.size()};
+ return GVArray::For<GVArrayImpl_For_GSpan_final>(mutable_span);
}
class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan {
@@ -630,7 +635,7 @@ class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan {
public:
GVArrayImpl_For_GArray(GArray<> array)
- : GVArrayImpl_For_GSpan(array.as_span()), array_(std::move(array))
+ : GVArrayImpl_For_GSpan(array.as_mutable_span()), array_(std::move(array))
{
}
};
@@ -682,7 +687,7 @@ GVMutableArray::GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl)
GVMutableArray GVMutableArray::ForSpan(GMutableSpan span)
{
- return GVMutableArray::For<GVMutableArrayImpl_For_GMutableSpan_final>(span);
+ return GVMutableArray::For<GVArrayImpl_For_GSpan_final>(span);
}
GVMutableArray::operator GVArray() const &
@@ -716,7 +721,6 @@ GVMutableArrayImpl *GVMutableArray::get_implementation() const
return this->get_impl();
}
-/* Copy the values from the source buffer to all elements in the virtual array. */
void GVMutableArray::set_all(const void *src)
{
this->get_impl()->set_all(src);
diff --git a/source/blender/functions/intern/multi_function.cc b/source/blender/functions/intern/multi_function.cc
index 43eacdcd2a1..837ccc4f4fb 100644
--- a/source/blender/functions/intern/multi_function.cc
+++ b/source/blender/functions/intern/multi_function.cc
@@ -16,6 +16,138 @@
#include "FN_multi_function.hh"
+#include "BLI_task.hh"
+#include "BLI_threads.h"
+
namespace blender::fn {
+using ExecutionHints = MultiFunction::ExecutionHints;
+
+ExecutionHints MultiFunction::execution_hints() const
+{
+ return this->get_execution_hints();
+}
+
+ExecutionHints MultiFunction::get_execution_hints() const
+{
+ return ExecutionHints{};
+}
+
+static bool supports_threading_by_slicing_params(const MultiFunction &fn)
+{
+ for (const int i : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(i);
+ if (ELEM(param_type.interface_type(),
+ MFParamType::InterfaceType::Mutable,
+ MFParamType::InterfaceType::Output)) {
+ if (param_type.data_type().is_vector()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static int64_t compute_grain_size(const ExecutionHints &hints, const IndexMask mask)
+{
+ int64_t grain_size = hints.min_grain_size;
+ if (hints.uniform_execution_time) {
+ const int thread_count = BLI_system_thread_count();
+ /* Avoid using a small grain size even if it is not necessary. */
+ const int64_t thread_based_grain_size = mask.size() / thread_count / 4;
+ grain_size = std::max(grain_size, thread_based_grain_size);
+ }
+ if (hints.allocates_array) {
+ const int64_t max_grain_size = 10000;
+ /* Avoid allocating many large intermediate arrays. Better process data in smaller chunks to
+ * keep peak memory usage lower. */
+ grain_size = std::min(grain_size, max_grain_size);
+ }
+ return grain_size;
+}
+
+void MultiFunction::call_auto(IndexMask mask, MFParams params, MFContext context) const
+{
+ if (mask.is_empty()) {
+ return;
+ }
+ const ExecutionHints hints = this->execution_hints();
+ const int64_t grain_size = compute_grain_size(hints, mask);
+
+ if (mask.size() <= grain_size) {
+ this->call(mask, params, context);
+ return;
+ }
+
+ const bool supports_threading = supports_threading_by_slicing_params(*this);
+ if (!supports_threading) {
+ this->call(mask, params, context);
+ return;
+ }
+
+ threading::parallel_for(mask.index_range(), grain_size, [&](const IndexRange sub_range) {
+ const IndexMask sliced_mask = mask.slice(sub_range);
+ if (!hints.allocates_array) {
+ /* There is no benefit to changing indices in this case. */
+ this->call(sliced_mask, params, context);
+ return;
+ }
+ if (sliced_mask[0] < grain_size) {
+ /* The indices are low, no need to offset them. */
+ this->call(sliced_mask, params, context);
+ return;
+ }
+ const int64_t input_slice_start = sliced_mask[0];
+ const int64_t input_slice_size = sliced_mask.last() - input_slice_start + 1;
+ const IndexRange input_slice_range{input_slice_start, input_slice_size};
+
+ Vector<int64_t> offset_mask_indices;
+ const IndexMask offset_mask = mask.slice_and_offset(sub_range, offset_mask_indices);
+
+ MFParamsBuilder offset_params{*this, offset_mask.min_array_size()};
+
+ /* Slice all parameters so that for the actual function call. */
+ for (const int param_index : this->param_indices()) {
+ const MFParamType param_type = this->param_type(param_index);
+ switch (param_type.category()) {
+ case MFParamType::SingleInput: {
+ const GVArray &varray = params.readonly_single_input(param_index);
+ offset_params.add_readonly_single_input(varray.slice(input_slice_range));
+ break;
+ }
+ case MFParamType::SingleMutable: {
+ const GMutableSpan span = params.single_mutable(param_index);
+ const GMutableSpan sliced_span = span.slice(input_slice_range);
+ offset_params.add_single_mutable(sliced_span);
+ break;
+ }
+ case MFParamType::SingleOutput: {
+ const GMutableSpan span = params.uninitialized_single_output_if_required(param_index);
+ if (span.is_empty()) {
+ offset_params.add_ignored_single_output();
+ }
+ else {
+ const GMutableSpan sliced_span = span.slice(input_slice_range);
+ offset_params.add_uninitialized_single_output(sliced_span);
+ }
+ break;
+ }
+ case MFParamType::VectorInput:
+ case MFParamType::VectorMutable:
+ case MFParamType::VectorOutput: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+ }
+
+ this->call(offset_mask, offset_params, context);
+ });
+}
+
+std::string MultiFunction::debug_name() const
+{
+ return signature_ref_->function_name;
+}
+
} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc
index f891f162820..24f9bbe0179 100644
--- a/source/blender/functions/intern/multi_function_builder.cc
+++ b/source/blender/functions/intern/multi_function_builder.cc
@@ -32,10 +32,8 @@ CustomMF_GenericConstant::CustomMF_GenericConstant(const CPPType &type,
}
value_ = value;
- MFSignatureBuilder signature{"Constant " + type.name()};
- std::stringstream ss;
- type.print_or_default(value, ss, type.name());
- signature.single_output(ss.str(), type);
+ MFSignatureBuilder signature{"Constant"};
+ signature.single_output("Value", type);
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -73,28 +71,11 @@ bool CustomMF_GenericConstant::equals(const MultiFunction &other) const
return type_.is_equal(value_, _other->value_);
}
-static std::string gspan_to_string(GSpan array)
-{
- const CPPType &type = array.type();
- std::stringstream ss;
- ss << "[";
- const int64_t max_amount = 5;
- for (int64_t i : IndexRange(std::min(max_amount, array.size()))) {
- type.print_or_default(array[i], ss, type.name());
- ss << ", ";
- }
- if (max_amount < array.size()) {
- ss << "...";
- }
- ss << "]";
- return ss.str();
-}
-
CustomMF_GenericConstantArray::CustomMF_GenericConstantArray(GSpan array) : array_(array)
{
const CPPType &type = array.type();
- MFSignatureBuilder signature{"Constant " + type.name() + " Vector"};
- signature.vector_output(gspan_to_string(array), type);
+ MFSignatureBuilder signature{"Constant Vector"};
+ signature.vector_output("Value", type);
signature_ = signature.build();
this->set_signature(&signature_);
}
@@ -109,12 +90,11 @@ void CustomMF_GenericConstantArray::call(IndexMask mask,
}
}
-CustomMF_DefaultOutput::CustomMF_DefaultOutput(StringRef name,
- Span<MFDataType> input_types,
+CustomMF_DefaultOutput::CustomMF_DefaultOutput(Span<MFDataType> input_types,
Span<MFDataType> output_types)
: output_amount_(output_types.size())
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Default Output"};
for (MFDataType data_type : input_types) {
signature.input("Input", data_type);
}
@@ -140,9 +120,9 @@ void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNU
}
}
-CustomMF_GenericCopy::CustomMF_GenericCopy(StringRef name, MFDataType data_type)
+CustomMF_GenericCopy::CustomMF_GenericCopy(MFDataType data_type)
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Copy"};
signature.input("Input", data_type);
signature.output("Output", data_type);
signature_ = signature.build();
diff --git a/source/blender/functions/intern/multi_function_parallel.cc b/source/blender/functions/intern/multi_function_parallel.cc
deleted file mode 100644
index eefe647644d..00000000000
--- a/source/blender/functions/intern/multi_function_parallel.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "FN_multi_function_parallel.hh"
-
-#include "BLI_task.hh"
-
-namespace blender::fn {
-
-ParallelMultiFunction::ParallelMultiFunction(const MultiFunction &fn, const int64_t grain_size)
- : fn_(fn), grain_size_(grain_size)
-{
- this->set_signature(&fn.signature());
-
- threading_supported_ = true;
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- if (param_type.data_type().category() == MFDataType::Vector) {
- /* Vector parameters do not support threading yet. */
- threading_supported_ = false;
- break;
- }
- }
-}
-
-void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext context) const
-{
- if (full_mask.size() <= grain_size_ || !threading_supported_) {
- fn_.call(full_mask, params, context);
- return;
- }
-
- threading::parallel_for(full_mask.index_range(), grain_size_, [&](const IndexRange mask_slice) {
- Vector<int64_t> sub_mask_indices;
- const IndexMask sub_mask = full_mask.slice_and_offset(mask_slice, sub_mask_indices);
- if (sub_mask.is_empty()) {
- return;
- }
- const int64_t input_slice_start = full_mask[mask_slice.first()];
- const int64_t input_slice_size = full_mask[mask_slice.last()] - input_slice_start + 1;
- const IndexRange input_slice_range{input_slice_start, input_slice_size};
-
- MFParamsBuilder sub_params{fn_, sub_mask.min_array_size()};
-
- /* All parameters are sliced so that the wrapped multi-function does not have to take care of
- * the index offset. */
- for (const int param_index : fn_.param_indices()) {
- const MFParamType param_type = fn_.param_type(param_index);
- switch (param_type.category()) {
- case MFParamType::SingleInput: {
- const GVArray &varray = params.readonly_single_input(param_index);
- sub_params.add_readonly_single_input(varray.slice(input_slice_range));
- break;
- }
- case MFParamType::SingleMutable: {
- const GMutableSpan span = params.single_mutable(param_index);
- const GMutableSpan sliced_span = span.slice(input_slice_start, input_slice_size);
- sub_params.add_single_mutable(sliced_span);
- break;
- }
- case MFParamType::SingleOutput: {
- const GMutableSpan span = params.uninitialized_single_output(param_index);
- const GMutableSpan sliced_span = span.slice(input_slice_start, input_slice_size);
- sub_params.add_uninitialized_single_output(sliced_span);
- break;
- }
- case MFParamType::VectorInput:
- case MFParamType::VectorMutable:
- case MFParamType::VectorOutput: {
- BLI_assert_unreachable();
- break;
- }
- }
- }
-
- fn_.call(sub_mask, sub_params, context);
- });
-}
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_params.cc b/source/blender/functions/intern/multi_function_params.cc
new file mode 100644
index 00000000000..376c5b2deb7
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_params.cc
@@ -0,0 +1,44 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "FN_multi_function_params.hh"
+
+namespace blender::fn {
+
+GMutableSpan MFParams::ensure_dummy_single_output(int data_index)
+{
+ /* Lock because we are actually modifying #builder_ and it may be used by multiple threads. */
+ std::lock_guard lock{builder_->mutex_};
+
+ for (const std::pair<int, GMutableSpan> &items : builder_->dummy_output_spans_) {
+ if (items.first == data_index) {
+ return items.second;
+ }
+ }
+
+ const CPPType &type = builder_->mutable_spans_[data_index].type();
+ void *buffer = builder_->scope_.linear_allocator().allocate(
+ builder_->min_array_size_ * type.size(), type.alignment());
+ if (!type.is_trivially_destructible()) {
+ builder_->scope_.add_destruct_call(
+ [&type, buffer, mask = builder_->mask_]() { type.destruct_indices(buffer, mask); });
+ }
+ const GMutableSpan span{type, buffer, builder_->min_array_size_};
+ builder_->dummy_output_spans_.append({data_index, span});
+ return span;
+}
+
+} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index 986c5dff0c4..804beb7d66f 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -782,7 +782,7 @@ class MFProcedureDotExport {
void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss)
{
const MultiFunction &fn = instruction.fn();
- this->instruction_name_format(fn.name() + ": ", ss);
+ this->instruction_name_format(fn.debug_name() + ": ", ss);
for (const int param_index : fn.param_indices()) {
const MFParamType param_type = fn.param_type(param_index);
const MFVariable *variable = instruction.params()[param_index];
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc
index 85d0cf4909f..47643ed22ee 100644
--- a/source/blender/functions/intern/multi_function_procedure_executor.cc
+++ b/source/blender/functions/intern/multi_function_procedure_executor.cc
@@ -20,13 +20,12 @@
namespace blender::fn {
-MFProcedureExecutor::MFProcedureExecutor(std::string name, const MFProcedure &procedure)
- : procedure_(procedure)
+MFProcedureExecutor::MFProcedureExecutor(const MFProcedure &procedure) : procedure_(procedure)
{
- MFSignatureBuilder signature(std::move(name));
+ MFSignatureBuilder signature("Procedure Executor");
for (const ConstMFParameter &param : procedure.params()) {
- signature.add(param.variable->name(), MFParamType(param.type, param.variable->data_type()));
+ signature.add("Parameter", MFParamType(param.type, param.variable->data_type()));
}
signature_ = signature.build();
@@ -140,32 +139,36 @@ class VariableState;
*/
class ValueAllocator : NonCopyable, NonMovable {
private:
- /* Allocate with 64 byte alignment for better reusability of buffers and improved cache
- * performance. */
+ /**
+ * Allocate with 64 byte alignment for better reusability of buffers and improved cache
+ * performance.
+ */
static constexpr inline int min_alignment = 64;
- /* Use stacks so that the most recently used buffers are reused first. This improves cache
- * efficiency. */
- std::array<Stack<VariableValue *>, tot_variable_value_types> values_free_lists_;
- /* The integer key is the size of one element (e.g. 4 for an integer buffer). All buffers are
- * aligned to #min_alignment bytes. */
+ /** All buffers in the free-lists below have been allocated with this allocator. */
+ LinearAllocator<> &linear_allocator_;
+
+ /**
+ * Use stacks so that the most recently used buffers are reused first. This improves cache
+ * efficiency.
+ */
+ std::array<Stack<VariableValue *>, tot_variable_value_types> variable_value_free_lists_;
+
+ /**
+ * The integer key is the size of one element (e.g. 4 for an integer buffer). All buffers are
+ * aligned to #min_alignment bytes.
+ */
Map<int, Stack<void *>> span_buffers_free_list_;
- public:
- ValueAllocator() = default;
+ /** Cache buffers for single values of different types. */
+ Map<const CPPType *, Stack<void *>> single_value_free_lists_;
- ~ValueAllocator()
+ /** The cached memory buffers can hold #VariableState values. */
+ Stack<void *> variable_state_free_list_;
+
+ public:
+ ValueAllocator(LinearAllocator<> &linear_allocator) : linear_allocator_(linear_allocator)
{
- for (Stack<VariableValue *> &stack : values_free_lists_) {
- while (!stack.is_empty()) {
- MEM_freeN(stack.pop());
- }
- }
- for (Stack<void *> &stack : span_buffers_free_list_.values()) {
- while (!stack.is_empty()) {
- MEM_freeN(stack.pop());
- }
- }
}
template<typename... Args> VariableState *obtain_variable_state(Args &&...args);
@@ -191,17 +194,17 @@ class ValueAllocator : NonCopyable, NonMovable {
{
void *buffer = nullptr;
- const int element_size = type.size();
- const int alignment = type.alignment();
+ const int64_t element_size = type.size();
+ const int64_t alignment = type.alignment();
if (alignment > min_alignment) {
/* In this rare case we fallback to not reusing existing buffers. */
- buffer = MEM_mallocN_aligned(element_size * size, alignment, __func__);
+ buffer = linear_allocator_.allocate(element_size * size, alignment);
}
else {
Stack<void *> *stack = span_buffers_free_list_.lookup_ptr(element_size);
if (stack == nullptr || stack->is_empty()) {
- buffer = MEM_mallocN_aligned(element_size * size, min_alignment, __func__);
+ buffer = linear_allocator_.allocate(element_size * size, min_alignment);
}
else {
/* Reuse existing buffer. */
@@ -225,7 +228,14 @@ class ValueAllocator : NonCopyable, NonMovable {
VariableValue_OneSingle *obtain_OneSingle(const CPPType &type)
{
- void *buffer = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ Stack<void *> &stack = single_value_free_lists_.lookup_or_add_default(&type);
+ void *buffer;
+ if (stack.is_empty()) {
+ buffer = linear_allocator_.allocate(type.size(), type.alignment());
+ }
+ else {
+ buffer = stack.pop();
+ }
return this->obtain<VariableValue_OneSingle>(buffer);
}
@@ -263,11 +273,11 @@ class ValueAllocator : NonCopyable, NonMovable {
}
case ValueType::OneSingle: {
auto *value_typed = static_cast<VariableValue_OneSingle *>(value);
+ const CPPType &type = data_type.single_type();
if (value_typed->is_initialized) {
- const CPPType &type = data_type.single_type();
type.destruct(value_typed->data);
}
- MEM_freeN(value_typed->data);
+ single_value_free_lists_.lookup_or_add_default(&type).push(value_typed->data);
break;
}
case ValueType::OneVector: {
@@ -277,7 +287,7 @@ class ValueAllocator : NonCopyable, NonMovable {
}
}
- Stack<VariableValue *> &stack = values_free_lists_[(int)value->type];
+ Stack<VariableValue *> &stack = variable_value_free_lists_[(int)value->type];
stack.push(value);
}
@@ -285,9 +295,9 @@ class ValueAllocator : NonCopyable, NonMovable {
template<typename T, typename... Args> T *obtain(Args &&...args)
{
static_assert(std::is_base_of_v<VariableValue, T>);
- Stack<VariableValue *> &stack = values_free_lists_[(int)T::static_type];
+ Stack<VariableValue *> &stack = variable_value_free_lists_[(int)T::static_type];
if (stack.is_empty()) {
- void *buffer = MEM_mallocN(sizeof(T), __func__);
+ void *buffer = linear_allocator_.allocate(sizeof(T), alignof(T));
return new (buffer) T(std::forward<Args>(args)...);
}
return new (stack.pop()) T(std::forward<Args>(args)...);
@@ -670,7 +680,12 @@ class VariableState : NonCopyable, NonMovable {
tot_initialized_ += mask.size();
}
- void destruct(IndexMask mask,
+ /**
+ * Destruct the masked elements in this variable.
+ * \return True when all elements of this variable are initialized and the variable state can be
+ * released.
+ */
+ bool destruct(IndexMask mask,
IndexMask full_mask,
const MFDataType &data_type,
ValueAllocator &value_allocator)
@@ -680,13 +695,12 @@ class VariableState : NonCopyable, NonMovable {
/* Sanity check to make sure that enough indices can be destructed. */
BLI_assert(new_tot_initialized >= 0);
+ bool do_destruct_self = false;
+
switch (value_->type) {
case ValueType::GVArray: {
if (mask.size() == full_mask.size()) {
- /* All elements are destructed. The elements are owned by the caller, so we don't
- * actually destruct them. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneSingle(data_type.single_type());
+ do_destruct_self = true;
}
else {
/* Not all elements are destructed. Since we can't work on the original array, we have to
@@ -702,18 +716,13 @@ class VariableState : NonCopyable, NonMovable {
const CPPType &type = data_type.single_type();
type.destruct_indices(this->value_as<VariableValue_Span>()->data, mask);
if (new_tot_initialized == 0) {
- /* Release span when all values are initialized. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneSingle(data_type.single_type());
+ do_destruct_self = true;
}
break;
}
case ValueType::GVVectorArray: {
if (mask.size() == full_mask.size()) {
- /* All elements are cleared. The elements are owned by the caller, so don't actually
- * destruct them. */
- value_allocator.release_value(value_, data_type);
- value_ = value_allocator.obtain_OneVector(data_type.vector_base_type());
+ do_destruct_self = true;
}
else {
/* Not all elements are cleared. Since we can't work on the original vector array, we
@@ -732,23 +741,24 @@ class VariableState : NonCopyable, NonMovable {
case ValueType::OneSingle: {
auto *value_typed = this->value_as<VariableValue_OneSingle>();
BLI_assert(value_typed->is_initialized);
+ UNUSED_VARS_NDEBUG(value_typed);
if (mask.size() == tot_initialized_) {
- const CPPType &type = data_type.single_type();
- type.destruct(value_typed->data);
- value_typed->is_initialized = false;
+ do_destruct_self = true;
}
break;
}
case ValueType::OneVector: {
auto *value_typed = this->value_as<VariableValue_OneVector>();
+ UNUSED_VARS(value_typed);
if (mask.size() == tot_initialized_) {
- value_typed->data.clear({0});
+ do_destruct_self = true;
}
break;
}
}
tot_initialized_ = new_tot_initialized;
+ return do_destruct_self;
}
void indices_split(IndexMask mask, IndicesSplitVectors &r_indices)
@@ -802,12 +812,17 @@ class VariableState : NonCopyable, NonMovable {
template<typename... Args> VariableState *ValueAllocator::obtain_variable_state(Args &&...args)
{
- return new VariableState(std::forward<Args>(args)...);
+ if (variable_state_free_list_.is_empty()) {
+ void *buffer = linear_allocator_.allocate(sizeof(VariableState), alignof(VariableState));
+ return new (buffer) VariableState(std::forward<Args>(args)...);
+ }
+ return new (variable_state_free_list_.pop()) VariableState(std::forward<Args>(args)...);
}
void ValueAllocator::release_variable_state(VariableState *state)
{
- delete state;
+ state->~VariableState();
+ variable_state_free_list_.push(state);
}
/** Keeps track of the states of all variables during evaluation. */
@@ -818,7 +833,8 @@ class VariableStates {
IndexMask full_mask_;
public:
- VariableStates(IndexMask full_mask) : full_mask_(full_mask)
+ VariableStates(LinearAllocator<> &linear_allocator, IndexMask full_mask)
+ : value_allocator_(linear_allocator), full_mask_(full_mask)
{
}
@@ -940,7 +956,10 @@ class VariableStates {
void destruct(const MFVariable &variable, const IndexMask &mask)
{
VariableState &variable_state = this->get_variable_state(variable);
- variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_);
+ if (variable_state.destruct(mask, full_mask_, variable.data_type(), value_allocator_)) {
+ variable_state.destruct_self(value_allocator_, variable.data_type());
+ variable_states_.remove_contained(&variable);
+ }
}
VariableState &get_variable_state(const MFVariable &variable)
@@ -1046,7 +1065,7 @@ static void execute_call_instruction(const MFCallInstruction &instruction,
}
try {
- fn.call(mask, params, context);
+ fn.call_auto(mask, params, context);
}
catch (...) {
/* Multi-functions must not throw exceptions. */
@@ -1162,9 +1181,9 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
{
BLI_assert(procedure_.validate());
- LinearAllocator<> allocator;
+ LinearAllocator<> linear_allocator;
- VariableStates variable_states{full_mask};
+ VariableStates variable_states{linear_allocator, full_mask};
variable_states.add_initial_variable_states(*this, procedure_, params);
InstructionScheduler scheduler;
@@ -1237,4 +1256,12 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
}
}
+MultiFunction::ExecutionHints MFProcedureExecutor::get_execution_hints() const
+{
+ ExecutionHints hints;
+ hints.allocates_array = true;
+ hints.min_grain_size = 10000;
+ return hints;
+}
+
} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_procedure_optimization.cc b/source/blender/functions/intern/multi_function_procedure_optimization.cc
new file mode 100644
index 00000000000..f220c85e535
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_procedure_optimization.cc
@@ -0,0 +1,90 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "FN_multi_function_procedure_optimization.hh"
+
+namespace blender::fn::procedure_optimization {
+
+void move_destructs_up(MFProcedure &procedure, MFInstruction &block_end_instr)
+{
+ /* A mapping from a variable to its destruct instruction. */
+ Map<MFVariable *, MFDestructInstruction *> destruct_instructions;
+ MFInstruction *current_instr = &block_end_instr;
+ while (true) {
+ MFInstructionType instr_type = current_instr->type();
+ switch (instr_type) {
+ case MFInstructionType::Destruct: {
+ MFDestructInstruction &destruct_instr = static_cast<MFDestructInstruction &>(
+ *current_instr);
+ MFVariable *variable = destruct_instr.variable();
+ if (variable == nullptr) {
+ continue;
+ }
+ /* Remember this destruct instruction so that it can be moved up later on when the last use
+ * of the variable is found. */
+ destruct_instructions.add(variable, &destruct_instr);
+ break;
+ }
+ case MFInstructionType::Call: {
+ MFCallInstruction &call_instr = static_cast<MFCallInstruction &>(*current_instr);
+ /* For each variable, place the corresponding remembered destruct instruction right after
+ * this call instruction. */
+ for (MFVariable *variable : call_instr.params()) {
+ if (variable == nullptr) {
+ continue;
+ }
+ MFDestructInstruction *destruct_instr = destruct_instructions.pop_default(variable,
+ nullptr);
+ if (destruct_instr == nullptr) {
+ continue;
+ }
+
+ /* Unlink destruct instruction from previous position. */
+ MFInstruction *after_destruct_instr = destruct_instr->next();
+ while (!destruct_instr->prev().is_empty()) {
+ /* Do a copy of the cursor here, because `destruct_instr->prev()` changes when
+ * #set_next is called below. */
+ const MFInstructionCursor cursor = destruct_instr->prev()[0];
+ cursor.set_next(procedure, after_destruct_instr);
+ }
+
+ /* Insert destruct instruction in new position. */
+ MFInstruction *next_instr = call_instr.next();
+ call_instr.set_next(destruct_instr);
+ destruct_instr->set_next(next_instr);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ const Span<MFInstructionCursor> prev_cursors = current_instr->prev();
+ if (prev_cursors.size() != 1) {
+ /* Stop when there is some branching before this instruction. */
+ break;
+ }
+ const MFInstructionCursor &prev_cursor = prev_cursors[0];
+ current_instr = prev_cursor.instruction();
+ if (current_instr == nullptr) {
+ /* Stop when there is no previous instruction. E.g. when this is the first instruction. */
+ break;
+ }
+ }
+}
+
+} // namespace blender::fn::procedure_optimization
diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc
index 16a6c73183d..4614f9eee58 100644
--- a/source/blender/functions/tests/FN_field_test.cc
+++ b/source/blender/functions/tests/FN_field_test.cc
@@ -160,9 +160,9 @@ class TwoOutputFunction : public MultiFunction {
MFSignature signature_;
public:
- TwoOutputFunction(StringRef name)
+ TwoOutputFunction()
{
- MFSignatureBuilder signature{name};
+ MFSignatureBuilder signature{"Two Outputs"};
signature.single_input<int>("In1");
signature.single_input<int>("In2");
signature.single_output<int>("Add");
@@ -190,8 +190,8 @@ TEST(field, FunctionTwoOutputs)
GField index_field_1{std::make_shared<IndexFieldInput>()};
GField index_field_2{std::make_shared<IndexFieldInput>()};
- std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation(
- std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field_1, index_field_2}));
+ std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(
+ FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field_1, index_field_2}));
GField result_field_1{fn, 0};
GField result_field_2{fn, 1};
@@ -221,8 +221,8 @@ TEST(field, TwoFunctionsTwoOutputs)
{
GField index_field{std::make_shared<IndexFieldInput>()};
- std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation(
- std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field, index_field}));
+ std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(
+ FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field, index_field}));
Array<int64_t> mask_indices = {2, 4, 6, 8};
IndexMask mask = mask_indices.as_span();
diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
index a0919d7926e..e3de23550c5 100644
--- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc
@@ -32,7 +32,7 @@ TEST(multi_function_procedure, ConstantOutput)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor executor{"My Procedure", procedure};
+ MFProcedureExecutor executor{procedure};
MFParamsBuilder params{executor, 2};
MFContextBuilder context;
@@ -73,7 +73,7 @@ TEST(multi_function_procedure, SimpleTest)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor executor{"My Procedure", procedure};
+ MFProcedureExecutor executor{procedure};
MFParamsBuilder params{executor, 3};
MFContextBuilder context;
@@ -125,7 +125,7 @@ TEST(multi_function_procedure, BranchTest)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Condition Test", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params(procedure_fn, 5);
Array<int> values_a = {1, 5, 3, 6, 2};
@@ -167,7 +167,7 @@ TEST(multi_function_procedure, EvaluateOne)
builder.add_return();
builder.add_output_parameter(*var2);
- MFProcedureExecutor procedure_fn{"Evaluate One", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> values_out = {1, 2, 3, 4, 5};
@@ -239,7 +239,7 @@ TEST(multi_function_procedure, SimpleLoop)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Simple Loop", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> counts = {4, 3, 7, 6, 4};
@@ -295,7 +295,7 @@ TEST(multi_function_procedure, Vectors)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Vectors", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
MFParamsBuilder params{procedure_fn, 5};
Array<int> v1 = {5, 2, 3};
@@ -359,7 +359,7 @@ TEST(multi_function_procedure, BufferReuse)
EXPECT_TRUE(procedure.validate());
- MFProcedureExecutor procedure_fn{"Buffer Reuse", procedure};
+ MFProcedureExecutor procedure_fn{procedure};
Array<int> inputs = {4, 1, 6, 2, 3};
Array<int> results(5, -1);
diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc
index d99993b35ac..20ca00cf598 100644
--- a/source/blender/functions/tests/FN_multi_function_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_test.cc
@@ -264,7 +264,6 @@ TEST(multi_function, CustomMF_GenericConstant)
{
int value = 42;
CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value, false};
- EXPECT_EQ(fn.param_name(0), "42");
Array<int> outputs(4, 0);
@@ -285,7 +284,6 @@ TEST(multi_function, CustomMF_GenericConstantArray)
{
std::array<int, 4> values = {3, 4, 5, 6};
CustomMF_GenericConstantArray fn{GSpan(Span(values))};
- EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]");
GVectorArray vector_array{CPPType::get<int32_t>(), 4};
GVectorArray_TypedMutableRef<int> vector_array_ref{vector_array};
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index 03f736d4dde..de508ddc540 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -31,7 +31,10 @@ set(INC
set(SRC
intern/mesh_to_curve_convert.cc
+ intern/realize_instances.cc
+
GEO_mesh_to_curve.hh
+ GEO_realize_instances.hh
)
set(LIB
diff --git a/source/blender/geometry/GEO_mesh_to_curve.hh b/source/blender/geometry/GEO_mesh_to_curve.hh
index 66459ab79a9..fac40cc40d5 100644
--- a/source/blender/geometry/GEO_mesh_to_curve.hh
+++ b/source/blender/geometry/GEO_mesh_to_curve.hh
@@ -29,6 +29,11 @@ class MeshComponent;
namespace blender::geometry {
+/**
+ * Convert the mesh into one or many poly splines. Since splines cannot have branches,
+ * intersections of more than three edges will become breaks in splines. Attributes that
+ * are not built-in on meshes and not curves are transferred to the result curve.
+ */
std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
const IndexMask selection);
diff --git a/source/blender/geometry/GEO_realize_instances.hh b/source/blender/geometry/GEO_realize_instances.hh
new file mode 100644
index 00000000000..ac16196667d
--- /dev/null
+++ b/source/blender/geometry/GEO_realize_instances.hh
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BKE_geometry_set.hh"
+
+namespace blender::geometry {
+
+struct RealizeInstancesOptions {
+ /**
+ * The default is to generate new ids for every element (when there was any id attribute in the
+ * input). This avoids having a geometry that contains the same id many times.
+ * When this is `true` the ids on the original geometries are kept unchanged and ids on instances
+ * are ignored. Ids are zero initialized when the original geometry did not have an id.
+ */
+ bool keep_original_ids = false;
+ /**
+ * When `true` the output geometry will contain all the generic attributes that existed on
+ * instances. Otherwise, instance attributes are ignored.
+ */
+ bool realize_instance_attributes = true;
+};
+
+/**
+ * Join all instances into a single geometry component for each geometry type. For example, all
+ * mesh instances (including the already realized mesh) are joined into a single mesh. The output
+ * geometry set does not contain any instances. If the input did not contain any instances, it is
+ * returned directly.
+ *
+ * The `id` attribute has special handling. If there is an id attribute on any component, the
+ * output will contain an `id` attribute as well. The output id is generated by mixing/hashing ids
+ * of instances and of the instanced geometry data.
+ */
+GeometrySet realize_instances(GeometrySet geometry_set, const RealizeInstancesOptions &options);
+
+GeometrySet realize_instances_legacy(GeometrySet geometry_set);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 7aaaec9f0c5..0cbec35ec7a 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -260,11 +260,6 @@ static Vector<std::pair<int, int>> get_selected_edges(const Mesh &mesh, const In
return selected_edges;
}
-/**
- * Convert the mesh into one or many poly splines. Since splines cannot have branches,
- * intersections of more than three edges will become breaks in splines. Attributes that
- * are not built-in on meshes and not curves are transferred to the result curve.
- */
std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component,
const IndexMask selection)
{
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
new file mode 100644
index 00000000000..ae513bf88e9
--- /dev/null
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -0,0 +1,1347 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "GEO_realize_instances.hh"
+
+#include "DNA_collection_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BLI_noise.hh"
+#include "BLI_task.hh"
+
+#include "BKE_collection.h"
+#include "BKE_geometry_set_instances.hh"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+#include "BKE_type_conversions.hh"
+
+namespace blender::geometry {
+
+using blender::bke::AttributeIDRef;
+using blender::bke::custom_data_type_to_cpp_type;
+using blender::bke::CustomDataAttributes;
+using blender::bke::object_get_evaluated_geometry_set;
+using blender::bke::OutputAttribute;
+using blender::bke::OutputAttribute_Typed;
+using blender::bke::ReadAttributeLookup;
+using blender::fn::CPPType;
+using blender::fn::GArray;
+using blender::fn::GMutableSpan;
+using blender::fn::GSpan;
+using blender::fn::GVArray;
+using blender::fn::GVArray_GSpan;
+
+/**
+ * An ordered set of attribute ids. Attributes are ordered to avoid name lookups in many places.
+ * Once the attributes are ordered, they can just be referred to by index.
+ */
+struct OrderedAttributes {
+ VectorSet<AttributeIDRef> ids;
+ Vector<AttributeKind> kinds;
+
+ int size() const
+ {
+ return this->kinds.size();
+ }
+
+ IndexRange index_range() const
+ {
+ return this->kinds.index_range();
+ }
+};
+
+struct AttributeFallbacksArray {
+ /**
+ * Instance attribute values used as fallback when the geometry does not have the
+ * corresponding attributes itself. The pointers point to attributes stored in the instances
+ * component or in #r_temporary_arrays. The order depends on the corresponding #OrderedAttributes
+ * instance.
+ */
+ Array<const void *> array;
+
+ AttributeFallbacksArray(int size) : array(size, nullptr)
+ {
+ }
+};
+
+struct PointCloudRealizeInfo {
+ const PointCloud *pointcloud = nullptr;
+ /** Matches the order stored in #AllPointCloudsInfo.attributes. */
+ Array<std::optional<GVArray_GSpan>> attributes;
+ /** Id attribute on the point cloud. If there are no ids, this #Span is empty. */
+ Span<int> stored_ids;
+};
+
+struct RealizePointCloudTask {
+ /** Starting index in the final realized point cloud. */
+ int start_index;
+ /** Preprocessed information about the point cloud. */
+ const PointCloudRealizeInfo *pointcloud_info;
+ /** Transformation that is applied to all positions. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+/** Start indices in the final output mesh. */
+struct MeshElementStartIndices {
+ int vertex = 0;
+ int edge = 0;
+ int poly = 0;
+ int loop = 0;
+};
+
+struct MeshRealizeInfo {
+ const Mesh *mesh = nullptr;
+ /** Maps old material indices to new material indices. */
+ Array<int> material_index_map;
+ /** Matches the order in #AllMeshesInfo.attributes. */
+ Array<std::optional<GVArray_GSpan>> attributes;
+ /** Vertex ids stored on the mesh. If there are no ids, this #Span is empty. */
+ Span<int> stored_vertex_ids;
+};
+
+struct RealizeMeshTask {
+ MeshElementStartIndices start_indices;
+ const MeshRealizeInfo *mesh_info;
+ /** Transformation that is applied to all positions. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+struct RealizeCurveInfo {
+ const CurveEval *curve = nullptr;
+ /**
+ * Matches the order in #AllCurvesInfo.attributes. For point attributes, the `std::optional`
+ * will be empty.
+ */
+ Array<std::optional<GVArray_GSpan>> spline_attributes;
+};
+
+struct RealizeCurveTask {
+ /* Start index in the final curve. */
+ int start_spline_index = 0;
+ const RealizeCurveInfo *curve_info;
+ /* Transformation applied to the position of control points and handles. */
+ float4x4 transform;
+ AttributeFallbacksArray attribute_fallbacks;
+ /** Only used when the output contains an output attribute. */
+ uint32_t id = 0;
+};
+
+struct AllPointCloudsInfo {
+ /** Ordering of all attributes that are propagated to the output point cloud generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original point clouds that are joined. */
+ VectorSet<const PointCloud *> order;
+ /** Preprocessed data about every original point cloud. This is ordered by #order. */
+ Array<PointCloudRealizeInfo> realize_info;
+ bool create_id_attribute = false;
+};
+
+struct AllMeshesInfo {
+ /** Ordering of all attributes that are propagated to the output mesh generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original meshes that are joined. */
+ VectorSet<const Mesh *> order;
+ /** Preprocessed data about every original mesh. This is ordered by #order. */
+ Array<MeshRealizeInfo> realize_info;
+ /** Ordered materials on the output mesh. */
+ VectorSet<Material *> materials;
+ bool create_id_attribute = false;
+};
+
+struct AllCurvesInfo {
+ /** Ordering of all attributes that are propagated to the output curve generically. */
+ OrderedAttributes attributes;
+ /** Ordering of the original curves that are joined. */
+ VectorSet<const CurveEval *> order;
+ /** Preprocessed data about every original curve. This is ordered by #order. */
+ Array<RealizeCurveInfo> realize_info;
+ bool create_id_attribute = false;
+};
+
+/** Collects all tasks that need to be executed to realize all instances. */
+struct GatherTasks {
+ Vector<RealizePointCloudTask> pointcloud_tasks;
+ Vector<RealizeMeshTask> mesh_tasks;
+ Vector<RealizeCurveTask> curve_tasks;
+
+ /* Volumes only have very simple support currently. Only the first found volume is put into the
+ * output. */
+ UserCounter<VolumeComponent> first_volume;
+};
+
+/** Current offsets while during the gather operation. */
+struct GatherOffsets {
+ int pointcloud_offset = 0;
+ MeshElementStartIndices mesh_offsets;
+ int spline_offset = 0;
+};
+
+struct GatherTasksInfo {
+ /** Static information about all geometries that are joined. */
+ const AllPointCloudsInfo &pointclouds;
+ const AllMeshesInfo &meshes;
+ const AllCurvesInfo &curves;
+ bool create_id_attribute_on_any_component = false;
+
+ /**
+ * Under some circumstances, temporary arrays need to be allocated during the gather operation.
+ * For example, when an instance attribute has to be realized as a different data type. This
+ * array owns all the temporary arrays so that they can live until all processing is done.
+ * Use #std::unique_ptr to avoid depending on whether #GArray has an inline buffer or not.
+ */
+ Vector<std::unique_ptr<GArray<>>> &r_temporary_arrays;
+
+ /** All gathered tasks. */
+ GatherTasks r_tasks;
+ /** Current offsets while gathering tasks. */
+ GatherOffsets r_offsets;
+};
+
+/**
+ * Information about the parent instances in the current context.
+ */
+struct InstanceContext {
+ /** Ordered by #AllPointCloudsInfo.attributes. */
+ AttributeFallbacksArray pointclouds;
+ /** Ordered by #AllMeshesInfo.attributes. */
+ AttributeFallbacksArray meshes;
+ /** Ordered by #AllCurvesInfo.attributes. */
+ AttributeFallbacksArray curves;
+ /** Id mixed from all parent instances. */
+ uint32_t id = 0;
+
+ InstanceContext(const GatherTasksInfo &gather_info)
+ : pointclouds(gather_info.pointclouds.attributes.size()),
+ meshes(gather_info.meshes.attributes.size()),
+ curves(gather_info.curves.attributes.size())
+ {
+ }
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Gather Realize Tasks
+ * \{ */
+
+/* Forward declaration. */
+static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
+ const GeometrySet &geometry_set,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context);
+
+/**
+ * Checks which of the #ordered_attributes exist on the #instances_component. For each attribute
+ * that exists on the instances, a pair is returned that contains the attribute index and the
+ * corresponding attribute data.
+ */
+static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
+ GatherTasksInfo &gather_info,
+ const InstancesComponent &instances_component,
+ const OrderedAttributes &ordered_attributes)
+{
+ Vector<std::pair<int, GSpan>> attributes_to_override;
+ const CustomDataAttributes &attributes = instances_component.attributes();
+ attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id);
+ if (attribute_index == -1) {
+ /* The attribute is not propagated to the final geometry. */
+ return true;
+ }
+ GSpan span = *attributes.get_for_read(attribute_id);
+ const CustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
+ if (meta_data.data_type != expected_type) {
+ const CPPType &from_type = span.type();
+ const CPPType &to_type = *custom_data_type_to_cpp_type(expected_type);
+ const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
+ if (!conversions.is_convertible(from_type, to_type)) {
+ /* Ignore the attribute because it can not be converted to the desired type. */
+ return true;
+ }
+ /* Convert the attribute on the instances component to the expected attribute type. */
+ std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
+ to_type, instances_component.instances_amount());
+ conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
+ span = temporary_array->as_span();
+ gather_info.r_temporary_arrays.append(std::move(temporary_array));
+ }
+ attributes_to_override.append({attribute_index, span});
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+ return attributes_to_override;
+}
+
+/**
+ * Calls #fn for every geometry in the given #InstanceReference. Also passes on the transformation
+ * that is applied to every instance.
+ */
+static void foreach_geometry_in_reference(
+ const InstanceReference &reference,
+ const float4x4 &base_transform,
+ const uint32_t id,
+ FunctionRef<void(const GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)> fn)
+{
+ switch (reference.type()) {
+ case InstanceReference::Type::Object: {
+ const Object &object = reference.object();
+ const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
+ fn(object_geometry_set, base_transform, id);
+ break;
+ }
+ case InstanceReference::Type::Collection: {
+ Collection &collection = reference.collection();
+ float4x4 offset_matrix = float4x4::identity();
+ sub_v3_v3(offset_matrix.values[3], collection.instance_offset);
+ int index = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
+ const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object);
+ const float4x4 matrix = base_transform * offset_matrix * object->obmat;
+ const int sub_id = noise::hash(id, index);
+ fn(object_geometry_set, matrix, sub_id);
+ index++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ break;
+ }
+ case InstanceReference::Type::GeometrySet: {
+ const GeometrySet &instance_geometry_set = reference.geometry_set();
+ fn(instance_geometry_set, base_transform, id);
+ break;
+ }
+ case InstanceReference::Type::None: {
+ break;
+ }
+ }
+}
+
+static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
+ const InstancesComponent &instances_component,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context)
+{
+ const Span<InstanceReference> references = instances_component.references();
+ const Span<int> handles = instances_component.instance_reference_handles();
+ const Span<float4x4> transforms = instances_component.instance_transforms();
+
+ Span<int> stored_instance_ids;
+ if (gather_info.create_id_attribute_on_any_component) {
+ std::optional<GSpan> ids = instances_component.attributes().get_for_read("id");
+ if (ids.has_value()) {
+ stored_instance_ids = ids->typed<int>();
+ }
+ }
+
+ /* Prepare attribute fallbacks. */
+ InstanceContext instance_context = base_instance_context;
+ Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.pointclouds.attributes);
+ Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.meshes.attributes);
+ Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
+ gather_info, instances_component, gather_info.curves.attributes);
+
+ for (const int i : transforms.index_range()) {
+ const int handle = handles[i];
+ const float4x4 &transform = transforms[i];
+ const InstanceReference &reference = references[handle];
+ const float4x4 new_base_transform = base_transform * transform;
+
+ /* Update attribute fallbacks for the current instance. */
+ for (const std::pair<int, GSpan> &pair : pointcloud_attributes_to_override) {
+ instance_context.pointclouds.array[pair.first] = pair.second[i];
+ }
+ for (const std::pair<int, GSpan> &pair : mesh_attributes_to_override) {
+ instance_context.meshes.array[pair.first] = pair.second[i];
+ }
+ for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
+ instance_context.curves.array[pair.first] = pair.second[i];
+ }
+
+ uint32_t local_instance_id = 0;
+ if (gather_info.create_id_attribute_on_any_component) {
+ if (stored_instance_ids.is_empty()) {
+ local_instance_id = (uint32_t)i;
+ }
+ else {
+ local_instance_id = (uint32_t)stored_instance_ids[i];
+ }
+ }
+ const uint32_t instance_id = noise::hash(base_instance_context.id, local_instance_id);
+
+ /* Add realize tasks for all referenced geometry sets recursively. */
+ foreach_geometry_in_reference(reference,
+ new_base_transform,
+ instance_id,
+ [&](const GeometrySet &instance_geometry_set,
+ const float4x4 &transform,
+ const uint32_t id) {
+ instance_context.id = id;
+ gather_realize_tasks_recursive(gather_info,
+ instance_geometry_set,
+ transform,
+ instance_context);
+ });
+ }
+}
+
+/**
+ * Gather tasks for all geometries in the #geometry_set.
+ */
+static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
+ const GeometrySet &geometry_set,
+ const float4x4 &base_transform,
+ const InstanceContext &base_instance_context)
+{
+ for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
+ const GeometryComponentType type = component->type();
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const MeshComponent &mesh_component = *static_cast<const MeshComponent *>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh != nullptr && mesh->totvert > 0) {
+ const int mesh_index = gather_info.meshes.order.index_of(mesh);
+ const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
+ gather_info.r_tasks.mesh_tasks.append({gather_info.r_offsets.mesh_offsets,
+ &mesh_info,
+ base_transform,
+ base_instance_context.meshes,
+ base_instance_context.id});
+ gather_info.r_offsets.mesh_offsets.vertex += mesh->totvert;
+ gather_info.r_offsets.mesh_offsets.edge += mesh->totedge;
+ gather_info.r_offsets.mesh_offsets.loop += mesh->totloop;
+ gather_info.r_offsets.mesh_offsets.poly += mesh->totpoly;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const PointCloudComponent &pointcloud_component =
+ *static_cast<const PointCloudComponent *>(component);
+ const PointCloud *pointcloud = pointcloud_component.get_for_read();
+ if (pointcloud != nullptr && pointcloud->totpoint > 0) {
+ const int pointcloud_index = gather_info.pointclouds.order.index_of(pointcloud);
+ const PointCloudRealizeInfo &pointcloud_info =
+ gather_info.pointclouds.realize_info[pointcloud_index];
+ gather_info.r_tasks.pointcloud_tasks.append({gather_info.r_offsets.pointcloud_offset,
+ &pointcloud_info,
+ base_transform,
+ base_instance_context.pointclouds,
+ base_instance_context.id});
+ gather_info.r_offsets.pointcloud_offset += pointcloud->totpoint;
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ const CurveComponent &curve_component = *static_cast<const CurveComponent *>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve != nullptr && !curve->splines().is_empty()) {
+ const int curve_index = gather_info.curves.order.index_of(curve);
+ const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
+ gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.spline_offset,
+ &curve_info,
+ base_transform,
+ base_instance_context.curves,
+ base_instance_context.id});
+ gather_info.r_offsets.spline_offset += curve->splines().size();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
+ component);
+ gather_realize_tasks_for_instances(
+ gather_info, instances_component, base_transform, base_instance_context);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ const VolumeComponent *volume_component = static_cast<const VolumeComponent *>(component);
+ if (!gather_info.r_tasks.first_volume) {
+ volume_component->user_add();
+ gather_info.r_tasks.first_volume = const_cast<VolumeComponent *>(volume_component);
+ }
+ break;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Point Cloud
+ * \{ */
+
+static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_POINT_CLOUD, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_pointclouds_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const PointCloud *> &r_pointclouds)
+{
+ if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) {
+ if (pointcloud->totpoint > 0) {
+ r_pointclouds.add(pointcloud);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
+ });
+ }
+}
+
+static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllPointCloudsInfo info;
+ info.attributes = gather_generic_pointcloud_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_pointclouds_to_realize(geometry_set, info.order);
+ info.realize_info.reinitialize(info.order.size());
+ for (const int pointcloud_index : info.realize_info.index_range()) {
+ PointCloudRealizeInfo &pointcloud_info = info.realize_info[pointcloud_index];
+ const PointCloud *pointcloud = info.order[pointcloud_index];
+ pointcloud_info.pointcloud = pointcloud;
+
+ /* Access attributes. */
+ PointCloudComponent component;
+ component.replace(const_cast<PointCloud *>(pointcloud), GeometryOwnershipType::ReadOnly);
+ pointcloud_info.attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ if (info.create_id_attribute) {
+ ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
+ if (ids_lookup) {
+ pointcloud_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>();
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options,
+ const RealizePointCloudTask &task,
+ PointCloud &dst_pointcloud,
+ MutableSpan<GMutableSpan> dst_attribute_spans,
+ MutableSpan<int> all_dst_ids)
+{
+ const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
+ const PointCloud &pointcloud = *pointcloud_info.pointcloud;
+ const Span<float3> src_positions{(float3 *)pointcloud.co, pointcloud.totpoint};
+ const IndexRange point_slice{task.start_index, pointcloud.totpoint};
+ MutableSpan<float3> dst_positions{(float3 *)dst_pointcloud.co + task.start_index,
+ pointcloud.totpoint};
+ MutableSpan<int> dst_ids = all_dst_ids.slice(task.start_index, pointcloud.totpoint);
+
+ /* Copy transformed positions. */
+ threading::parallel_for(IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ dst_positions[i] = task.transform * src_positions[i];
+ }
+ });
+ /* Create point ids. */
+ if (!all_dst_ids.is_empty()) {
+ if (options.keep_original_ids) {
+ if (pointcloud_info.stored_ids.is_empty()) {
+ dst_ids.fill(0);
+ }
+ else {
+ dst_ids.copy_from(pointcloud_info.stored_ids);
+ }
+ }
+ else {
+ threading::parallel_for(IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ if (pointcloud_info.stored_ids.is_empty()) {
+ for (const int i : range) {
+ dst_ids[i] = noise::hash(task.id, i);
+ }
+ }
+ else {
+ for (const int i : range) {
+ dst_ids[i] = noise::hash(task.id, pointcloud_info.stored_ids[i]);
+ }
+ }
+ });
+ }
+ }
+ /* Copy generic attributes. */
+ threading::parallel_for(
+ dst_attribute_spans.index_range(), 10, [&](const IndexRange attribute_range) {
+ for (const int attribute_index : attribute_range) {
+ GMutableSpan dst_span = dst_attribute_spans[attribute_index].slice(point_slice);
+ const CPPType &cpp_type = dst_span.type();
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (pointcloud_info.attributes[attribute_index].has_value()) {
+ /* Copy attribute from the original point cloud. */
+ const GSpan src_span = *pointcloud_info.attributes[attribute_index];
+ threading::parallel_for(
+ IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ cpp_type.copy_assign_n(
+ src_span.slice(range).data(), dst_span.slice(range).data(), range.size());
+ });
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ /* As the fallback value for the attribute. */
+ threading::parallel_for(
+ IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
+ cpp_type.fill_assign_n(
+ attribute_fallback, dst_span.slice(range).data(), range.size());
+ });
+ }
+ }
+ });
+}
+
+static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options,
+ const AllPointCloudsInfo &all_pointclouds_info,
+ const Span<RealizePointCloudTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizePointCloudTask &last_task = tasks.last();
+ const PointCloud &last_pointcloud = *last_task.pointcloud_info->pointcloud;
+ const int tot_points = last_task.start_index + last_pointcloud.totpoint;
+
+ /* Allocate new point cloud. */
+ PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(tot_points);
+ PointCloudComponent &dst_component =
+ r_realized_geometry.get_component_for_write<PointCloudComponent>();
+ dst_component.replace(dst_pointcloud);
+
+ /* Prepare id attribute. */
+ OutputAttribute_Typed<int> point_ids;
+ MutableSpan<int> point_ids_span;
+ if (all_pointclouds_info.create_id_attribute) {
+ point_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
+ point_ids_span = point_ids.as_span();
+ }
+
+ /* Prepare generic output attributes. */
+ Vector<OutputAttribute> dst_attributes;
+ Vector<GMutableSpan> dst_attribute_spans;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
+ dst_attribute_spans.append(dst_attribute.as_span());
+ dst_attributes.append(std::move(dst_attribute));
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizePointCloudTask &task = tasks[task_index];
+ execute_realize_pointcloud_task(
+ options, task, *dst_pointcloud, dst_attribute_spans, point_ids_span);
+ }
+ });
+
+ /* Save modified attributes. */
+ for (OutputAttribute &dst_attribute : dst_attributes) {
+ dst_attribute.save();
+ }
+ if (point_ids) {
+ point_ids.save();
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh
+ * \{ */
+
+static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_MESH);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_MESH, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("normal");
+ attributes_to_propagate.remove("material_index");
+ attributes_to_propagate.remove("shade_smooth");
+ attributes_to_propagate.remove("crease");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_meshes_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const Mesh *> &r_meshes)
+{
+ if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
+ if (mesh->totvert > 0) {
+ r_meshes.add(mesh);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_meshes_to_realize(instance_geometry_set, r_meshes);
+ });
+ }
+}
+
+static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllMeshesInfo info;
+ info.attributes = gather_generic_mesh_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_meshes_to_realize(geometry_set, info.order);
+ for (const Mesh *mesh : info.order) {
+ for (const int slot_index : IndexRange(mesh->totcol)) {
+ Material *material = mesh->mat[slot_index];
+ info.materials.add(material);
+ }
+ }
+ info.realize_info.reinitialize(info.order.size());
+ for (const int mesh_index : info.realize_info.index_range()) {
+ MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
+ const Mesh *mesh = info.order[mesh_index];
+ mesh_info.mesh = mesh;
+
+ /* Create material index mapping. */
+ mesh_info.material_index_map.reinitialize(mesh->totcol);
+ for (const int old_slot_index : IndexRange(mesh->totcol)) {
+ Material *material = mesh->mat[old_slot_index];
+ const int new_slot_index = info.materials.index_of(material);
+ mesh_info.material_index_map[old_slot_index] = new_slot_index;
+ }
+
+ /* Access attributes. */
+ MeshComponent component;
+ component.replace(const_cast<Mesh *>(mesh), GeometryOwnershipType::ReadOnly);
+ mesh_info.attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ mesh_info.attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ if (info.create_id_attribute) {
+ ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id");
+ if (ids_lookup) {
+ mesh_info.stored_vertex_ids = ids_lookup.varray.get_internal_span().typed<int>();
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
+ const RealizeMeshTask &task,
+ const OrderedAttributes &ordered_attributes,
+ Mesh &dst_mesh,
+ MutableSpan<GMutableSpan> dst_attribute_spans,
+ MutableSpan<int> all_dst_vertex_ids)
+{
+ const MeshRealizeInfo &mesh_info = *task.mesh_info;
+ const Mesh &mesh = *mesh_info.mesh;
+
+ const Span<MVert> src_verts{mesh.mvert, mesh.totvert};
+ const Span<MEdge> src_edges{mesh.medge, mesh.totedge};
+ const Span<MLoop> src_loops{mesh.mloop, mesh.totloop};
+ const Span<MPoly> src_polys{mesh.mpoly, mesh.totpoly};
+
+ MutableSpan<MVert> dst_verts{dst_mesh.mvert + task.start_indices.vertex, mesh.totvert};
+ MutableSpan<MEdge> dst_edges{dst_mesh.medge + task.start_indices.edge, mesh.totedge};
+ MutableSpan<MLoop> dst_loops{dst_mesh.mloop + task.start_indices.loop, mesh.totloop};
+ MutableSpan<MPoly> dst_polys{dst_mesh.mpoly + task.start_indices.poly, mesh.totpoly};
+
+ MutableSpan<int> dst_vertex_ids = all_dst_vertex_ids.slice(task.start_indices.vertex,
+ mesh.totvert);
+
+ const Span<int> material_index_map = mesh_info.material_index_map;
+
+ threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) {
+ for (const int i : vert_range) {
+ const MVert &src_vert = src_verts[i];
+ MVert &dst_vert = dst_verts[i];
+ dst_vert = src_vert;
+ copy_v3_v3(dst_vert.co, task.transform * float3(src_vert.co));
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totedge), 1024, [&](const IndexRange edge_range) {
+ for (const int i : edge_range) {
+ const MEdge &src_edge = src_edges[i];
+ MEdge &dst_edge = dst_edges[i];
+ dst_edge = src_edge;
+ dst_edge.v1 += task.start_indices.vertex;
+ dst_edge.v2 += task.start_indices.vertex;
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totloop), 1024, [&](const IndexRange loop_range) {
+ for (const int i : loop_range) {
+ const MLoop &src_loop = src_loops[i];
+ MLoop &dst_loop = dst_loops[i];
+ dst_loop = src_loop;
+ dst_loop.v += task.start_indices.vertex;
+ dst_loop.e += task.start_indices.edge;
+ }
+ });
+ threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange poly_range) {
+ for (const int i : poly_range) {
+ const MPoly &src_poly = src_polys[i];
+ MPoly &dst_poly = dst_polys[i];
+ dst_poly = src_poly;
+ dst_poly.loopstart += task.start_indices.loop;
+ if (src_poly.mat_nr >= 0 && src_poly.mat_nr < mesh.totcol) {
+ dst_poly.mat_nr = material_index_map[src_poly.mat_nr];
+ }
+ else {
+ /* The material index was invalid before. */
+ dst_poly.mat_nr = 0;
+ }
+ }
+ });
+ /* Create id attribute. */
+ if (!all_dst_vertex_ids.is_empty()) {
+ if (options.keep_original_ids) {
+ if (mesh_info.stored_vertex_ids.is_empty()) {
+ dst_vertex_ids.fill(0);
+ }
+ else {
+ dst_vertex_ids.copy_from(mesh_info.stored_vertex_ids);
+ }
+ }
+ else {
+ threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) {
+ if (mesh_info.stored_vertex_ids.is_empty()) {
+ for (const int i : vert_range) {
+ dst_vertex_ids[i] = noise::hash(task.id, i);
+ }
+ }
+ else {
+ for (const int i : vert_range) {
+ const int original_id = mesh_info.stored_vertex_ids[i];
+ dst_vertex_ids[i] = noise::hash(task.id, original_id);
+ }
+ }
+ });
+ }
+ }
+ /* Copy generic attributes. */
+ threading::parallel_for(
+ dst_attribute_spans.index_range(), 10, [&](const IndexRange attribute_range) {
+ for (const int attribute_index : attribute_range) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ IndexRange element_slice;
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ element_slice = IndexRange(task.start_indices.vertex, mesh.totvert);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ element_slice = IndexRange(task.start_indices.edge, mesh.totedge);
+ break;
+ case ATTR_DOMAIN_CORNER:
+ element_slice = IndexRange(task.start_indices.loop, mesh.totloop);
+ break;
+ case ATTR_DOMAIN_FACE:
+ element_slice = IndexRange(task.start_indices.poly, mesh.totpoly);
+ break;
+ default:
+ BLI_assert_unreachable();
+ }
+ GMutableSpan dst_span = dst_attribute_spans[attribute_index].slice(element_slice);
+ const CPPType &cpp_type = dst_span.type();
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (mesh_info.attributes[attribute_index].has_value()) {
+ const GSpan src_span = *mesh_info.attributes[attribute_index];
+ threading::parallel_for(
+ IndexRange(element_slice.size()), 1024, [&](const IndexRange sub_range) {
+ cpp_type.copy_assign_n(src_span.slice(sub_range).data(),
+ dst_span.slice(sub_range).data(),
+ sub_range.size());
+ });
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ threading::parallel_for(
+ IndexRange(element_slice.size()), 1024, [&](const IndexRange sub_range) {
+ cpp_type.fill_assign_n(
+ attribute_fallback, dst_span.slice(sub_range).data(), sub_range.size());
+ });
+ }
+ }
+ });
+}
+
+static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
+ const AllMeshesInfo &all_meshes_info,
+ const Span<RealizeMeshTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ const VectorSet<Material *> &ordered_materials,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizeMeshTask &last_task = tasks.last();
+ const Mesh &last_mesh = *last_task.mesh_info->mesh;
+ const int tot_vertices = last_task.start_indices.vertex + last_mesh.totvert;
+ const int tot_edges = last_task.start_indices.edge + last_mesh.totedge;
+ const int tot_loops = last_task.start_indices.loop + last_mesh.totloop;
+ const int tot_poly = last_task.start_indices.poly + last_mesh.totpoly;
+
+ Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, 0, tot_loops, tot_poly);
+ MeshComponent &dst_component = r_realized_geometry.get_component_for_write<MeshComponent>();
+ dst_component.replace(dst_mesh);
+
+ /* Copy settings from the first input geometry set with a mesh. */
+ const RealizeMeshTask &first_task = tasks.first();
+ const Mesh &first_mesh = *first_task.mesh_info->mesh;
+ BKE_mesh_copy_parameters_for_eval(dst_mesh, &first_mesh);
+
+ /* Add materials. */
+ for (const int i : IndexRange(ordered_materials.size())) {
+ Material *material = ordered_materials[i];
+ BKE_id_material_eval_assign(&dst_mesh->id, i + 1, material);
+ }
+
+ /* Prepare id attribute. */
+ OutputAttribute_Typed<int> vertex_ids;
+ MutableSpan<int> vertex_ids_span;
+ if (all_meshes_info.create_id_attribute) {
+ vertex_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT);
+ vertex_ids_span = vertex_ids.as_span();
+ }
+
+ /* Prepare generic output attributes. */
+ Vector<OutputAttribute> dst_attributes;
+ Vector<GMutableSpan> dst_attribute_spans;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, domain, data_type);
+ dst_attribute_spans.append(dst_attribute.as_span());
+ dst_attributes.append(std::move(dst_attribute));
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizeMeshTask &task = tasks[task_index];
+ execute_realize_mesh_task(
+ options, task, ordered_attributes, *dst_mesh, dst_attribute_spans, vertex_ids_span);
+ }
+ });
+
+ /* Save modified attributes. */
+ for (OutputAttribute &dst_attribute : dst_attributes) {
+ dst_attribute.save();
+ }
+ if (vertex_ids) {
+ vertex_ids.save();
+ }
+
+ BKE_mesh_normals_tag_dirty(dst_mesh);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve
+ * \{ */
+
+static OrderedAttributes gather_generic_curve_attributes_to_propagate(
+ const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
+{
+ Vector<GeometryComponentType> src_component_types;
+ src_component_types.append(GEO_COMPONENT_TYPE_CURVE);
+ if (options.realize_instance_attributes) {
+ src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ }
+
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ in_geometry_set.gather_attributes_for_propagation(
+ src_component_types, GEO_COMPONENT_TYPE_CURVE, true, attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("cyclic");
+ attributes_to_propagate.remove("resolution");
+ attributes_to_propagate.remove("tilt");
+ attributes_to_propagate.remove("radius");
+ attributes_to_propagate.remove("handle_right");
+ attributes_to_propagate.remove("handle_left");
+ r_create_id = attributes_to_propagate.pop_try("id").has_value();
+ OrderedAttributes ordered_attributes;
+ for (const auto item : attributes_to_propagate.items()) {
+ ordered_attributes.ids.add_new(item.key);
+ ordered_attributes.kinds.append(item.value);
+ }
+ return ordered_attributes;
+}
+
+static void gather_curves_to_realize(const GeometrySet &geometry_set,
+ VectorSet<const CurveEval *> &r_curves)
+{
+ if (const CurveEval *curve = geometry_set.get_curve_for_read()) {
+ if (!curve->splines().is_empty()) {
+ r_curves.add(curve);
+ }
+ }
+ if (const InstancesComponent *instances =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
+ gather_curves_to_realize(instance_geometry_set, r_curves);
+ });
+ }
+}
+
+static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
+ const RealizeInstancesOptions &options)
+{
+ AllCurvesInfo info;
+ info.attributes = gather_generic_curve_attributes_to_propagate(
+ geometry_set, options, info.create_id_attribute);
+
+ gather_curves_to_realize(geometry_set, info.order);
+ info.realize_info.reinitialize(info.order.size());
+ for (const int curve_index : info.realize_info.index_range()) {
+ RealizeCurveInfo &curve_info = info.realize_info[curve_index];
+ const CurveEval *curve = info.order[curve_index];
+ curve_info.curve = curve;
+
+ /* Access attributes. */
+ CurveComponent component;
+ component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly);
+ curve_info.spline_attributes.reinitialize(info.attributes.size());
+ for (const int attribute_index : info.attributes.index_range()) {
+ const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+ const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
+ const CustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ if (component.attribute_exists(attribute_id)) {
+ GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type);
+ curve_info.spline_attributes[attribute_index].emplace(std::move(attribute));
+ }
+ }
+ }
+ return info;
+}
+
+static void execute_realize_curve_task(const RealizeInstancesOptions &options,
+ const AllCurvesInfo &all_curves_info,
+ const RealizeCurveTask &task,
+ const OrderedAttributes &ordered_attributes,
+ MutableSpan<SplinePtr> dst_splines,
+ MutableSpan<GMutableSpan> dst_spline_attributes)
+{
+ const RealizeCurveInfo &curve_info = *task.curve_info;
+ const CurveEval &curve = *curve_info.curve;
+
+ const Span<SplinePtr> src_splines = curve.splines();
+
+ /* Initialize point attributes. */
+ threading::parallel_for(src_splines.index_range(), 100, [&](const IndexRange src_spline_range) {
+ for (const int src_spline_index : src_spline_range) {
+ const int dst_spline_index = src_spline_index + task.start_spline_index;
+ const Spline &src_spline = *src_splines[src_spline_index];
+ SplinePtr dst_spline = src_spline.copy_without_attributes();
+ dst_spline->transform(task.transform);
+ const int spline_size = dst_spline->size();
+
+ const CustomDataAttributes &src_point_attributes = src_spline.attributes;
+ CustomDataAttributes &dst_point_attributes = dst_spline->attributes;
+
+ /* Create point ids. */
+ if (all_curves_info.create_id_attribute) {
+ dst_point_attributes.create("id", CD_PROP_INT32);
+ MutableSpan<int> dst_point_ids = dst_point_attributes.get_for_write("id")->typed<int>();
+ std::optional<GSpan> src_point_ids_opt = src_point_attributes.get_for_read("id");
+ if (options.keep_original_ids) {
+ if (src_point_ids_opt.has_value()) {
+ const Span<int> src_point_ids = src_point_ids_opt->typed<int>();
+ dst_point_ids.copy_from(src_point_ids);
+ }
+ else {
+ dst_point_ids.fill(0);
+ }
+ }
+ else {
+ if (src_point_ids_opt.has_value()) {
+ const Span<int> src_point_ids = src_point_ids_opt->typed<int>();
+ for (const int i : IndexRange(dst_spline->size())) {
+ dst_point_ids[i] = noise::hash(task.id, src_point_ids[i]);
+ }
+ }
+ else {
+ for (const int i : IndexRange(dst_spline->size())) {
+ /* Mix spline index into the id, because otherwise points on different splines will
+ * get the same id. */
+ dst_point_ids[i] = noise::hash(task.id, src_spline_index, i);
+ }
+ }
+ }
+ }
+
+ /* Copy generic point attributes. */
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_POINT) {
+ continue;
+ }
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const CPPType &cpp_type = *custom_data_type_to_cpp_type(data_type);
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ const std::optional<GSpan> src_span_opt = src_point_attributes.get_for_read(attribute_id);
+ void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), __func__);
+ if (src_span_opt.has_value()) {
+ const GSpan src_span = *src_span_opt;
+ cpp_type.copy_construct_n(src_span.data(), dst_buffer, spline_size);
+ }
+ else {
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ cpp_type.fill_construct_n(attribute_fallback, dst_buffer, spline_size);
+ }
+ dst_point_attributes.create_by_move(attribute_id, data_type, dst_buffer);
+ }
+
+ dst_splines[dst_spline_index] = std::move(dst_spline);
+ }
+ });
+ /* Initialize spline attributes. */
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain != ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const CPPType &cpp_type = *custom_data_type_to_cpp_type(data_type);
+
+ GMutableSpan dst_span = dst_spline_attributes[attribute_index].slice(task.start_spline_index,
+ src_splines.size());
+ if (curve_info.spline_attributes[attribute_index].has_value()) {
+ const GSpan src_span = *curve_info.spline_attributes[attribute_index];
+ cpp_type.copy_construct_n(src_span.data(), dst_span.data(), src_splines.size());
+ }
+ else {
+ const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
+ if (attribute_fallback == nullptr) {
+ attribute_fallback = cpp_type.default_value();
+ }
+ cpp_type.fill_construct_n(attribute_fallback, dst_span.data(), src_splines.size());
+ }
+ }
+}
+
+static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
+ const AllCurvesInfo &all_curves_info,
+ const Span<RealizeCurveTask> tasks,
+ const OrderedAttributes &ordered_attributes,
+ GeometrySet &r_realized_geometry)
+{
+ if (tasks.is_empty()) {
+ return;
+ }
+
+ const RealizeCurveTask &last_task = tasks.last();
+ const CurveEval &last_curve = *last_task.curve_info->curve;
+ const int tot_splines = last_task.start_spline_index + last_curve.splines().size();
+
+ Array<SplinePtr> dst_splines(tot_splines);
+
+ CurveEval *dst_curve = new CurveEval();
+ dst_curve->attributes.reallocate(tot_splines);
+ CustomDataAttributes &spline_attributes = dst_curve->attributes;
+
+ /* Prepare spline attributes. */
+ Vector<GMutableSpan> dst_spline_attributes;
+ for (const int attribute_index : ordered_attributes.index_range()) {
+ const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
+ const CustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ if (domain == ATTR_DOMAIN_CURVE) {
+ spline_attributes.create(attribute_id, data_type);
+ dst_spline_attributes.append(*spline_attributes.get_for_write(attribute_id));
+ }
+ else {
+ dst_spline_attributes.append({CPPType::get<float>()});
+ }
+ }
+
+ /* Actually execute all tasks. */
+ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
+ for (const int task_index : task_range) {
+ const RealizeCurveTask &task = tasks[task_index];
+ execute_realize_curve_task(
+ options, all_curves_info, task, ordered_attributes, dst_splines, dst_spline_attributes);
+ }
+ });
+
+ dst_curve->add_splines(dst_splines);
+
+ CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
+ dst_component.replace(dst_curve);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Realize Instances
+ * \{ */
+
+static void remove_id_attribute_from_instances(GeometrySet &geometry_set)
+{
+ geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
+ if (sub_geometry.has<InstancesComponent>()) {
+ InstancesComponent &component = geometry_set.get_component_for_write<InstancesComponent>();
+ component.attributes().remove("id");
+ }
+ });
+}
+
+GeometrySet realize_instances(GeometrySet geometry_set, const RealizeInstancesOptions &options)
+{
+ /* The algorithm works in three steps:
+ * 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
+ * 2. Gather "tasks" that need to be executed to realize the instances. Each task corresponds to
+ * instances of the previously preprocessed geometry.
+ * 3. Execute all tasks in parallel.
+ */
+
+ if (!geometry_set.has_instances()) {
+ return geometry_set;
+ }
+
+ if (options.keep_original_ids) {
+ remove_id_attribute_from_instances(geometry_set);
+ }
+
+ AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(geometry_set, options);
+ AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options);
+ AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options);
+
+ Vector<std::unique_ptr<GArray<>>> temporary_arrays;
+ const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
+ all_meshes_info.create_id_attribute ||
+ all_curves_info.create_id_attribute;
+ GatherTasksInfo gather_info = {all_pointclouds_info,
+ all_meshes_info,
+ all_curves_info,
+ create_id_attribute,
+ temporary_arrays};
+ const float4x4 transform = float4x4::identity();
+ InstanceContext attribute_fallbacks(gather_info);
+ gather_realize_tasks_recursive(gather_info, geometry_set, transform, attribute_fallbacks);
+
+ GeometrySet new_geometry_set;
+ execute_realize_pointcloud_tasks(options,
+ all_pointclouds_info,
+ gather_info.r_tasks.pointcloud_tasks,
+ all_pointclouds_info.attributes,
+ new_geometry_set);
+ execute_realize_mesh_tasks(options,
+ all_meshes_info,
+ gather_info.r_tasks.mesh_tasks,
+ all_meshes_info.attributes,
+ all_meshes_info.materials,
+ new_geometry_set);
+ execute_realize_curve_tasks(options,
+ all_curves_info,
+ gather_info.r_tasks.curve_tasks,
+ all_curves_info.attributes,
+ new_geometry_set);
+
+ if (gather_info.r_tasks.first_volume) {
+ new_geometry_set.add(*gather_info.r_tasks.first_volume);
+ }
+
+ return new_geometry_set;
+}
+
+GeometrySet realize_instances_legacy(GeometrySet geometry_set)
+{
+ RealizeInstancesOptions options;
+ options.keep_original_ids = true;
+ options.realize_instance_attributes = false;
+ return realize_instances(std::move(geometry_set), options);
+}
+
+/** \} */
+
+} // namespace blender::geometry
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index afcd551d0af..5ee75619259 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -62,6 +62,7 @@ set(SRC
intern/MOD_gpencilnoise.c
intern/MOD_gpenciloffset.c
intern/MOD_gpencilopacity.c
+ intern/MOD_gpencilshrinkwrap.c
intern/MOD_gpencilsimplify.c
intern/MOD_gpencilsmooth.c
intern/MOD_gpencilsubdiv.c
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
index 7d75ed5804e..95028ee959d 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_lineart.h
@@ -23,6 +23,7 @@
#include "DNA_windowmanager_types.h"
/* Operator types should be in exposed header. */
+
void OBJECT_OT_lineart_bake_strokes(struct wmOperatorType *ot);
void OBJECT_OT_lineart_bake_strokes_all(struct wmOperatorType *ot);
void OBJECT_OT_lineart_clear(struct wmOperatorType *ot);
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index d9285f44a37..56cee115760 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -48,6 +48,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_WeightProximity;
extern GpencilModifierTypeInfo modifierType_Gpencil_WeightAngle;
extern GpencilModifierTypeInfo modifierType_Gpencil_Lineart;
extern GpencilModifierTypeInfo modifierType_Gpencil_Dash;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Shrinkwrap;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
index 2e241ea5848..fe78a7e7bcc 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c
@@ -203,9 +203,6 @@ void gpencil_modifier_curve_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiTemplateCurveMapping(layout, ptr, "curve", 0, false, false, false, false);
}
-/**
- * Draw modifier error message.
- */
void gpencil_modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
{
GpencilModifierData *md = ptr->data;
@@ -232,7 +229,7 @@ PointerRNA *gpencil_modifier_panel_get_property_pointers(Panel *panel, PointerRN
UI_block_lock_clear(block);
UI_block_lock_set(block, ID_IS_LINKED((Object *)ptr->owner_id), ERROR_LIBDATA_MESSAGE);
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
return ptr;
}
@@ -312,7 +309,7 @@ static void gpencil_modifier_panel_header(const bContext *UNUSED(C), Panel *pane
PointerRNA *ptr = UI_panel_custom_data_get(panel);
GpencilModifierData *md = (GpencilModifierData *)ptr->data;
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
bool narrow_panel = (panel->sizex < UI_UNIT_X * 9 && panel->sizex != 0);
@@ -360,9 +357,6 @@ static void gpencil_modifier_panel_header(const bContext *UNUSED(C), Panel *pane
/** \name Modifier Registration Helpers
* \{ */
-/**
- * Create a panel in the context's region
- */
PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
GpencilModifierType type,
PanelDrawFn draw)
@@ -390,12 +384,6 @@ PanelType *gpencil_modifier_panel_register(ARegionType *region_type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
index 782b36d47ed..2cccd6e15dd 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.h
@@ -37,15 +37,27 @@ void gpencil_modifier_masking_panel_draw(Panel *panel, bool use_material, bool u
void gpencil_modifier_curve_header_draw(const bContext *C, Panel *panel);
void gpencil_modifier_curve_panel_draw(const bContext *C, Panel *panel);
+/**
+ * Draw modifier error message.
+ */
void gpencil_modifier_panel_end(struct uiLayout *layout, PointerRNA *ptr);
struct PointerRNA *gpencil_modifier_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
PanelType *gpencil_modifier_panel_register(struct ARegionType *region_type,
GpencilModifierType type,
PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *gpencil_modifier_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 9ea146c77f2..f6a85919de4 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -67,10 +67,10 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(WeightProximity);
INIT_GP_TYPE(Lineart);
INIT_GP_TYPE(Dash);
+ INIT_GP_TYPE(Shrinkwrap);
#undef INIT_GP_TYPE
}
-/* verify if valid layer, material and pass index */
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
const Material *material,
@@ -147,7 +147,6 @@ bool is_stroke_affected_by_modifier(Object *ob,
return true;
}
-/* verify if valid vertex group *and return weight */
float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
{
float weight = 1.0f;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 2878ad4c73a..59ed11a02f3 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -29,6 +29,9 @@ struct Object;
struct bGPDlayer;
struct bGPDstroke;
+/**
+ * Verify if valid layer, material and pass index.
+ */
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
const struct Material *material,
@@ -42,4 +45,7 @@ bool is_stroke_affected_by_modifier(struct Object *ob,
const bool inv3,
const bool inv4);
+/**
+ * Verify if valid vertex group *and return weight.
+ */
float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index 7d2eb4b2c75..6a4d0de5c80 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -313,8 +313,6 @@ static void panel_draw(const bContext *C, Panel *panel)
UI_TEMPLATE_LIST_FLAG_NONE);
uiLayout *col = uiLayoutColumn(row, false);
- uiLayoutSetContextPointer(col, "modifier", ptr);
-
uiLayout *sub = uiLayoutColumn(col, true);
uiItemO(sub, "", ICON_ADD, "GPENCIL_OT_segment_add");
uiItemO(sub, "", ICON_REMOVE, "GPENCIL_OT_segment_remove");
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
index 80b60547e92..af0067e06aa 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
@@ -23,8 +23,10 @@
#include <stdio.h>
+#include "BLI_hash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -56,6 +58,7 @@
#include "MOD_gpencil_util.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
static void initData(GpencilModifierData *md)
{
@@ -71,6 +74,20 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
BKE_gpencil_modifier_copydata_generic(md, target);
}
+static float *noise_table(int len, int offset, int seed)
+{
+ float *table = MEM_callocN(sizeof(float) * len, __func__);
+ for (int i = 0; i < len; i++) {
+ table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + offset + 1));
+ }
+ return table;
+}
+
+BLI_INLINE float table_sample(float *table, float x)
+{
+ return interpf(table[(int)ceilf(x)], table[(int)floor(x)], fractf(x));
+}
+
static bool gpencil_modify_stroke(bGPDstroke *gps,
const float length,
const float overshoot_fac,
@@ -104,9 +121,15 @@ static bool gpencil_modify_stroke(bGPDstroke *gps,
return changed;
}
-static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke *gps)
+static void applyLength(GpencilModifierData *md,
+ Depsgraph *depsgraph,
+ bGPdata *gpd,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ Object *ob)
{
bool changed = false;
+ LengthGpencilModifierData *lmd = (LengthGpencilModifierData *)md;
const float len = (lmd->mode == GP_LENGTH_ABSOLUTE) ? 1.0f :
BKE_gpencil_stroke_length(gps, true);
const int totpoints = gps->totpoints;
@@ -120,11 +143,48 @@ static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke
int first_mode = 1;
float second_fac = lmd->end_fac;
int second_mode = 2;
+
+ float rand[2] = {0.0f, 0.0f};
+ if (lmd->rand_start_fac != 0.0 || lmd->rand_end_fac != 0.0) {
+ int seed = lmd->seed;
+
+ /* Make sure different modifiers get different seeds. */
+ seed += BLI_hash_string(ob->id.name + 2);
+ seed += BLI_hash_string(md->name);
+
+ if (lmd->flag & GP_LENGTH_USE_RANDOM) {
+ seed += ((int)DEG_get_ctime(depsgraph)) / lmd->step;
+ }
+
+ float rand_offset = BLI_hash_int_01(seed);
+
+ /* Get stroke index for random offset. */
+ int rnd_index = BLI_findindex(&gpf->strokes, gps);
+ const uint primes[2] = {2, 3};
+ double offset[2] = {0.0f, 0.0f};
+ double r[2];
+
+ float *noise_table_length = noise_table(4, (int)floor(lmd->rand_offset), seed + 2);
+
+ /* To ensure a nice distribution, we use halton sequence and offset using the seed. */
+ BLI_halton_2d(primes, offset, rnd_index, r);
+ for (int j = 0; j < 2; j++) {
+ float noise = table_sample(noise_table_length, j * 2 + fractf(lmd->rand_offset));
+
+ rand[j] = fmodf(r[j] + rand_offset, 1.0f);
+ rand[j] = fabs(fmodf(sin(rand[j] * 12.9898f + j * 78.233f) * 43758.5453f, 1.0f) + noise);
+ }
+
+ MEM_SAFE_FREE(noise_table_length);
+
+ first_fac = first_fac + rand[0] * lmd->rand_start_fac;
+ second_fac = second_fac + rand[1] * lmd->rand_end_fac;
+ }
+
if (first_fac < 0) {
SWAP(float, first_fac, second_fac);
SWAP(int, first_mode, second_mode);
}
-
const int first_extra_point_count = ceil(first_fac * lmd->point_density);
const int second_extra_point_count = ceil(second_fac * lmd->point_density);
@@ -161,10 +221,10 @@ static void applyLength(LengthGpencilModifierData *lmd, bGPdata *gpd, bGPDstroke
}
static void deformStroke(GpencilModifierData *md,
- Depsgraph *UNUSED(depsgraph),
+ Depsgraph *depsgraph,
Object *ob,
bGPDlayer *gpl,
- bGPDframe *UNUSED(gpf),
+ bGPDframe *gpf,
bGPDstroke *gps)
{
bGPdata *gpd = ob->data;
@@ -187,7 +247,7 @@ static void deformStroke(GpencilModifierData *md,
/* Don't affect cyclic strokes as they have no start/end. */
return;
}
- applyLength(lmd, gpd, gps);
+ applyLength(md, depsgraph, gpd, gpf, gps, ob);
}
static void bakeModifier(Main *UNUSED(bmain),
@@ -214,6 +274,39 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
}
+static void random_header_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiItemR(layout, ptr, "use_random", 0, IFACE_("Randomize"), ICON_NONE);
+}
+
+static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_random"));
+
+ uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
+}
+
+static void offset_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+ uiLayoutSetPropSep(layout, true);
+ uiItemR(layout, ptr, "random_start_factor", 0, IFACE_("Random Offset Start"), ICON_NONE);
+ uiItemR(layout, ptr, "random_end_factor", 0, IFACE_("Random Offset End"), ICON_NONE);
+ uiItemR(layout, ptr, "random_offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE);
+}
+
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -277,6 +370,10 @@ static void panelRegister(ARegionType *region_type)
region_type, eGpencilModifierType_Length, panel_draw);
gpencil_modifier_subpanel_register(
region_type, "curvature", "", curvature_header_draw, curvature_panel_draw, panel_type);
+ PanelType *offset_panel = gpencil_modifier_subpanel_register(
+ region_type, "offset", "Random Offsets", NULL, offset_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
+ region_type, "randomize", "", random_header_draw, random_panel_draw, offset_panel);
gpencil_modifier_subpanel_register(
region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
new file mode 100644
index 00000000000..6990b41e6ce
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
@@ -0,0 +1,350 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+#include <string.h> /* For #MEMCPY_STRUCT_AFTER. */
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_defaults.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_shrinkwrap.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_ui_common.h"
+#include "MOD_gpencil_util.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ShrinkwrapGpencilModifierData *gpmd = (ShrinkwrapGpencilModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(ShrinkwrapGpencilModifierData), modifier);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copydata_generic(md, target);
+}
+
+static void deformStroke(GpencilModifierData *md,
+ Depsgraph *UNUSED(depsgraph),
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps)
+{
+ bGPdata *gpd = ob->data;
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->material,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_SHRINKWRAP_INVERT_LAYER,
+ mmd->flag & GP_SHRINKWRAP_INVERT_PASS,
+ mmd->flag & GP_SHRINKWRAP_INVERT_LAYERPASS,
+ mmd->flag & GP_SHRINKWRAP_INVERT_MATERIAL)) {
+ return;
+ }
+
+ if ((mmd->cache_data == NULL) || (mmd->target == ob) || (mmd->aux_target == ob)) {
+ return;
+ }
+
+ bGPDspoint *pt = gps->points;
+ float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * gps->totpoints, __func__);
+ int i;
+ /* Prepare array of points. */
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(vert_coords[i], &pt->x);
+ }
+
+ shrinkwrapGpencilModifier_deform(mmd, ob, gps->dvert, def_nr, vert_coords, gps->totpoints);
+
+ /* Apply deformed coordinates. */
+ pt = gps->points;
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(&pt->x, vert_coords[i]);
+ /* Smooth stroke. */
+ if (mmd->smooth_factor > 0.0f) {
+ for (int r = 0; r < mmd->smooth_step; r++) {
+ BKE_gpencil_stroke_smooth_point(gps, i, mmd->smooth_factor, true);
+ }
+ }
+ }
+
+ MEM_freeN(vert_coords);
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+}
+
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if ((mmd->target == ob) || (mmd->aux_target == ob)) {
+ return;
+ }
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ /* Apply shrinkwrap effects on this frame. */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+
+ /* Recalculate shrinkwrap data. */
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ Object *ob_target = DEG_get_evaluated_object(depsgraph, mmd->target);
+ Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__);
+ if (BKE_shrinkwrap_init_tree(
+ mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) {
+
+ /* Compute shrinkwrap effects on this frame. */
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ deformStroke(md, depsgraph, ob, gpl, gpf, gps);
+ }
+ }
+ /* Free data. */
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+ }
+ }
+
+ /* Return frame state and DB to original state. */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ if (mmd->cache_data) {
+ BKE_shrinkwrap_free_tree(mmd->cache_data);
+ MEM_SAFE_FREE(mmd->cache_data);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+
+ /* The object type check is only needed here in case we have a placeholder
+ * object assigned (because the library containing the mesh is missing).
+ *
+ * In other cases it should be impossible to have a type mismatch.
+ */
+ if (!mmd->target || mmd->target->type != OB_MESH) {
+ return true;
+ }
+ if (mmd->aux_target && mmd->aux_target->type != OB_MESH) {
+ return true;
+ }
+ return false;
+}
+
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+ CustomData_MeshMasks mask = {0};
+
+ if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) {
+ mask.vmask |= CD_MASK_NORMAL;
+ mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ }
+
+ if (mmd->target != NULL) {
+ DEG_add_object_relation(ctx->node, mmd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(ctx->node, mmd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_customdata_mask(ctx->node, mmd->target, &mask);
+ if (mmd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ DEG_add_special_eval_flag(ctx->node, &mmd->target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
+ }
+ if (mmd->aux_target != NULL) {
+ DEG_add_object_relation(
+ ctx->node, mmd->aux_target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(
+ ctx->node, mmd->aux_target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_customdata_mask(ctx->node, mmd->aux_target, &mask);
+ if (mmd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ DEG_add_special_eval_flag(
+ ctx->node, &mmd->aux_target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
+ }
+ DEG_add_modifier_to_transform_relation(ctx->node, "Shrinkwrap Modifier");
+}
+
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->target, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->aux_target, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *row, *col;
+ uiLayout *layout = panel->layout;
+ int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayoutSetPropSep(layout, true);
+
+ int wrap_method = RNA_enum_get(ptr, "wrap_method");
+
+ uiItemR(layout, ptr, "wrap_method", 0, NULL, ICON_NONE);
+
+ if (ELEM(wrap_method,
+ MOD_SHRINKWRAP_PROJECT,
+ MOD_SHRINKWRAP_NEAREST_SURFACE,
+ MOD_SHRINKWRAP_TARGET_PROJECT)) {
+ uiItemR(layout, ptr, "wrap_mode", 0, NULL, ICON_NONE);
+ }
+
+ if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
+ uiItemR(layout, ptr, "project_limit", 0, IFACE_("Limit"), ICON_NONE);
+ uiItemR(layout, ptr, "subsurf_levels", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRowWithHeading(col, true, IFACE_("Axis"));
+ uiItemR(row, ptr, "use_project_x", toggles_flag, NULL, ICON_NONE);
+ uiItemR(row, ptr, "use_project_y", toggles_flag, NULL, ICON_NONE);
+ uiItemR(row, ptr, "use_project_z", toggles_flag, NULL, ICON_NONE);
+
+ uiItemR(col, ptr, "use_negative_direction", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_positive_direction", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, ptr, "cull_face", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col,
+ RNA_boolean_get(ptr, "use_negative_direction") &&
+ RNA_enum_get(ptr, "cull_face") != 0);
+ uiItemR(col, ptr, "use_invert_cull", 0, NULL, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "target", 0, NULL, ICON_NONE);
+ if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
+ uiItemR(layout, ptr, "auxiliary_target", 0, NULL, ICON_NONE);
+ }
+ uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "smooth_factor", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "smooth_step", 0, IFACE_("Repeat"), ICON_NONE);
+
+ gpencil_modifier_panel_end(layout, ptr);
+}
+
+static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ gpencil_modifier_masking_panel_draw(panel, true, true);
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ PanelType *panel_type = gpencil_modifier_panel_register(
+ region_type, eGpencilModifierType_Shrinkwrap, panel_draw);
+ gpencil_modifier_subpanel_register(
+ region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Shrinkwrap = {
+ /* name */ "Shrinkwrap",
+ /* structName */ "ShrinkwrapGpencilModifierData",
+ /* structSize */ sizeof(ShrinkwrapGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+ /* panelRegister */ panelRegister,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
index b00db1ba2d2..a63cbb53645 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -132,7 +132,7 @@ static void deformStroke(GpencilModifierData *md,
const float val = mmd->factor * weight;
/* perform smoothing */
if (mmd->flag & GP_SMOOTH_MOD_LOCATION) {
- BKE_gpencil_stroke_smooth_point(gps, i, val);
+ BKE_gpencil_stroke_smooth_point(gps, i, val, false);
}
if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) {
BKE_gpencil_stroke_smooth_strength(gps, i, val);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 869f93f832e..2ef72da03fd 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -485,7 +485,7 @@ typedef struct LineartBoundingArea {
(((a) + DBL_TRIANGLE_LIM) >= (b) && ((a)-DBL_TRIANGLE_LIM) <= (b))
/* Notes on this function:
-
+ *
* r_ratio: The ratio on segment a1-a2. When r_ratio is very close to zero or one, it
* fixes the value to zero or one, this makes it easier to identify "on the tip" situations.
*
@@ -649,9 +649,18 @@ void MOD_lineart_destroy_render_data(struct LineartGpencilModifierData *lmd);
void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb);
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb);
+/**
+ * This function only connects two different chains. It will not do any clean up or smart chaining.
+ * So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
+ * implemented yet.
+ */
void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold);
void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb);
+/**
+ * This should always be the last stage!, see the end of
+ * #MOD_lineart_chain_split_for_fixed_occlusion().
+ */
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance);
void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
@@ -661,6 +670,11 @@ void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
+/**
+ * This is the entry point of all line art calculations.
+ *
+ * \return True when a change is made.
+ */
bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
struct LineartGpencilModifierData *lmd,
struct LineartCache **cached_result,
@@ -668,15 +682,24 @@ bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
struct Scene;
+/**
+ * This only gets initial "biggest" tile.
+ */
LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
double x,
double y);
+/**
+ * Wrapper for more convenience.
+ */
LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y);
struct bGPDframe;
struct bGPDlayer;
+/**
+ * Wrapper for external calls.
+ */
void MOD_lineart_gpencil_generate(LineartCache *cache,
struct Depsgraph *depsgraph,
struct Object *ob,
@@ -697,6 +720,9 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
const char *vgname,
int modifier_flags);
+/**
+ * Length is in image space.
+ */
float MOD_lineart_chain_compute_length(LineartEdgeChain *ec);
void ED_operatortypes_lineart(void);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 88dcfb89c25..0deb8b1c335 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -794,11 +794,6 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
return closest_cre;
}
-/**
- * This function only connects two different chains. It will not do any clean up or smart chaining.
- * So no: removing overlapping chains, removal of short isolated segments, and no loop reduction is
- * implemented yet.
- */
void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec;
@@ -881,9 +876,6 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
}
}
-/**
- * Length is in image space.
- */
float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
{
LineartEdgeChainItem *eci;
@@ -1072,10 +1064,6 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
}
}
-/**
- * This should always be the last stage!, see the end of
- * #MOD_lineart_chain_split_for_fixed_occlusion().
- */
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
{
LineartEdgeChain *ec, *new_ec;
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 88d717eb032..d9a32711833 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -502,10 +502,6 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
rb->edge_mark.last = rb->edge_mark.first;
rb->floating.last = rb->floating.first;
- /* This is needed because the occlusion function expects the camera vector to point towards the
- * camera. */
- negate_v3_db(rb->view_vector);
-
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
for (i = 0; i < thread_count; i++) {
@@ -579,9 +575,7 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
c2 = ratiod(v0[1], v1[1], v[1]);
return (c2 >= -DBL_TRIANGLE_LIM && c2 <= 1 + DBL_TRIANGLE_LIM);
}
- else {
- return false;
- }
+ return false;
}
if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[1], v0[1])) {
@@ -592,9 +586,7 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
c1 = ratiod(v0[0], v1[0], v[0]);
return (c1 >= -DBL_TRIANGLE_LIM && c1 <= 1 + DBL_TRIANGLE_LIM);
}
- else {
- return false;
- }
+ return false;
}
if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) {
@@ -2336,9 +2328,9 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* if returns true, then from/to will carry the occluded segments
* in ratio from `e->v1` to `e->v2`. The line is later cut with these two values.
*
- * TODO: (Yiming) This function uses a convoluted method that needs to be redesigned.
+ * TODO(@Yiming): This function uses a convoluted method that needs to be redesigned.
*
- * 1) The lineart_intersect_seg_seg() and lineart_point_triangle_relation() are separate calls,
+ * 1) The #lineart_intersect_seg_seg() and #lineart_point_triangle_relation() are separate calls,
* which would potentially return results that doesn't agree, especially when it's an edge
* extruding from one of the triangle's point. To get the information using one math process can
* solve this problem.
@@ -2350,7 +2342,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* I keep this function as-is because it's still fast, and more importantly the output value
* threshold is already in tune with the cutting function in the next stage.
* While current "edge aligned" fix isn't ideal, it does solve most of the precision issue
- * especially in ortho camera mode.
+ * especially in orthographic camera mode.
*/
static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
const LineartTriangle *tri,
@@ -3010,7 +3002,7 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
*/
static void lineart_main_get_view_vector(LineartRenderBuffer *rb)
{
- float direction[3] = {0, 0, -1};
+ float direction[3] = {0, 0, 1};
float trans[3];
float inv[4][4];
float obmat_no_scale[4][4];
@@ -3767,9 +3759,6 @@ static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
return true;
}
-/**
- * This only gets initial "biggest" tile.
- */
LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
double x,
double y)
@@ -3841,9 +3830,6 @@ static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, d
return iba;
}
-/**
- * Wrapper for more convenience.
- */
LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
{
LineartBoundingArea *ba;
@@ -4149,11 +4135,6 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
return 0;
}
-/**
- * This is the entry point of all line art calculations.
- *
- * \return True when a change is made.
- */
bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartGpencilModifierData *lmd,
LineartCache **cached_result,
@@ -4398,7 +4379,7 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
}
}
- if (types & LRT_EDGE_FLAG_INTERSECTION) {
+ if (ec->type & LRT_EDGE_FLAG_INTERSECTION) {
if (mask_switches & LRT_GPENCIL_INTERSECTION_MATCH) {
if (ec->intersection_mask != intersection_mask) {
continue;
@@ -4481,9 +4462,6 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
}
-/**
- * Wrapper for external calls.
- */
void MOD_lineart_gpencil_generate(LineartCache *cache,
Depsgraph *depsgraph,
Object *ob,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
index b74499daf6b..c53404a87e2 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -444,7 +444,6 @@ static int lineart_gpencil_clear_strokes_all_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* Bake all line art modifiers on the current object. */
void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
{
ot->name = "Bake Line Art";
@@ -456,7 +455,6 @@ void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
ot->modal = lineart_gpencil_bake_strokes_commom_modal;
}
-/* Bake all lineart objects in the scene. */
void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot)
{
ot->name = "Bake Line Art (All)";
@@ -468,7 +466,6 @@ void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot)
ot->modal = lineart_gpencil_bake_strokes_commom_modal;
}
-/* clear all line art modifiers on the current object. */
void OBJECT_OT_lineart_clear(wmOperatorType *ot)
{
ot->name = "Clear Baked Line Art";
@@ -478,7 +475,6 @@ void OBJECT_OT_lineart_clear(wmOperatorType *ot)
ot->exec = lineart_gpencil_clear_strokes_exec;
}
-/* clear all lineart objects in the scene. */
void OBJECT_OT_lineart_clear_all(wmOperatorType *ot)
{
ot->name = "Clear Baked Line Art (All)";
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index 911c8cc2e42..a8bc4f271c9 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -102,25 +102,48 @@ void GPU_batch_init_ex(GPUBatch *batch,
GPUVertBuf *vert,
GPUIndexBuf *elem,
eGPUBatchFlag owns_flag);
+/**
+ * This will share the VBOs with the new batch.
+ */
void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src);
#define GPU_batch_create(prim, verts, elem) GPU_batch_create_ex(prim, verts, elem, 0)
#define GPU_batch_init(batch, prim, verts, elem) GPU_batch_init_ex(batch, prim, verts, elem, 0)
-/* Same as discard but does not free. (does not call free callback). */
+/**
+ * Same as discard but does not free. (does not call free callback).
+ */
void GPU_batch_clear(GPUBatch *);
-void GPU_batch_discard(GPUBatch *); /* verts & elem are not discarded */
+/**
+ * \note Verts & elem are not discarded.
+ */
+void GPU_batch_discard(GPUBatch *);
+/**
+ * \note Override ONLY the first instance VBO (and free them if owned).
+ */
void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */
+/**
+ * \note Override any previously assigned elem (and free it if owned).
+ */
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo);
int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
+/**
+ * Returns the index of verts in the batch.
+ */
int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
#define GPU_batch_vertbuf_add(batch, verts) GPU_batch_vertbuf_add_ex(batch, verts, false)
void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader);
+/**
+ * Bind program bound to IMM to the batch.
+ *
+ * XXX Use this with much care. Drawing with the #GPUBatch API is not compatible with IMM.
+ * DO NOT DRAW WITH THE BATCH BEFORE CALLING #immUnbindProgram.
+ */
void GPU_batch_program_set_imm_shader(GPUBatch *batch);
void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id);
void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
@@ -129,6 +152,7 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
/* Will only work after setting the batch program. */
/* TODO(fclem): These need to be replaced by GPU_shader_uniform_* with explicit shader. */
+
#define GPU_batch_uniform_1i(batch, name, x) GPU_shader_uniform_1i((batch)->shader, name, x);
#define GPU_batch_uniform_1b(batch, name, x) GPU_shader_uniform_1b((batch)->shader, name, x);
#define GPU_batch_uniform_1f(batch, name, x) GPU_shader_uniform_1f((batch)->shader, name, x);
@@ -151,14 +175,19 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
void GPU_batch_draw(GPUBatch *batch);
void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count);
+/**
+ * Draw multiple instance of a batch without having any instance attributes.
+ */
void GPU_batch_draw_instanced(GPUBatch *batch, int i_count);
-/* This does not bind/unbind shader and does not call GPU_matrix_bind() */
+/**
+ * This does not bind/unbind shader and does not call GPU_matrix_bind().
+ */
void GPU_batch_draw_advanced(GPUBatch *, int v_first, int v_count, int i_first, int i_count);
#if 0 /* future plans */
-/* Can multiple batches share a GPUVertBuf? Use ref count? */
+/* Can multiple batches share a #GPUVertBuf? Use ref count? */
/* We often need a batch with its own data, to be created and discarded together. */
/* WithOwn variants reduce number of system allocations. */
diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h
index 19f200fecbf..73c9172f2ba 100644
--- a/source/blender/gpu/GPU_batch_presets.h
+++ b/source/blender/gpu/GPU_batch_presets.h
@@ -35,7 +35,8 @@ extern "C" {
/* gpu_batch_presets.c */
-/* Replacement for gluSphere */
+/* Replacement for #gluSphere */
+
struct GPUBatch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT;
struct GPUBatch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT;
struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
@@ -43,6 +44,9 @@ struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
const float col_dark[4],
const float width) ATTR_WARN_UNUSED_RESULT;
+/**
+ * To be used with procedural placement inside shader.
+ */
struct GPUBatch *GPU_batch_preset_quad(void);
void gpu_batch_presets_init(void);
diff --git a/source/blender/gpu/GPU_batch_utils.h b/source/blender/gpu/GPU_batch_utils.h
index 37dccc4621c..660ae0c8844 100644
--- a/source/blender/gpu/GPU_batch_utils.h
+++ b/source/blender/gpu/GPU_batch_utils.h
@@ -30,6 +30,16 @@ extern "C" {
struct rctf;
/* gpu_batch_utils.c */
+
+/**
+ * Creates triangles from a byte-array of polygons.
+ *
+ * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function.
+ *
+ * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon).
+ * \param polys_flat_len: Length of the array (must be an even number).
+ * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1.
+ */
struct GPUBatch *GPU_batch_tris_from_poly_2d_encoded(
const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
@@ -37,7 +47,11 @@ struct GPUBatch *GPU_batch_wire_from_poly_2d_encoded(
const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
-/* Only use by draw manager. Use the presets function instead for interface. */
+/**
+ * Replacement for #gluSphere.
+ *
+ * \note Only use by draw manager. Use the presets function instead for interface.
+ */
struct GPUBatch *gpu_batch_sphere(int lat_res, int lon_res) ATTR_WARN_UNUSED_RESULT;
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index b770bde65fc..9ba283bf65f 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -44,11 +44,17 @@ struct Mesh;
struct PBVH;
struct SubdivCCG;
-/* Buffers for drawing from PBVH grids. */
+/**
+ * Buffers for drawing from PBVH grids.
+ */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
-/* Build must be called once before using the other functions, used every time
- * mesh topology changes. Threaded. */
+/**
+ * Build must be called once before using the other functions,
+ * used every time mesh topology changes.
+ *
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
@@ -58,23 +64,36 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
const int face_indices_len,
const struct Mesh *mesh);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_hidden);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
-/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Free part of data for update. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers);
void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
const struct DMFlagMat *grid_flag_mats,
const int *grid_indices);
-/* Update mesh buffers without topology changes. Threaded. */
+/**
+ * Update mesh buffers without topology changes. Threaded.
+ */
enum {
GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1),
GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 2),
GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS = (1 << 3),
};
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
const float *vmask,
@@ -85,6 +104,11 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MPropCol *vtcol,
const int update_flags);
+/**
+ * Creates a vertex buffer (coordinate, normal, color) and,
+ * if smooth shading, an element index buffer.
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
struct GSet *bm_faces,
@@ -92,6 +116,9 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct GSet *bm_other_verts,
const int update_flags);
+/**
+ * Threaded: do not call any functions that use OpenGL calls!
+ */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,
struct CCGElem **grids,
@@ -104,13 +131,17 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
const struct CCGKey *key,
const int update_flags);
-/* Finish update. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Finish update. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers);
-/* Free buffers. Not thread safe, must run in OpenGL main thread. */
+/**
+ * Free buffers. Not thread safe, must run in OpenGL main thread.
+ */
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
-/* draw */
+/** Draw. */
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index 5b5d0f16c9f..9cd1dbd37f1 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -64,6 +64,9 @@ bool GPU_shader_image_load_store_support(void);
bool GPU_mem_stats_supported(void);
void GPU_mem_stats_get(int *totalmem, int *freemem);
+/**
+ * Return support for the active context + window.
+ */
bool GPU_stereo_quadbuffer_support(void);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index 82f13424502..5189fa1ae41 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -44,8 +44,14 @@ void GPU_backend_exit(void);
typedef struct GPUContext GPUContext;
GPUContext *GPU_context_create(void *ghost_window);
+/**
+ * To be called after #GPU_context_active_set(ctx_to_destroy).
+ */
void GPU_context_discard(GPUContext *);
+/**
+ * Ctx can be NULL.
+ */
void GPU_context_active_set(GPUContext *);
GPUContext *GPU_context_active_get(void);
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index f67e850ad80..9796ac63272 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -33,7 +33,14 @@ extern "C" {
void GPU_debug_group_begin(const char *name);
void GPU_debug_group_end(void);
+/**
+ * Return a formatted string showing the current group hierarchy in this format:
+ * "Group1 > Group 2 > Group3 > ... > GroupN : "
+ */
void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf);
+/**
+ * Return true if inside a debug group with the same name.
+ */
bool GPU_debug_group_match(const char *ref);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index bf0ab3dc533..b203c49a7f1 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -62,6 +62,9 @@ typedef struct GPUOffScreen GPUOffScreen;
GPUFrameBuffer *GPU_framebuffer_create(const char *name);
void GPU_framebuffer_free(GPUFrameBuffer *fb);
void GPU_framebuffer_bind(GPUFrameBuffer *fb);
+/**
+ * Workaround for binding a SRGB frame-buffer without doing the SRGB transform.
+ */
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *fb);
void GPU_framebuffer_restore(void);
@@ -69,6 +72,9 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
GPUFrameBuffer *GPU_framebuffer_active_get(void);
+/**
+ * Returns the default frame-buffer. Will always exists even if it's just a dummy.
+ */
GPUFrameBuffer *GPU_framebuffer_back_get(void);
#define GPU_FRAMEBUFFER_FREE_SAFE(fb) \
@@ -113,6 +119,12 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, struct GPUTexture *tex);
GPU_framebuffer_config_array(*(_fb), config, (sizeof(config) / sizeof(GPUAttachment))); \
} while (0)
+/**
+ * First #GPUAttachment in *config is always the depth/depth_stencil buffer.
+ * Following #GPUAttachments are color buffers.
+ * Setting #GPUAttachment.mip to -1 will leave the texture in this slot.
+ * Setting #GPUAttachment.tex to NULL will detach the texture in this slot.
+ */
void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_len);
#define GPU_ATTACHMENT_NONE \
@@ -156,8 +168,16 @@ void GPU_framebuffer_texture_cubeface_attach(
/* Frame-buffer operations. */
+/**
+ * Viewport and scissor size is stored per frame-buffer.
+ * It is only reset to its original dimensions explicitly OR when binding the frame-buffer after
+ * modifying its attachments.
+ */
void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h);
void GPU_framebuffer_viewport_get(GPUFrameBuffer *fb, int r_viewport[4]);
+/**
+ * Reset to its attachment(s) size.
+ */
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *fb);
void GPU_framebuffer_clear(GPUFrameBuffer *fb,
@@ -184,6 +204,9 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb,
#define GPU_framebuffer_clear_color_depth_stencil(fb, col, depth, stencil) \
GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, col, depth, stencil)
+/**
+ * Clear all textures attached to this frame-buffer with a different color.
+ */
void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4]);
void GPU_framebuffer_read_depth(
@@ -198,6 +221,9 @@ void GPU_framebuffer_read_color(GPUFrameBuffer *fb,
eGPUDataFormat format,
void *data);
+/**
+ * Read_slot and write_slot are only used for color buffers.
+ */
void GPU_framebuffer_blit(GPUFrameBuffer *fb_read,
int read_slot,
GPUFrameBuffer *fb_write,
@@ -233,6 +259,9 @@ int GPU_offscreen_width(const GPUOffScreen *ofs);
int GPU_offscreen_height(const GPUOffScreen *ofs);
struct GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs);
+/**
+ * \note only to be used by viewport code!
+ */
void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUFrameBuffer **r_fb,
struct GPUTexture **r_color,
diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h
index edb7c9fe5b5..a175fc65ba4 100644
--- a/source/blender/gpu/GPU_immediate.h
+++ b/source/blender/gpu/GPU_immediate.h
@@ -39,7 +39,7 @@ extern "C" {
/** Returns a cleared vertex format, ready for #add_attr. */
GPUVertFormat *immVertexFormat(void);
-/** Every immBegin must have a program bound first. */
+/** Every #immBegin must have a program bound first. */
void immBindShader(GPUShader *shader);
/** Call after your last immEnd, or before binding another program. */
void immUnbindProgram(void);
@@ -50,10 +50,12 @@ void immBegin(GPUPrimType, uint vertex_len);
void immBeginAtMost(GPUPrimType, uint max_vertex_len);
void immEnd(void); /* finishes and draws. */
-/* immBegin a batch, then use standard immFunctions as usual. */
-/* immEnd will finalize the batch instead of drawing. */
-/* Then you can draw it as many times as you like!
+/* - #immBegin a batch, then use standard `imm*` functions as usual.
+ * - #immEnd will finalize the batch instead of drawing.
+ *
+ * Then you can draw it as many times as you like!
* Partially replaces the need for display lists. */
+
GPUBatch *immBeginBatch(GPUPrimType, uint vertex_len);
GPUBatch *immBeginBatchAtMost(GPUPrimType, uint vertex_len);
@@ -81,12 +83,14 @@ void immAttr4ub(uint attr_id, unsigned char r, unsigned char g, unsigned char b,
void immAttr3ubv(uint attr_id, const unsigned char data[3]);
void immAttr4ubv(uint attr_id, const unsigned char data[4]);
-/* Explicitly skip an attribute. */
-/* This advanced option kills automatic value copying for this attr_id. */
+/* Explicitly skip an attribute.
+ * This advanced option kills automatic value copying for this attr_id. */
+
void immAttrSkip(uint attr_id);
-/* Provide one last attribute value & end the current vertex. */
-/* This is most often used for 2D or 3D position (similar to glVertex). */
+/* Provide one last attribute value & end the current vertex.
+ * This is most often used for 2D or 3D position (similar to #glVertex). */
+
void immVertex2f(uint attr_id, float x, float y);
void immVertex3f(uint attr_id, float x, float y, float z);
void immVertex4f(uint attr_id, float x, float y, float z, float w);
@@ -101,6 +105,7 @@ void immVertex3fv(uint attr_id, const float data[3]);
void immVertex2iv(uint attr_id, const int data[2]);
/* Provide uniform values that don't change for the entire draw call. */
+
void immUniform1i(const char *name, int x);
void immUniform1f(const char *name, float x);
void immUniform2f(const char *name, float x, float y);
@@ -109,6 +114,9 @@ void immUniform3f(const char *name, float x, float y, float z);
void immUniform3fv(const char *name, const float data[3]);
void immUniform4f(const char *name, float x, float y, float z, float w);
void immUniform4fv(const char *name, const float data[4]);
+/**
+ * Note array index is not supported for name (i.e: "array[0]").
+ */
void immUniformArray4fv(const char *bare_name, const float *data, int count);
void immUniformMatrix4fv(const char *name, const float data[4][4]);
@@ -116,7 +124,8 @@ void immBindTexture(const char *name, GPUTexture *tex);
void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state);
/* Convenience functions for setting "uniform vec4 color". */
-/* The rgb functions have implicit alpha = 1.0. */
+/* The RGB functions have implicit alpha = 1.0. */
+
void immUniformColor4f(float r, float g, float b, float a);
void immUniformColor4fv(const float rgba[4]);
void immUniformColor3f(float r, float g, float b);
@@ -135,7 +144,7 @@ void immUniformColor4ubv(const unsigned char rgba[4]);
*/
void immBindBuiltinProgram(eGPUBuiltinShader shader_id);
-/* Extend immUniformColor to take Blender's themes */
+/** Extend #immUniformColor to take Blender's themes. */
void immUniformThemeColor(int color_id);
void immUniformThemeColorAlpha(int color_id, float a);
void immUniformThemeColor3(int color_id);
diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h
index 047c3d3da00..102bd6c284c 100644
--- a/source/blender/gpu/GPU_immediate_util.h
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -31,32 +31,85 @@ extern "C" {
void immRectf(uint pos, float x1, float y1, float x2, float y2);
void immRecti(uint pos, int x1, int y1, int x2, int y2);
-/* Same as immRectf/immRecti but does not call immBegin/immEnd. To use with GPU_PRIM_TRIS. */
+/**
+ * Same as #immRectf / #immRecti but does not call #immBegin / #immEnd.
+ * To use with #GPU_PRIM_TRIS.
+ */
void immRectf_fast(uint pos, float x1, float y1, float x2, float y2);
void immRectf_fast_with_color(
uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4]);
void immRecti_fast_with_color(
uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4]);
+/**
+ * Pack color into 3 bytes
+ *
+ * This define converts a numerical value to the equivalent 24-bit
+ * color, while not being endian-sensitive. On little-endian, this
+ * is the same as doing a 'naive' indexing, on big-endian, it is not!
+ *
+ * \note BGR format (i.e. 0xBBGGRR)...
+ *
+ * \param x: color.
+ */
void imm_cpack(uint x);
+/**
+ * Draw a circle outline with the given \a radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \param shdr_pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param radius: The circle's radius.
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ */
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments);
+/**
+ * Draw a filled circle with the given \a radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \param shdr_pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param radius: The circle's radius.
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ */
void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_wire_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments);
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments);
void imm_draw_circle_fill_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments);
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments);
-/* use this version when GPUVertFormat has a vec3 position */
+/**
+ * Use this version when #GPUVertFormat has a vec3 position.
+ */
void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_dashed_3d(uint pos, float x, float y, float radius, int nsegments);
void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments);
-/* same as 'imm_draw_disk_partial_fill_2d', except it draws a wire arc. */
+/**
+ * Same as 'imm_draw_disk_partial_fill_2d', except it draws a wire arc.
+ */
void imm_draw_circle_partial_wire_2d(
uint pos, float x, float y, float radius, int nsegments, float start, float sweep);
+/**
+ * Draw a filled arc with the given inner and outer radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \note Arguments are `gluPartialDisk` compatible.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param rad_inner: The inner circle's radius.
+ * \param rad_outer: The outer circle's radius (can be zero).
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ * \param start: Specifies the starting angle, in degrees, of the disk portion.
+ * \param sweep: Specifies the sweep angle, in degrees, of the disk portion.
+ */
void imm_draw_disk_partial_fill_2d(uint pos,
float x,
float y,
@@ -66,9 +119,21 @@ void imm_draw_disk_partial_fill_2d(uint pos,
float start,
float sweep);
+/**
+ * Draw a lined box.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param x1: left.
+ * \param y1: bottom.
+ * \param x2: right.
+ * \param y2: top.
+ */
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2);
void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2);
+/**
+ * Draw a standard checkerboard to indicate transparent backgrounds.
+ */
void imm_draw_box_checker_2d_ex(float x1,
float y1,
float x2,
@@ -85,6 +150,18 @@ void imm_draw_cube_corners_3d(uint pos,
const float aspect[3],
const float factor);
+/**
+ * Draw a cylinder. Replacement for #gluCylinder.
+ * \warning Slow, better use it only if you no other choices.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param nor: The vertex attribute number for normal.
+ * \param base: Specifies the radius of the cylinder at z = 0.
+ * \param top: Specifies the radius of the cylinder at z = height.
+ * \param height: Specifies the height of the cylinder.
+ * \param slices: Specifies the number of subdivisions around the z axis.
+ * \param stacks: Specifies the number of subdivisions along the z axis.
+ */
void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks);
void imm_draw_cylinder_wire_3d(
@@ -92,7 +169,7 @@ void imm_draw_cylinder_wire_3d(
void imm_draw_cylinder_fill_3d(
uint pos, float base, float top, float height, int slices, int stacks);
-void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos);
+void imm_drawcircball(const float cent[3], float radius, const float tmat[4][4], uint pos);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index e64521768f9..ea3028e539b 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -54,7 +54,7 @@ typedef struct GPUMaterial GPUMaterial;
typedef struct GPUNode GPUNode;
typedef struct GPUNodeLink GPUNodeLink;
-/* Functions to create GPU Materials nodes */
+/* Functions to create GPU Materials nodes. */
typedef enum eGPUType {
/* Keep in sync with GPU_DATATYPE_STR */
@@ -180,10 +180,17 @@ struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material,
int sample_len,
struct GPUTexture **tex_profile);
-/* High level functions to create and use GPU materials */
+/**
+ * High level functions to create and use GPU materials.
+ */
GPUMaterial *GPU_material_from_nodetree_find(struct ListBase *gpumaterials,
const void *engine_type,
int options);
+/**
+ * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
+ * This is enforced since constructing other arguments to this function may be expensive
+ * so only do this when they are needed.
+ */
GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
@@ -205,10 +212,21 @@ void GPU_materials_free(struct Main *bmain);
struct Scene *GPU_material_scene(GPUMaterial *material);
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
struct GPUShader *GPU_material_get_shader(GPUMaterial *material);
+/**
+ * Return can be NULL if it's a world material.
+ */
struct Material *GPU_material_get_material(GPUMaterial *material);
+/**
+ * Return true if the material compilation has not yet begin or begin.
+ */
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat);
struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material);
+/**
+ * Create dynamic UBO from parameters
+ *
+ * \param inputs: Items are #LinkData, data is #GPUInput (`BLI_genericNodeN(GPUInput)`).
+ */
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void);
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
index edf16f04349..bfd4a14d112 100644
--- a/source/blender/gpu/GPU_matrix.h
+++ b/source/blender/gpu/GPU_matrix.h
@@ -31,7 +31,10 @@ extern "C" {
struct GPUShader;
-void GPU_matrix_reset(void); /* to Identity transform & empty stack */
+/**
+ * To Identity transform & empty stack.
+ */
+void GPU_matrix_reset(void);
/* ModelView Matrix (2D or 3D) */
@@ -52,9 +55,13 @@ void GPU_matrix_translate_3fv(const float vec[3]);
void GPU_matrix_scale_3f(float x, float y, float z);
void GPU_matrix_scale_3fv(const float vec[3]);
-/* Axis of rotation should be a unit vector. */
+/**
+ * Axis of rotation should be a unit vector.
+ */
void GPU_matrix_rotate_3f(float deg, float x, float y, float z);
-/* Axis of rotation should be a unit vector. */
+/**
+ * Axis of rotation should be a unit vector.
+ */
void GPU_matrix_rotate_3fv(float deg, const float axis[3]);
void GPU_matrix_rotate_axis(float deg, char axis); /* TODO: enum for axis? */
@@ -78,12 +85,12 @@ void GPU_matrix_scale_2f(float x, float y);
void GPU_matrix_scale_2fv(const float vec[2]);
void GPU_matrix_rotate_2d(float deg);
-/* Projection Matrix (2D or 3D) */
+/* Projection Matrix (2D or 3D). */
void GPU_matrix_push_projection(void);
void GPU_matrix_pop_projection(void);
-/* 3D Projection Matrix */
+/* 3D Projection Matrix. */
void GPU_matrix_identity_projection_set(void);
void GPU_matrix_projection_set(const float m[4][4]);
@@ -136,11 +143,12 @@ bool GPU_matrix_unproject_3fv(const float win[3],
const int view[4],
float r_world[3]);
-/* 2D Projection Matrix */
+/* 2D Projection Matrix. */
void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top);
-/* functions to get matrix values */
+/* Functions to get matrix values. */
+
const float (*GPU_matrix_model_view_get(float m[4][4]))[4];
const float (*GPU_matrix_projection_get(float m[4][4]))[4];
const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4];
@@ -148,12 +156,19 @@ const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4];
const float (*GPU_matrix_normal_get(float m[3][3]))[3];
const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3];
-/* set uniform values for currently bound shader */
+/**
+ * Set uniform values for currently bound shader.
+ */
void GPU_matrix_bind(struct GPUShader *shader);
bool GPU_matrix_dirty_get(void); /* since last bind */
-/* own working polygon offset */
+/**
+ * Own working polygon offset.
+ */
float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float dist);
+/**
+ * \note \a viewdist is only for orthographic projections at the moment.
+ */
void GPU_polygon_offset(float viewdist, float dist);
/* Python API needs to be able to inspect the stack so errors raise exceptions
diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h
index fa7d5d7fba8..0d80c0ed8af 100644
--- a/source/blender/gpu/GPU_platform.h
+++ b/source/blender/gpu/GPU_platform.h
@@ -66,7 +66,10 @@ typedef enum eGPUSupportLevel {
extern "C" {
#endif
+/* GPU Types */
+
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
+
eGPUSupportLevel GPU_platform_support_level(void);
const char *GPU_platform_vendor(void);
const char *GPU_platform_renderer(void);
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index d28363253b1..c02af763311 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -31,7 +31,7 @@ extern "C" {
struct rcti;
-/* flags for mode of operation */
+/** Flags for mode of operation. */
enum {
GPU_SELECT_ALL = 1,
/* gpu_select_query */
@@ -42,21 +42,48 @@ enum {
GPU_SELECT_PICK_NEAREST = 5,
};
+/**
+ * Initialize and provide buffer for results.
+ */
void GPU_select_begin(
unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits);
+/**
+ * Loads a new selection id and ends previous query, if any.
+ * In second pass of selection it also returns
+ * if id has been hit on the first pass already.
+ * Thus we can skip drawing un-hit objects.
+ *
+ * \warning We rely on the order of object rendering on passes to be the same for this to work.
+ */
bool GPU_select_load_id(unsigned int id);
void GPU_select_finalize(void);
+/**
+ * Cleanup and flush selection results to buffer.
+ * Return number of hits and hits in buffer.
+ * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit.
+ */
unsigned int GPU_select_end(void);
-/* cache selection region */
+/* Cache selection region. */
+
bool GPU_select_is_cached(void);
void GPU_select_cache_begin(void);
void GPU_select_cache_load_id(void);
void GPU_select_cache_end(void);
-/* utilities */
+/* Utilities. */
+
+/**
+ * Helper function, nothing special but avoids doing inline since hits aren't sorted by depth
+ * and purpose of 4x buffer indices isn't so clear.
+ *
+ * Note that comparing depth as uint is fine.
+ */
const uint *GPU_select_buffer_near(const uint *buffer, int hits);
uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id);
+/**
+ * Part of the solution copied from `rect_subregion_stride_calc`.
+ */
void GPU_select_buffer_stride_realign(const struct rcti *src, const struct rcti *dst, uint *r_buf);
#ifdef __cplusplus
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 614af01b17b..5c373551494 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -70,6 +70,26 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
struct GPU_ShaderCreateFromArray_Params {
const char **vert, **geom, **frag, **defs;
};
+/**
+ * Use via #GPU_shader_create_from_arrays macro (avoids passing in param).
+ *
+ * Similar to #DRW_shader_create_with_lib with the ability to include libs for each type of shader.
+ *
+ * It has the advantage that each item can be conditionally included
+ * without having to build the string inline, then free it.
+ *
+ * \param params: NULL terminated arrays of strings.
+ *
+ * Example:
+ * \code{.c}
+ * sh = GPU_shader_create_from_arrays({
+ * .vert = (const char *[]){shader_lib_glsl, shader_vert_glsl, NULL},
+ * .geom = (const char *[]){shader_geom_glsl, NULL},
+ * .frag = (const char *[]){shader_frag_glsl, NULL},
+ * .defs = (const char *[]){"#define DEFINE\n", test ? "#define OTHER_DEFINE\n" : "", NULL},
+ * });
+ * \endcode
+ */
struct GPUShader *GPU_shader_create_from_arrays_impl(
const struct GPU_ShaderCreateFromArray_Params *params, const char *func, int line);
@@ -88,10 +108,13 @@ void GPU_shader_unbind(void);
const char *GPU_shader_get_name(GPUShader *shader);
-/* Returns true if transform feedback was successfully enabled. */
+/**
+ * Returns true if transform feedback was successfully enabled.
+ */
bool GPU_shader_transform_feedback_enable(GPUShader *shader, struct GPUVertBuf *vertbuf);
void GPU_shader_transform_feedback_disable(GPUShader *shader);
+/** DEPRECATED: Kept only because of BGL API. */
int GPU_shader_get_program(GPUShader *shader);
typedef enum {
@@ -134,6 +157,7 @@ void GPU_shader_set_srgb_uniform(GPUShader *shader);
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
+/** DEPRECATED: Kept only because of Python GPU API. */
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
int GPU_shader_get_ssbo(GPUShader *shader, const char *name);
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index 1c1211d2a3e..fa70a8934db 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -48,8 +48,8 @@ ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_SHADER_STORAGE)
* Defines the fixed pipeline blending equation.
* SRC is the output color from the shader.
* DST is the color from the frame-buffer.
- * The blending equation is :
- * (SRC * A) + (DST * B).
+ * The blending equation is:
+ * `(SRC * A) + (DST * B)`.
* The blend mode will modify the A and B parameters.
*/
typedef enum eGPUBlend {
@@ -124,10 +124,23 @@ void GPU_front_facing(bool invert);
void GPU_depth_range(float near, float far);
void GPU_scissor_test(bool enable);
void GPU_line_smooth(bool enable);
+/**
+ * \note By convention, this is set as needed and not reset back to 1.0.
+ * This means code that draws lines must always set the line width beforehand,
+ * but is not expected to restore it's previous value.
+ */
void GPU_line_width(float width);
void GPU_logic_op_xor_set(bool enable);
void GPU_point_size(float size);
void GPU_polygon_smooth(bool enable);
+
+/**
+ * Programmable point size:
+ * - Shaders set their own point size when enabled
+ * - Use GPU_point_size when disabled.
+ *
+ * TODO: remove and use program point size everywhere.
+ */
void GPU_program_point_size(bool enable);
void GPU_scissor(int x, int y, int width, int height);
void GPU_scissor_get(int coords[4]);
@@ -158,6 +171,9 @@ eGPUDepthTest GPU_depth_test_get(void);
eGPUWriteMask GPU_write_mask_get(void);
uint GPU_stencil_mask_get(void);
eGPUStencilTest GPU_stencil_test_get(void);
+/**
+ * \note Already pre-multiplied by `U.pixelsize`.
+ */
float GPU_line_width_get(void);
void GPU_flush(void);
@@ -165,6 +181,10 @@ void GPU_finish(void);
void GPU_apply_state(void);
void GPU_bgl_start(void);
+
+/**
+ * Just turn off the `bgl` safeguard system. Can be called even without #GPU_bgl_start.
+ */
void GPU_bgl_end(void);
bool GPU_bgl_get(void);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index deff9e47871..54e9bde70d8 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -32,7 +32,8 @@ struct GPUVertBuf;
/** Opaque type hiding blender::gpu::Texture. */
typedef struct GPUTexture GPUTexture;
-/* GPU Samplers state
+/**
+ * GPU Samplers state
* - Specify the sampler state to bind a texture with.
* - Internally used by textures.
* - All states are created at startup to avoid runtime costs.
@@ -60,8 +61,9 @@ typedef enum eGPUSamplerState {
} \
} while (0)
-/* `GPU_SAMPLER_MAX` is not a valid enum value, but only a limit.
- * It also creates a bad mask for the `NOT` operator in `ENUM_OPERATORS`.
+/**
+ * #GPU_SAMPLER_MAX is not a valid enum value, but only a limit.
+ * It also creates a bad mask for the `NOT` operator in #ENUM_OPERATORS.
*/
static const int GPU_SAMPLER_MAX = (GPU_SAMPLER_ICON + 1);
ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON)
@@ -70,6 +72,9 @@ ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON)
extern "C" {
#endif
+/**
+ * Update user defined sampler states.
+ */
void GPU_samplers_update(void);
/* GPU Texture
@@ -84,11 +89,13 @@ void GPU_samplers_update(void);
* - if created with from_blender, will not free the texture
*/
-/* Wrapper to supported OpenGL/Vulkan texture internal storage
+/**
+ * Wrapper to supported OpenGL/Vulkan texture internal storage
* If you need a type just un-comment it. Be aware that some formats
* are not supported by render-buffers. All of the following formats
* are part of the OpenGL 3.3 core
- * specification. */
+ * specification.
+ */
typedef enum eGPUTextureFormat {
/* Formats texture & render-buffer. */
GPU_RGBA8UI,
@@ -221,12 +228,19 @@ GPUTexture *GPU_texture_create_cube_array(
const char *name, int w, int d, int mip_len, eGPUTextureFormat format, const float *data);
/* Special textures. */
+
GPUTexture *GPU_texture_create_from_vertbuf(const char *name, struct GPUVertBuf *vert);
/**
* \a data should hold all the data for all mipmaps.
*/
+/**
+ * DDS texture loading. Return NULL if support is not available.
+ */
GPUTexture *GPU_texture_create_compressed_2d(
const char *name, int w, int h, int miplen, eGPUTextureFormat format, const void *data);
+/**
+ * Create an error texture that will bind an invalid texture (pink) at draw time.
+ */
GPUTexture *GPU_texture_create_error(int dimension, bool array);
void GPU_texture_update_mipmap(GPUTexture *tex,
@@ -234,6 +248,9 @@ void GPU_texture_update_mipmap(GPUTexture *tex,
eGPUDataFormat gpu_data_format,
const void *pixels);
+/**
+ * \note Updates only mip 0.
+ */
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
void GPU_texture_update_sub(GPUTexture *tex,
eGPUDataFormat data_format,
@@ -244,9 +261,20 @@ void GPU_texture_update_sub(GPUTexture *tex,
int width,
int height,
int depth);
+/**
+ * Makes data interpretation aware of the source layout.
+ * Skipping pixels correctly when changing rows when doing partial update.
+ */
void GPU_unpack_row_length_set(uint len);
void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl);
+/**
+ * Fills the whole texture with the same data for all pixels.
+ * \warning Only work for 2D texture for now.
+ * \warning Only clears the mip 0 of the texture.
+ * \param data_format: data format of the pixel data.
+ * \param data: 1 pixel worth of data to fill the texture with.
+ */
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
void GPU_texture_free(GPUTexture *tex);
@@ -261,6 +289,9 @@ void GPU_texture_image_bind(GPUTexture *tex, int unit);
void GPU_texture_image_unbind(GPUTexture *tex);
void GPU_texture_image_unbind_all(void);
+/**
+ * Copy a texture content to a similar texture. Only MIP 0 is copied.
+ */
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src);
void GPU_texture_generate_mipmap(GPUTexture *tex);
@@ -292,7 +323,8 @@ int GPU_texture_opengl_bindcode(const GPUTexture *tex);
void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size);
-/* utilities */
+/* Utilities. */
+
size_t GPU_texture_component_len(eGPUTextureFormat format);
size_t GPU_texture_dataformat_size(eGPUDataFormat data_format);
diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h
index 4efac0a8c00..c9ea1582ad4 100644
--- a/source/blender/gpu/GPU_uniform_buffer.h
+++ b/source/blender/gpu/GPU_uniform_buffer.h
@@ -40,6 +40,12 @@ struct ListBase;
typedef struct GPUUniformBuf GPUUniformBuf;
GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name);
+/**
+ * Create UBO from inputs list.
+ * Return NULL if failed to create or if \param inputs: is empty.
+ *
+ * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput).
+ */
GPUUniformBuf *GPU_uniformbuf_create_from_list(struct ListBase *inputs, const char *name);
#define GPU_uniformbuf_create(size) GPU_uniformbuf_create_ex(size, NULL, __func__);
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index 2c54016daa7..62a495abfb3 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -79,10 +79,13 @@ GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *, GPUUsageTyp
*/
const void *GPU_vertbuf_read(GPUVertBuf *verts);
void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data);
+/** Same as discard but does not free. */
void GPU_vertbuf_clear(GPUVertBuf *verts);
void GPU_vertbuf_discard(GPUVertBuf *);
-/* Avoid GPUVertBuf datablock being free but not its data. */
+/**
+ * Avoid GPUVertBuf data-block being free but not its data.
+ */
void GPU_vertbuf_handle_ref_add(GPUVertBuf *verts);
void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts);
@@ -93,25 +96,42 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsa
GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts);
+/**
+ * Create a new allocation, discarding any existing data.
+ */
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len);
+/**
+ * Resize buffer keeping existing data.
+ */
void GPU_vertbuf_data_resize(GPUVertBuf *, uint v_len);
+/**
+ * Set vertex count but does not change allocation.
+ * Only this many verts will be uploaded to the GPU and rendered.
+ * This is useful for streaming data.
+ */
void GPU_vertbuf_data_len_set(GPUVertBuf *, uint v_len);
-/* The most important #set_attr variant is the untyped one. Get it right first.
+/**
+ * The most important #set_attr variant is the untyped one. Get it right first.
* It takes a void* so the app developer is responsible for matching their app data types
* to the vertex attribute's type and component count. They're in control of both, so this
- * should not be a problem. */
-
+ * should not be a problem.
+ */
void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data);
+/** Fills a whole vertex (all attributes). Data must match packed layout. */
void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data);
-/* Tightly packed, non interleaved input data. */
+/**
+ * Tightly packed, non interleaved input data.
+ */
void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data);
void GPU_vertbuf_attr_fill_stride(GPUVertBuf *, uint a_idx, uint stride, const void *data);
-/* For low level access only */
+/**
+ * For low level access only.
+ */
typedef struct GPUVertBufRaw {
uint size;
uint stride;
@@ -138,18 +158,32 @@ GPU_INLINE uint GPU_vertbuf_raw_used(GPUVertBufRaw *a)
void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *, uint a_idx, GPUVertBufRaw *access);
+/**
+ * Returns the data buffer and set it to null internally to avoid freeing.
+ * \note Be careful when using this. The data needs to match the expected format.
+ */
void *GPU_vertbuf_steal_data(GPUVertBuf *verts);
+/**
+ * \note Be careful when using this. The data needs to match the expected format.
+ */
void *GPU_vertbuf_get_data(const GPUVertBuf *verts);
const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts);
GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts);
+/**
+ * Should be rename to #GPU_vertbuf_data_upload.
+ */
void GPU_vertbuf_use(GPUVertBuf *);
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding);
-/* XXX do not use. */
+/**
+ * XXX: do not use!
+ * This is just a wrapper for the use of the Hair refine workaround.
+ * To be used with #GPU_vertbuf_use().
+ */
void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data);
/* Metrics */
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index 0d5388c6b82..4af9901a88c 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -113,8 +113,33 @@ uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
+/**
+ * Makes vertex attribute from the next vertices to be accessible in the vertex shader.
+ * For an attribute named "attr" you can access the next nth vertex using "attr{number}".
+ * Use this function after specifying all the attributes in the format.
+ *
+ * NOTE: This does NOT work when using indexed rendering.
+ * NOTE: Only works for first attribute name. (this limitation can be changed if needed)
+ *
+ * WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute
+ * name short to avoid overflowing the name-buffer.
+ */
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count);
+/**
+ * Make attribute layout non-interleaved.
+ * Warning! This does not change data layout!
+ * Use direct buffer access to fill the data.
+ * This is for advanced usage.
+ *
+ * De-interleaved data means all attribute data for each attribute
+ * is stored continuously like this:
+ * 000011112222
+ * instead of:
+ * 012012012012
+ *
+ * \note This is per attribute de-interleaving, NOT per component.
+ */
void GPU_vertformat_deinterleave(GPUVertFormat *format);
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
@@ -126,10 +151,16 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
return format->names + attr->names[n_idx];
}
-/* WARNING: Can only rename using a string with same character count.
- * WARNING: This removes all other aliases of this attribute. */
+/**
+ * \warning Can only rename using a string with same character count.
+ * \warning This removes all other aliases of this attribute.
+ */
void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr, const char *new_name);
+/**
+ * \warning Always add a prefix to the result of this function as
+ * the generated string can start with a number and not be a valid attribute name.
+ */
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len);
/* format conversion */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index 4d9970dac90..c4948d68298 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -49,12 +49,26 @@ GPUViewport *GPU_viewport_create(void);
GPUViewport *GPU_viewport_stereo_create(void);
void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect);
void GPU_viewport_unbind(GPUViewport *viewport);
+/**
+ * Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
+ * color transform to display space.
+ *
+ * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done
+ * with inversed axis coordinates (upside down or sideways).
+ */
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect);
+/**
+ * Version of #GPU_viewport_draw_to_screen() that lets caller decide if display colorspace
+ * transform should be performed.
+ */
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
int view,
const rcti *rect,
bool display_colorspace,
bool do_overlay_merge);
+/**
+ * Must be executed inside Draw-manager OpenGL Context.
+ */
void GPU_viewport_free(GPUViewport *viewport);
void GPU_viewport_colorspace_set(GPUViewport *viewport,
@@ -62,7 +76,13 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
const ColorManagedDisplaySettings *display_settings,
float dither);
+/**
+ * Should be called from DRW after DRW_opengl_context_enable.
+ */
void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs);
+/**
+ * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
+ */
void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct GPUOffScreen *ofs,
bool display_colorspace,
@@ -70,6 +90,9 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct DRWData **GPU_viewport_data_get(GPUViewport *viewport);
+/**
+ * Merge the stereo textures. `color` and `overlay` texture will be modified.
+ */
void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format);
void GPU_viewport_tag_update(GPUViewport *viewport);
@@ -82,6 +105,9 @@ GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport, int view);
GPUTexture *GPU_viewport_overlay_texture(GPUViewport *viewport, int view);
GPUTexture *GPU_viewport_depth_texture(GPUViewport *viewport);
+/**
+ * Overlay frame-buffer for drawing outside of DRW module.
+ */
GPUFrameBuffer *GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport);
#ifdef __cplusplus
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index 0e5c7900da9..2874dea775f 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -50,7 +50,7 @@ using namespace blender::gpu;
/** \name Creation & Deletion
* \{ */
-GPUBatch *GPU_batch_calloc(void)
+GPUBatch *GPU_batch_calloc()
{
GPUBatch *batch = GPUBackend::get()->batch_alloc();
memset(batch, 0, sizeof(*batch));
@@ -90,7 +90,6 @@ void GPU_batch_init_ex(GPUBatch *batch,
batch->shader = nullptr;
}
-/* This will share the VBOs with the new batch. */
void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src)
{
GPU_batch_init_ex(
@@ -137,7 +136,6 @@ void GPU_batch_discard(GPUBatch *batch)
/** \name Buffers Management
* \{ */
-/* NOTE: Override ONLY the first instance vbo (and free them if owned). */
void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
{
BLI_assert(inst);
@@ -151,7 +149,6 @@ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
SET_FLAG_FROM_TEST(batch->flag, own_vbo, GPU_BATCH_OWNS_INST_VBO);
}
-/* NOTE: Override any previously assigned elem (and free it if owned). */
void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo)
{
BLI_assert(elem);
@@ -188,7 +185,6 @@ int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo)
return -1;
}
-/* Returns the index of verts in the batch. */
int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
{
BLI_assert(verts);
@@ -243,7 +239,6 @@ void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count)
GPU_batch_draw_advanced(batch, v_first, v_count, 0, 0);
}
-/* Draw multiple instance of a batch without having any instance attributes. */
void GPU_batch_draw_instanced(GPUBatch *batch, int i_count)
{
BLI_assert(batch->inst[0] == nullptr);
@@ -301,9 +296,6 @@ void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
GPU_batch_program_set_builtin_with_config(batch, shader_id, GPU_SHADER_CFG_DEFAULT);
}
-/* Bind program bound to IMM to the batch.
- * XXX Use this with much care. Drawing with the GPUBatch API is not compatible with IMM.
- * DO NOT DRAW WITH THE BATCH BEFORE CALLING immUnbindProgram. */
void GPU_batch_program_set_imm_shader(GPUBatch *batch)
{
GPU_batch_set_shader(batch, immGetShader());
@@ -315,12 +307,12 @@ void GPU_batch_program_set_imm_shader(GPUBatch *batch)
/** \name Init/Exit
* \{ */
-void gpu_batch_init(void)
+void gpu_batch_init()
{
gpu_batch_presets_init();
}
-void gpu_batch_exit(void)
+void gpu_batch_exit()
{
gpu_batch_presets_exit();
}
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
index 6a1645a71d8..b97378ad638 100644
--- a/source/blender/gpu/intern/gpu_batch_presets.c
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -154,7 +154,6 @@ GPUBatch *GPU_batch_preset_sphere_wire(int lod)
/** \name Create Sphere (3D)
* \{ */
-/* Replacement for gluSphere */
GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
{
const float lon_inc = 2 * M_PI / lon_res;
@@ -331,7 +330,6 @@ GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
return g_presets_2d.batch.panel_drag_widget;
}
-/* To be used with procedural placement inside shader. */
GPUBatch *GPU_batch_preset_quad(void)
{
if (!g_presets_2d.batch.quad) {
diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c
index e2d03d27035..a381df5974a 100644
--- a/source/blender/gpu/intern/gpu_batch_utils.c
+++ b/source/blender/gpu/intern/gpu_batch_utils.c
@@ -33,15 +33,6 @@
/** \name Polygon Creation (2D)
* \{ */
-/**
- * Creates triangles from a byte-array of polygons.
- *
- * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function.
- *
- * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon).
- * \param polys_flat_len: Length of the array (must be an even number).
- * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1.
- */
GPUBatch *GPU_batch_tris_from_poly_2d_encoded(const uchar *polys_flat,
uint polys_flat_len,
const rctf *rect)
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 43483916236..bd24616820a 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -57,6 +57,10 @@
/* XXX: the rest of the code in this file is used for optimized PBVH
* drawing and doesn't interact at all with the buffer code above */
+/* -------------------------------------------------------------------- */
+/** \name Private Types
+ * \{ */
+
struct GPU_PBVH_Buffers {
GPUIndexBuf *index_buf, *index_buf_fast;
GPUIndexBuf *index_lines_buf, *index_lines_buf_fast;
@@ -204,7 +208,6 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE);
}
-/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
const float *vmask,
@@ -337,7 +340,6 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->mvert = mvert;
}
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
const MLoop *mloop,
const MLoopTri *looptri,
@@ -584,7 +586,6 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
}
}
-/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
SubdivCCG *subdiv_ccg,
CCGElem **grids,
@@ -764,7 +765,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->show_overlay = !empty_mask || !default_face_set;
}
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden)
{
GPU_PBVH_Buffers *buffers;
@@ -878,9 +878,6 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
}
}
-/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
- * shading, an element index buffer.
- * Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
@@ -1048,7 +1045,6 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/** \name Generic
* \{ */
-/* Threaded - do not call any functions that use OpenGL calls! */
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index c6e9dc210cb..f12fd96d1ba 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -44,7 +44,7 @@ using namespace blender::gpu;
/** \name Capabilities
* \{ */
-int GPU_max_texture_size(void)
+int GPU_max_texture_size()
{
return GCaps.max_texture_size;
}
@@ -57,27 +57,27 @@ int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size)
return min_ii(reslimit, res);
}
-int GPU_max_texture_layers(void)
+int GPU_max_texture_layers()
{
return GCaps.max_texture_layers;
}
-int GPU_max_textures_vert(void)
+int GPU_max_textures_vert()
{
return GCaps.max_textures_vert;
}
-int GPU_max_textures_geom(void)
+int GPU_max_textures_geom()
{
return GCaps.max_textures_geom;
}
-int GPU_max_textures_frag(void)
+int GPU_max_textures_frag()
{
return GCaps.max_textures_frag;
}
-int GPU_max_textures(void)
+int GPU_max_textures()
{
return GCaps.max_textures;
}
@@ -92,37 +92,37 @@ int GPU_max_work_group_size(int index)
return GCaps.max_work_group_size[index];
}
-int GPU_max_uniforms_vert(void)
+int GPU_max_uniforms_vert()
{
return GCaps.max_uniforms_vert;
}
-int GPU_max_uniforms_frag(void)
+int GPU_max_uniforms_frag()
{
return GCaps.max_uniforms_frag;
}
-int GPU_max_batch_indices(void)
+int GPU_max_batch_indices()
{
return GCaps.max_batch_indices;
}
-int GPU_max_batch_vertices(void)
+int GPU_max_batch_vertices()
{
return GCaps.max_batch_vertices;
}
-int GPU_max_vertex_attribs(void)
+int GPU_max_vertex_attribs()
{
return GCaps.max_vertex_attribs;
}
-int GPU_max_varying_floats(void)
+int GPU_max_varying_floats()
{
return GCaps.max_varying_floats;
}
-int GPU_extensions_len(void)
+int GPU_extensions_len()
{
return GCaps.extensions_len;
}
@@ -132,43 +132,43 @@ const char *GPU_extension_get(int i)
return GCaps.extension_get ? GCaps.extension_get(i) : "\0";
}
-bool GPU_mip_render_workaround(void)
+bool GPU_mip_render_workaround()
{
return GCaps.mip_render_workaround;
}
-bool GPU_depth_blitting_workaround(void)
+bool GPU_depth_blitting_workaround()
{
return GCaps.depth_blitting_workaround;
}
-bool GPU_use_main_context_workaround(void)
+bool GPU_use_main_context_workaround()
{
return GCaps.use_main_context_workaround;
}
-bool GPU_crappy_amd_driver(void)
+bool GPU_crappy_amd_driver()
{
/* Currently are the same drivers with the `unused_fb_slot` problem. */
return GCaps.broken_amd_driver;
}
-bool GPU_use_hq_normals_workaround(void)
+bool GPU_use_hq_normals_workaround()
{
return GCaps.use_hq_normals_workaround;
}
-bool GPU_compute_shader_support(void)
+bool GPU_compute_shader_support()
{
return GCaps.compute_shader_support;
}
-bool GPU_shader_storage_buffer_objects_support(void)
+bool GPU_shader_storage_buffer_objects_support()
{
return GCaps.shader_storage_buffer_objects_support;
}
-bool GPU_shader_image_load_store_support(void)
+bool GPU_shader_image_load_store_support()
{
return GCaps.shader_image_load_store_support;
}
@@ -179,7 +179,7 @@ bool GPU_shader_image_load_store_support(void)
/** \name Memory statistics
* \{ */
-bool GPU_mem_stats_supported(void)
+bool GPU_mem_stats_supported()
{
return GCaps.mem_stats_support;
}
@@ -189,8 +189,7 @@ void GPU_mem_stats_get(int *totalmem, int *freemem)
Context::get()->memory_statistics_get(totalmem, freemem);
}
-/* Return support for the active context + window. */
-bool GPU_stereo_quadbuffer_support(void)
+bool GPU_stereo_quadbuffer_support()
{
return Context::get()->front_right != nullptr;
}
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 943a6151ced..5af15d1bc3d 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -109,7 +109,6 @@ GPUContext *GPU_context_create(void *ghost_window)
return wrap(ctx);
}
-/* to be called after GPU_context_active_set(ctx_to_destroy) */
void GPU_context_discard(GPUContext *ctx_)
{
Context *ctx = unwrap(ctx_);
@@ -117,7 +116,6 @@ void GPU_context_discard(GPUContext *ctx_)
active_ctx = nullptr;
}
-/* ctx can be NULL */
void GPU_context_active_set(GPUContext *ctx_)
{
Context *ctx = unwrap(ctx_);
@@ -133,7 +131,7 @@ void GPU_context_active_set(GPUContext *ctx_)
}
}
-GPUContext *GPU_context_active_get(void)
+GPUContext *GPU_context_active_get()
{
return wrap(Context::get());
}
@@ -146,12 +144,12 @@ GPUContext *GPU_context_active_get(void)
static std::mutex main_context_mutex;
-void GPU_context_main_lock(void)
+void GPU_context_main_lock()
{
main_context_mutex.lock();
}
-void GPU_context_main_unlock(void)
+void GPU_context_main_unlock()
{
main_context_mutex.unlock();
}
@@ -180,7 +178,7 @@ void GPU_backend_init(eGPUBackendType backend_type)
}
}
-void GPU_backend_exit(void)
+void GPU_backend_exit()
{
/* TODO: assert no resource left. Currently UI textures are still not freed in their context
* correctly. */
diff --git a/source/blender/gpu/intern/gpu_debug.cc b/source/blender/gpu/intern/gpu_debug.cc
index 2d9fb7822ae..85cec67d2a7 100644
--- a/source/blender/gpu/intern/gpu_debug.cc
+++ b/source/blender/gpu/intern/gpu_debug.cc
@@ -45,7 +45,7 @@ void GPU_debug_group_begin(const char *name)
ctx->debug_group_begin(name, stack.size());
}
-void GPU_debug_group_end(void)
+void GPU_debug_group_end()
{
if (!(G.debug & G_DEBUG_GPU)) {
return;
@@ -55,10 +55,6 @@ void GPU_debug_group_end(void)
ctx->debug_group_end();
}
-/**
- * Return a formatted string showing the current group hierarchy in this format:
- * "Group1 > Group 2 > Group3 > ... > GroupN : "
- */
void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
{
Context *ctx = Context::get();
@@ -77,7 +73,6 @@ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf)
r_name_buf[sz - 3] = '\0';
}
-/* Return true if inside a debug group with the same name. */
bool GPU_debug_group_match(const char *ref)
{
/* Otherwise there will be no names. */
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 9099a6e4245..3404eb67e28 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -216,18 +216,12 @@ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
unwrap(gpu_fb)->bind(enable_srgb);
}
-/**
- * Workaround for binding a SRGB frame-buffer without doing the SRGB transform.
- */
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
{
const bool enable_srgb = false;
unwrap(gpu_fb)->bind(enable_srgb);
}
-/**
- * For stereo rendering.
- */
void GPU_backbuffer_bind(eGPUBackBuffer buffer)
{
Context *ctx = Context::get();
@@ -240,19 +234,18 @@ void GPU_backbuffer_bind(eGPUBackBuffer buffer)
}
}
-void GPU_framebuffer_restore(void)
+void GPU_framebuffer_restore()
{
Context::get()->back_left->bind(false);
}
-GPUFrameBuffer *GPU_framebuffer_active_get(void)
+GPUFrameBuffer *GPU_framebuffer_active_get()
{
Context *ctx = Context::get();
return wrap(ctx ? ctx->active_fb : nullptr);
}
-/* Returns the default frame-buffer. Will always exists even if it's just a dummy. */
-GPUFrameBuffer *GPU_framebuffer_back_get(void)
+GPUFrameBuffer *GPU_framebuffer_back_get()
{
Context *ctx = Context::get();
return wrap(ctx ? ctx->back_left : nullptr);
@@ -302,12 +295,6 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
unwrap(tex)->detach_from(unwrap(fb));
}
-/**
- * First GPUAttachment in *config is always the depth/depth_stencil buffer.
- * Following GPUAttachments are color buffers.
- * Setting GPUAttachment.mip to -1 will leave the texture in this slot.
- * Setting GPUAttachment.tex to NULL will detach the texture in this slot.
- */
void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
const GPUAttachment *config,
int config_len)
@@ -341,11 +328,6 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
/* ---------- Viewport & Scissor Region ----------- */
-/**
- * Viewport and scissor size is stored per frame-buffer.
- * It is only reset to its original dimensions explicitly OR when binding the frame-buffer after
- * modifying its attachments.
- */
void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int width, int height)
{
int viewport_rect[4] = {x, y, width, height};
@@ -357,9 +339,6 @@ void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4])
unwrap(gpu_fb)->viewport_get(r_viewport);
}
-/**
- * Reset to its attachment(s) size.
- */
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *gpu_fb)
{
unwrap(gpu_fb)->viewport_reset();
@@ -376,9 +355,6 @@ void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
unwrap(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil);
}
-/**
- * Clear all textures attached to this frame-buffer with a different color.
- */
void GPU_framebuffer_multi_clear(GPUFrameBuffer *gpu_fb, const float (*clear_cols)[4])
{
unwrap(gpu_fb)->clear_multi(clear_cols);
@@ -425,7 +401,6 @@ void GPU_frontbuffer_read_pixels(
Context::get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
}
-/* read_slot and write_slot are only used for color buffers. */
/* TODO(fclem): port as texture operation. */
void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
int read_slot,
@@ -466,11 +441,6 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
prev_fb->bind(true);
}
-/**
- * Use this if you need to custom down-sample your texture and use the previous mip-level as
- * input. This function only takes care of the correct texture handling. It execute the callback
- * for each texture level.
- */
void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb,
int max_lvl,
void (*callback)(void *userData, int level),
@@ -514,14 +484,14 @@ void GPU_framebuffer_push(GPUFrameBuffer *fb)
FrameBufferStack.top++;
}
-GPUFrameBuffer *GPU_framebuffer_pop(void)
+GPUFrameBuffer *GPU_framebuffer_pop()
{
BLI_assert(FrameBufferStack.top > 0);
FrameBufferStack.top--;
return FrameBufferStack.framebuffers[FrameBufferStack.top];
}
-uint GPU_framebuffer_stack_level_get(void)
+uint GPU_framebuffer_stack_level_get()
{
return FrameBufferStack.top;
}
@@ -704,9 +674,6 @@ GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs)
return ofs->color;
}
-/**
- * \note only to be used by viewport code!
- */
void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUFrameBuffer **r_fb,
GPUTexture **r_color,
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index cdd56a117db..7ca93252683 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -89,7 +89,6 @@ void immUnbindProgram()
imm->shader = nullptr;
}
-/* XXX do not use it. Special hack to use OCIO with batch API. */
GPUShader *immGetShader()
{
return imm->shader;
@@ -603,7 +602,6 @@ void immUniform4fv(const char *name, const float data[4])
GPU_shader_uniform_4fv(imm->shader, name, data);
}
-/* Note array index is not supported for name (i.e: "array[0]"). */
void immUniformArray4fv(const char *name, const float *data, int count)
{
GPU_shader_uniform_4fv_array(imm->shader, name, count, (const float(*)[4])data);
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index df18b89bd67..37a423d41a0 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -143,17 +143,6 @@ void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4])
}
#endif
-/**
- * Pack color into 3 bytes
- *
- * This define converts a numerical value to the equivalent 24-bit
- * color, while not being endian-sensitive. On little-endian, this
- * is the same as doing a 'naive' indexing, on big-endian, it is not!
- *
- * \note BGR format (i.e. 0xBBGGRR)...
- *
- * \param x: color.
- */
void imm_cpack(uint x)
{
immUniformColor3ub(((x)&0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF));
@@ -163,64 +152,44 @@ static void imm_draw_circle(GPUPrimType prim_type,
const uint shdr_pos,
float x,
float y,
- float rad_x,
- float rad_y,
+ float radius_x,
+ float radius_y,
int nsegments)
{
immBegin(prim_type, nsegments);
for (int i = 0; i < nsegments; i++) {
const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle)));
+ immVertex2f(shdr_pos, x + (radius_x * cosf(angle)), y + (radius_y * sinf(angle)));
}
immEnd();
}
-/**
- * Draw a circle outline with the given \a radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \param shdr_pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad: The circle's radius.
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- */
-void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad, rad, nsegments);
+ imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, radius, radius, nsegments);
}
-/**
- * Draw a filled circle with the given \a radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \param shdr_pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad: The circle's radius.
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- */
-void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad, rad, nsegments);
+ imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, radius, radius, nsegments);
}
void imm_draw_circle_wire_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments)
{
- imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad_x, rad_y, nsegments);
+ imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, radius_x, radius_y, nsegments);
}
void imm_draw_circle_fill_aspect_2d(
- uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+ uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments)
{
- imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad_x, rad_y, nsegments);
+ imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, radius_x, radius_y, nsegments);
}
static void imm_draw_circle_partial(GPUPrimType prim_type,
uint pos,
float x,
float y,
- float rad,
+ float radius,
int nsegments,
float start,
float sweep)
@@ -234,15 +203,15 @@ static void imm_draw_circle_partial(GPUPrimType prim_type,
const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
const float angle_sin = sinf(angle);
const float angle_cos = cosf(angle);
- immVertex2f(pos, x + rad * angle_cos, y + rad * angle_sin);
+ immVertex2f(pos, x + radius * angle_cos, y + radius * angle_sin);
}
immEnd();
}
void imm_draw_circle_partial_wire_2d(
- uint pos, float x, float y, float rad, int nsegments, float start, float sweep)
+ uint pos, float x, float y, float radius, int nsegments, float start, float sweep)
{
- imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, rad, nsegments, start, sweep);
+ imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, radius, nsegments, start, sweep);
}
static void imm_draw_disk_partial(GPUPrimType prim_type,
@@ -274,21 +243,6 @@ static void imm_draw_disk_partial(GPUPrimType prim_type,
immEnd();
}
-/**
- * Draw a filled arc with the given inner and outer radius.
- * The circle is centered at \a x, \a y and drawn in the XY plane.
- *
- * \note Arguments are `gluPartialDisk` compatible.
- *
- * \param pos: The vertex attribute number for position.
- * \param x: Horizontal center.
- * \param y: Vertical center.
- * \param rad_inner: The inner circle's radius.
- * \param rad_outer: The outer circle's radius (can be zero).
- * \param nsegments: The number of segments to use in drawing (more = smoother).
- * \param start: Specifies the starting angle, in degrees, of the disk portion.
- * \param sweep: Specifies the sweep angle, in degrees, of the disk portion.
- */
void imm_draw_disk_partial_fill_2d(uint pos,
float x,
float y,
@@ -303,40 +257,31 @@ void imm_draw_disk_partial_fill_2d(uint pos,
}
static void imm_draw_circle_3D(
- GPUPrimType prim_type, uint pos, float x, float y, float rad, int nsegments)
+ GPUPrimType prim_type, uint pos, float x, float y, float radius, int nsegments)
{
immBegin(prim_type, nsegments);
for (int i = 0; i < nsegments; i++) {
float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f);
+ immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
}
immEnd();
}
-void imm_draw_circle_wire_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, rad, nsegments);
+ imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, radius, nsegments);
}
-void imm_draw_circle_dashed_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_dashed_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, rad, nsegments / 2);
+ imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, radius, nsegments / 2);
}
-void imm_draw_circle_fill_3d(uint pos, float x, float y, float rad, int nsegments)
+void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments)
{
- imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, rad, nsegments);
+ imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, radius, nsegments);
}
-/**
- * Draw a lined box.
- *
- * \param pos: The vertex attribute number for position.
- * \param x1: left.
- * \param y1: bottom.
- * \param x2: right.
- * \param y2: top.
- */
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
{
immBegin(GPU_PRIM_LINE_LOOP, 4);
@@ -358,9 +303,6 @@ void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
immEnd();
}
-/**
- * Draw a standard checkerboard to indicate transparent backgrounds.
- */
void imm_draw_box_checker_2d_ex(float x1,
float y1,
float x2,
@@ -458,18 +400,6 @@ void imm_draw_cube_corners_3d(uint pos,
immEnd();
}
-/**
- * Draw a cylinder. Replacement for gluCylinder.
- * _warning_ : Slow, better use it only if you no other choices.
- *
- * \param pos: The vertex attribute number for position.
- * \param nor: The vertex attribute number for normal.
- * \param base: Specifies the radius of the cylinder at z = 0.
- * \param top: Specifies the radius of the cylinder at z = height.
- * \param height: Specifies the height of the cylinder.
- * \param slices: Specifies the number of subdivisions around the z axis.
- * \param stacks: Specifies the number of subdivisions along the z axis.
- */
void imm_draw_cylinder_fill_normal_3d(
uint pos, uint nor, float base, float top, float height, int slices, int stacks)
{
@@ -608,7 +538,7 @@ void imm_draw_cylinder_fill_3d(
static void circball_array_fill(const float verts[CIRCLE_RESOL][3],
const float cent[3],
- float rad,
+ const float radius,
const float tmat[4][4])
{
/* 32 values of sin function (still same result!) */
@@ -632,8 +562,8 @@ static void circball_array_fill(const float verts[CIRCLE_RESOL][3],
float vx[3], vy[3];
float *viter = (float *)verts;
- mul_v3_v3fl(vx, tmat[0], rad);
- mul_v3_v3fl(vy, tmat[1], rad);
+ mul_v3_v3fl(vx, tmat[0], radius);
+ mul_v3_v3fl(vy, tmat[1], radius);
for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
@@ -642,11 +572,11 @@ static void circball_array_fill(const float verts[CIRCLE_RESOL][3],
}
}
-void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos)
+void imm_drawcircball(const float cent[3], float radius, const float tmat[4][4], uint pos)
{
float verts[CIRCLE_RESOL][3];
- circball_array_fill(verts, cent, rad, tmat);
+ circball_array_fill(verts, cent, radius, tmat);
immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL);
for (int i = 0; i < CIRCLE_RESOL; i++) {
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index be7470e79c1..3472cc24a74 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -349,7 +349,7 @@ uint32_t *IndexBuf::unmap(const uint32_t *mapped_memory) const
/** \name C-API
* \{ */
-GPUIndexBuf *GPU_indexbuf_calloc(void)
+GPUIndexBuf *GPU_indexbuf_calloc()
{
return wrap(GPUBackend::get()->indexbuf_alloc());
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 6872a08e854..3804f2f0dd1 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -115,7 +115,6 @@ enum {
/* Functions */
-/* Returns the address of the future pointer to coba_tex */
GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
int size,
float *pixels,
@@ -212,7 +211,6 @@ GPUShader *GPU_material_get_shader(GPUMaterial *material)
return material->pass ? GPU_pass_shader_get(material->pass) : NULL;
}
-/* Return can be NULL if it's a world material. */
Material *GPU_material_get_material(GPUMaterial *material)
{
return material->ma;
@@ -223,11 +221,6 @@ GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material)
return material->ubo;
}
-/**
- * Create dynamic UBO from parameters
- *
- * \param inputs: Items are #LinkData, data is #GPUInput (`BLI_genericNodeN(GPUInput)`).
- */
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
{
#ifndef NDEBUG
@@ -545,7 +538,6 @@ GSet *gpu_material_used_libraries(GPUMaterial *material)
return material->used_libraries;
}
-/* Return true if the material compilation has not yet begin or begin. */
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
{
return mat->status;
@@ -592,11 +584,6 @@ GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials,
return NULL;
}
-/**
- * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
- * This is enforced since constructing other arguments to this function may be expensive
- * so only do this when they are needed.
- */
GPUMaterial *GPU_material_from_nodetree(Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc
index bbcc241f5e3..cf3f7f5e778 100644
--- a/source/blender/gpu/intern/gpu_matrix.cc
+++ b/source/blender/gpu/intern/gpu_matrix.cc
@@ -67,7 +67,7 @@ struct GPUMatrixState {
#define ProjectionStack Context::get()->matrix_state->projection_stack
#define Projection ProjectionStack.stack[ProjectionStack.top]
-GPUMatrixState *GPU_matrix_state_create(void)
+GPUMatrixState *GPU_matrix_state_create()
{
#define MATRIX_4X4_IDENTITY \
{ \
@@ -99,7 +99,7 @@ static void gpu_matrix_state_active_set_dirty(bool value)
state->dirty = value;
}
-void GPU_matrix_reset(void)
+void GPU_matrix_reset()
{
GPUMatrixState *state = Context::get()->matrix_state;
state->model_view_stack.top = 0;
@@ -132,28 +132,28 @@ static void checkmat(cosnt float *m)
#endif
-void GPU_matrix_push(void)
+void GPU_matrix_push()
{
BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH);
ModelViewStack.top++;
copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]);
}
-void GPU_matrix_pop(void)
+void GPU_matrix_pop()
{
BLI_assert(ModelViewStack.top > 0);
ModelViewStack.top--;
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_push_projection(void)
+void GPU_matrix_push_projection()
{
BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH);
ProjectionStack.top++;
copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]);
}
-void GPU_matrix_pop_projection(void)
+void GPU_matrix_pop_projection()
{
BLI_assert(ProjectionStack.top > 0);
ProjectionStack.top--;
@@ -167,7 +167,7 @@ void GPU_matrix_set(const float m[4][4])
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_identity_projection_set(void)
+void GPU_matrix_identity_projection_set()
{
unit_m4(Projection);
CHECKMAT(Projection3D);
@@ -181,7 +181,7 @@ void GPU_matrix_projection_set(const float m[4][4])
gpu_matrix_state_active_set_dirty(true);
}
-void GPU_matrix_identity_set(void)
+void GPU_matrix_identity_set()
{
unit_m4(ModelView);
gpu_matrix_state_active_set_dirty(true);
@@ -668,7 +668,7 @@ void GPU_matrix_bind(GPUShader *shader)
gpu_matrix_state_active_set_dirty(false);
}
-bool GPU_matrix_dirty_get(void)
+bool GPU_matrix_dirty_get()
{
GPUMatrixState *state = Context::get()->matrix_state;
return state->dirty;
@@ -677,17 +677,18 @@ bool GPU_matrix_dirty_get(void)
/* -------------------------------------------------------------------- */
/** \name Python API Helpers
* \{ */
+
BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch");
/* Return int since caller is may subtract. */
-int GPU_matrix_stack_level_get_model_view(void)
+int GPU_matrix_stack_level_get_model_view()
{
GPUMatrixState *state = Context::get()->matrix_state;
return (int)state->model_view_stack.top;
}
-int GPU_matrix_stack_level_get_projection(void)
+int GPU_matrix_stack_level_get_projection()
{
GPUMatrixState *state = Context::get()->matrix_state;
return (int)state->projection_stack.top;
@@ -733,9 +734,6 @@ float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float di
return winmat[3][2] * -0.0025f * dist;
}
-/**
- * \note \a viewdist is only for ortho at the moment.
- */
void GPU_polygon_offset(float viewdist, float dist)
{
static float winmat[4][4], offset = 0.0f;
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 585cb296bac..50ff450ac79 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -791,7 +791,6 @@ static void gpu_node_free(GPUNode *node)
MEM_freeN(node);
}
-/* Free intermediate node graph. */
void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
{
GPUNode *node;
@@ -803,7 +802,6 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
graph->outlink = NULL;
}
-/* Free both node graph and requested attributes and textures. */
void gpu_node_graph_free(GPUNodeGraph *graph)
{
BLI_freelistN(&graph->outlink_aovs);
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 929191cff73..8a112ac9c4d 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -167,12 +167,21 @@ typedef struct GPUNodeGraph {
void gpu_node_graph_prune_unused(GPUNodeGraph *graph);
void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph);
+/**
+ * Free intermediate node graph.
+ */
void gpu_node_graph_free_nodes(GPUNodeGraph *graph);
+/**
+ * Free both node graph and requested attributes and textures.
+ */
void gpu_node_graph_free(GPUNodeGraph *graph);
/* Material calls */
struct GPUNodeGraph *gpu_material_node_graph(struct GPUMaterial *material);
+/**
+ * Returns the address of the future pointer to coba_tex.
+ */
struct GPUTexture **gpu_material_ramp_texture_row_set(struct GPUMaterial *mat,
int size,
float *pixels,
diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc
index 49dde473300..34834a62268 100644
--- a/source/blender/gpu/intern/gpu_platform.cc
+++ b/source/blender/gpu/intern/gpu_platform.cc
@@ -127,37 +127,36 @@ eGPUSupportLevel GPU_platform_support_level()
return GPG.support_level;
}
-const char *GPU_platform_vendor(void)
+const char *GPU_platform_vendor()
{
BLI_assert(GPG.initialized);
return GPG.vendor;
}
-const char *GPU_platform_renderer(void)
+const char *GPU_platform_renderer()
{
BLI_assert(GPG.initialized);
return GPG.renderer;
}
-const char *GPU_platform_version(void)
+const char *GPU_platform_version()
{
BLI_assert(GPG.initialized);
return GPG.version;
}
-const char *GPU_platform_support_level_key(void)
+const char *GPU_platform_support_level_key()
{
BLI_assert(GPG.initialized);
return GPG.support_key;
}
-const char *GPU_platform_gpu_name(void)
+const char *GPU_platform_gpu_name()
{
BLI_assert(GPG.initialized);
return GPG.gpu_name;
}
-/* GPU Types */
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
{
BLI_assert(GPG.initialized);
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 3c89f082e9b..aadb52fb49c 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -71,9 +71,6 @@ static GPUSelectState g_select_state = {0};
/** \name Public API
* \{ */
-/**
- * initialize and provide buffer for results
- */
void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits)
{
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
@@ -107,14 +104,6 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode,
}
}
-/**
- * loads a new selection id and ends previous query, if any.
- * In second pass of selection it also returns
- * if id has been hit on the first pass already.
- * Thus we can skip drawing un-hit objects.
- *
- * \warning We rely on the order of object rendering on passes to be the same for this to work.
- */
bool GPU_select_load_id(uint id)
{
/* if no selection mode active, ignore */
@@ -133,11 +122,6 @@ bool GPU_select_load_id(uint id)
}
}
-/**
- * Cleanup and flush selection results to buffer.
- * Return number of hits and hits in buffer.
- * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit.
- */
uint GPU_select_end(void)
{
uint hits = 0;
@@ -205,12 +189,6 @@ bool GPU_select_is_cached(void)
/** \name Utilities
* \{ */
-/**
- * Helper function, nothing special but avoids doing inline since hits aren't sorted by depth
- * and purpose of 4x buffer indices isn't so clear.
- *
- * Note that comparing depth as uint is fine.
- */
const uint *GPU_select_buffer_near(const uint *buffer, int hits)
{
const uint *buffer_near = NULL;
@@ -244,7 +222,6 @@ uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id)
return hits_final;
}
-/* Part of the solution copied from `rect_subregion_stride_calc`. */
void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_buf)
{
const int x = dst->xmin - src->xmin;
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index a8907859bf4..737e4c6e874 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -730,7 +730,6 @@ void gpu_select_pick_cache_end(void)
BLI_freelistN(&g_pick_state.cache.bufs);
}
-/* is drawing needed? */
bool gpu_select_pick_is_cached(void)
{
return g_pick_state.is_cached;
diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h
index e49feb3fc50..e5a84a037a6 100644
--- a/source/blender/gpu/intern/gpu_select_private.h
+++ b/source/blender/gpu/intern/gpu_select_private.h
@@ -30,16 +30,21 @@ extern "C" {
#endif
/* gpu_select_pick */
+
void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode);
bool gpu_select_pick_load_id(uint id, bool end);
uint gpu_select_pick_end(void);
void gpu_select_pick_cache_begin(void);
void gpu_select_pick_cache_end(void);
+/**
+ * \return true if drawing is not needed.
+ */
bool gpu_select_pick_is_cached(void);
void gpu_select_pick_cache_load_id(void);
/* gpu_select_sample_query */
+
void gpu_select_query_begin(
uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits);
bool gpu_select_query_load_id(uint id);
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc
index 047ce0cfb35..a430d4a9d62 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.cc
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -151,7 +151,7 @@ bool gpu_select_query_load_id(uint id)
return true;
}
-uint gpu_select_query_end(void)
+uint gpu_select_query_end()
{
uint hits = 0;
const uint maxhits = g_query_state.bufsize;
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index 9340d311472..1b6cb196534 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -284,26 +284,6 @@ static const char *string_join_array_maybe_alloc(const char **str_arr, bool *r_i
return str_arr[0];
}
-/**
- * Use via #GPU_shader_create_from_arrays macro (avoids passing in param).
- *
- * Similar to #DRW_shader_create_with_lib with the ability to include libs for each type of shader.
- *
- * It has the advantage that each item can be conditionally included
- * without having to build the string inline, then free it.
- *
- * \param params: NULL terminated arrays of strings.
- *
- * Example:
- * \code{.c}
- * sh = GPU_shader_create_from_arrays({
- * .vert = (const char *[]){shader_lib_glsl, shader_vert_glsl, NULL},
- * .geom = (const char *[]){shader_geom_glsl, NULL},
- * .frag = (const char *[]){shader_frag_glsl, NULL},
- * .defs = (const char *[]){"#define DEFINE\n", test ? "#define OTHER_DEFINE\n" : "", NULL},
- * });
- * \endcode
- */
struct GPUShader *GPU_shader_create_from_arrays_impl(
const struct GPU_ShaderCreateFromArray_Params *params, const char *func, int line)
{
@@ -431,7 +411,6 @@ int GPU_shader_get_ssbo(GPUShader *shader, const char *name)
return ssbo ? ssbo->location : -1;
}
-/* DEPRECATED. */
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
{
ShaderInterface *interface = unwrap(shader)->interface;
@@ -466,7 +445,6 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name)
/** \name Getters
* \{ */
-/* DEPRECATED: Kept only because of BGL API */
int GPU_shader_get_program(GPUShader *shader)
{
return unwrap(shader)->program_handle_get();
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index ae94112b17b..937f49ccaec 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -65,14 +65,17 @@ static void sort_input_list(MutableSpan<ShaderInput> dst)
}
}
-/* Sorts all inputs inside their respective array.
- * This is to allow fast hash collision detection.
- * See ShaderInterface::input_lookup for more details. */
void ShaderInterface::sort_inputs()
{
+ /* Sorts all inputs inside their respective array.
+ * This is to allow fast hash collision detection.
+ * See `ShaderInterface::input_lookup` for more details. */
+
sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_));
+ sort_input_list(
+ MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_));
}
void ShaderInterface::debug_print()
diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh
index ebed7b15170..12a7ffabcc6 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.hh
+++ b/source/blender/gpu/intern/gpu_shader_interface.hh
@@ -130,7 +130,9 @@ class ShaderInterface {
inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const;
- /* Finalize interface construction by sorting the ShaderInputs for faster lookups. */
+ /**
+ * Finalize interface construction by sorting the #ShaderInputs for faster lookups.
+ */
void sort_inputs(void);
private:
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index 9ee8a8b8d32..a43ddb09ff8 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -165,11 +165,6 @@ void GPU_depth_range(float near, float far)
copy_v2_fl2(state.depth_range, near, far);
}
-/**
- * \note By convention, this is set as needed and not reset back to 1.0.
- * This means code that draws lines must always set the line width beforehand,
- * but is not expected to restore it's previous value.
- */
void GPU_line_width(float width)
{
width = max_ff(1.0f, width * PIXELSIZE);
@@ -184,10 +179,6 @@ void GPU_point_size(float size)
state.point_size = size * ((state.point_size > 0.0) ? 1.0f : -1.0f);
}
-/* Programmable point size
- * - shaders set their own point size when enabled
- * - use GPU_point_size when disabled */
-/* TODO: remove and use program point size everywhere. */
void GPU_program_point_size(bool enable)
{
StateManager *stack = Context::get()->state_manager;
@@ -264,7 +255,6 @@ eGPUStencilTest GPU_stencil_test_get()
return (eGPUStencilTest)state.stencil_test;
}
-/* NOTE: Already premultiplied by U.pixelsize. */
float GPU_line_width_get()
{
const GPUStateMutable &state = Context::get()->state_manager->mutable_state;
@@ -363,7 +353,6 @@ void GPU_bgl_start()
}
}
-/* Just turn off the bgl safeguard system. Can be called even without GPU_bgl_start. */
void GPU_bgl_end()
{
Context *ctx = Context::get();
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index 2744c0c5e17..c7e2043b790 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -298,7 +298,6 @@ GPUTexture *GPU_texture_create_cube_array(
name, w, w, d, GPU_TEXTURE_CUBE_ARRAY, mip_len, format, GPU_DATA_FLOAT, data);
}
-/* DDS texture loading. Return NULL if support is not available. */
GPUTexture *GPU_texture_create_compressed_2d(
const char *name, int w, int h, int miplen, eGPUTextureFormat tex_format, const void *data)
{
@@ -337,7 +336,6 @@ GPUTexture *GPU_texture_create_from_vertbuf(const char *name, GPUVertBuf *vert)
return reinterpret_cast<GPUTexture *>(tex);
}
-/* Create an error texture that will bind an invalid texture (pink) at draw time. */
GPUTexture *GPU_texture_create_error(int dimension, bool is_array)
{
float pixel[4] = {1.0f, 0.0f, 1.0f, 1.0f};
@@ -386,27 +384,17 @@ void *GPU_texture_read(GPUTexture *tex_, eGPUDataFormat data_format, int miplvl)
return tex->read(miplvl, data_format);
}
-/**
- * Fills the whole texture with the same data for all pixels.
- * \warning Only work for 2D texture for now.
- * \warning Only clears the mip 0 of the texture.
- * \param data_format: data format of the pixel data.
- * \param data: 1 pixel worth of data to fill the texture with.
- */
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
{
BLI_assert(data != nullptr); /* Do not accept NULL as parameter. */
reinterpret_cast<Texture *>(tex)->clear(data_format, data);
}
-/* NOTE: Updates only mip 0. */
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
{
reinterpret_cast<Texture *>(tex)->update(data_format, data);
}
-/* Makes data interpretation aware of the source layout.
- * Skipping pixels correctly when changing rows when doing partial update. */
void GPU_unpack_row_length_set(uint len)
{
Context::get()->state_manager->texture_unpack_row_length_set(len);
@@ -461,7 +449,6 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
reinterpret_cast<Texture *>(tex)->generate_mipmap();
}
-/* Copy a texture content to a similar texture. Only MIP 0 is copied. */
void GPU_texture_copy(GPUTexture *dst_, GPUTexture *src_)
{
Texture *src = reinterpret_cast<Texture *>(src_);
@@ -626,7 +613,6 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size)
* Override texture sampler state for one sampler unit only.
* \{ */
-/* Update user defined sampler states. */
void GPU_samplers_update(void)
{
GPUBackend::get()->samplers_update();
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer.cc b/source/blender/gpu/intern/gpu_uniform_buffer.cc
index 3a9269d1753..332875ba81f 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer.cc
+++ b/source/blender/gpu/intern/gpu_uniform_buffer.cc
@@ -201,12 +201,6 @@ GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const cha
return wrap(ubo);
}
-/**
- * Create UBO from inputs list.
- * Return NULL if failed to create or if \param inputs: is empty.
- *
- * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput).
- */
GPUUniformBuf *GPU_uniformbuf_create_from_list(ListBase *inputs, const char *name)
{
/* There is no point on creating an UBO if there is no arguments. */
@@ -245,7 +239,7 @@ void GPU_uniformbuf_unbind(GPUUniformBuf *ubo)
unwrap(ubo)->unbind();
}
-void GPU_uniformbuf_unbind_all(void)
+void GPU_uniformbuf_unbind_all()
{
/* FIXME */
}
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 7ff68242c17..5ed9648387f 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -159,7 +159,6 @@ void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data)
return unwrap(verts)->unmap(mapped_data);
}
-/** Same as discard but does not free. */
void GPU_vertbuf_clear(GPUVertBuf *verts)
{
unwrap(verts)->clear();
@@ -183,21 +182,16 @@ void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts)
/* -------- Data update -------- */
-/* create a new allocation, discarding any existing data */
void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
{
unwrap(verts)->allocate(v_len);
}
-/* resize buffer keeping existing data */
void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len)
{
unwrap(verts)->resize(v_len);
}
-/* Set vertex count but does not change allocation.
- * Only this many verts will be uploaded to the GPU and rendered.
- * This is useful for streaming data. */
void GPU_vertbuf_data_len_set(GPUVertBuf *verts_, uint v_len)
{
VertBuf *verts = unwrap(verts_);
@@ -229,7 +223,6 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data)
GPU_vertbuf_attr_fill_stride(verts_, a_idx, stride, data);
}
-/** Fills a whole vertex (all attributes). Data must match packed layout. */
void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data)
{
VertBuf *verts = unwrap(verts_);
@@ -284,15 +277,12 @@ void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw
/* -------- Getters -------- */
-/* NOTE: Be careful when using this. The data needs to match the expected format. */
void *GPU_vertbuf_get_data(const GPUVertBuf *verts)
{
/* TODO: Assert that the format has no padding. */
return unwrap(verts)->data;
}
-/* Returns the data buffer and set it to null internally to avoid freeing.
- * NOTE: Be careful when using this. The data needs to match the expected format. */
void *GPU_vertbuf_steal_data(GPUVertBuf *verts_)
{
VertBuf *verts = unwrap(verts_);
@@ -328,7 +318,6 @@ uint GPU_vertbuf_get_memory_usage()
return VertBuf::memory_usage;
}
-/* Should be rename to GPU_vertbuf_data_upload */
void GPU_vertbuf_use(GPUVertBuf *verts)
{
unwrap(verts)->upload();
@@ -339,8 +328,6 @@ void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding)
unwrap(verts)->bind_as_ssbo(binding);
}
-/* XXX this is just a wrapper for the use of the Hair refine workaround.
- * To be used with GPU_vertbuf_use(). */
void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data)
{
unwrap(verts)->update_sub(start, len, data);
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index 78a119bcec8..ad45f2a4d7b 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -190,17 +190,6 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
attr->names[attr->name_len++] = copy_attr_name(format, alias);
}
-/**
- * Makes vertex attribute from the next vertices to be accessible in the vertex shader.
- * For an attribute named "attr" you can access the next nth vertex using "attr{number}".
- * Use this function after specifying all the attributes in the format.
- *
- * NOTE: This does NOT work when using indexed rendering.
- * NOTE: Only works for first attribute name. (this limitation can be changed if needed)
- *
- * WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute
- * name short to avoid overflowing the name-buffer.
- */
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count)
{
/* Sanity check. Maximum can be upgraded if needed. */
@@ -271,8 +260,6 @@ static void safe_bytes(char out[11], const char data[8])
}
}
-/* Warning: Always add a prefix to the result of this function as
- * the generated string can start with a number and not be a valid attribute name. */
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint UNUSED(max_len))
{
char data[8] = {0};
@@ -306,20 +293,6 @@ void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uin
#endif
}
-/**
- * Make attribute layout non-interleaved.
- * Warning! This does not change data layout!
- * Use direct buffer access to fill the data.
- * This is for advanced usage.
- *
- * De-interleaved data means all attribute data for each attribute
- * is stored continuously like this:
- * 000011112222
- * instead of:
- * 012012012012
- *
- * \note This is per attribute de-interleaving, NOT per component.
- */
void GPU_vertformat_deinterleave(GPUVertFormat *format)
{
/* Ideally we should change the stride and offset here. This would allow
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index ccd9a4c061b..c604859fa94 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -194,7 +194,6 @@ void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect)
viewport->active_view = view;
}
-/* Should be called from DRW after DRW_opengl_context_enable. */
void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs)
{
GPUTexture *color, *depth;
@@ -258,7 +257,6 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
viewport->do_color_management = true;
}
-/* Merge the stereo textures. `color` and `overlay` texture will be modified. */
void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format)
{
if (!ELEM(stereo_format->display_mode, S3D_DISPLAY_ANAGLYPH, S3D_DISPLAY_INTERLACE)) {
@@ -452,10 +450,6 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
}
}
-/**
- * Version of #GPU_viewport_draw_to_screen() that lets caller decide if display colorspace
- * transform should be performed.
- */
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
int view,
const rcti *rect,
@@ -508,21 +502,11 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
viewport, view, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
}
-/**
- * Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
- * color transform to display space.
- *
- * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done
- * with inversed axis coordinates (upside down or sideways).
- */
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect)
{
GPU_viewport_draw_to_screen_ex(viewport, view, rect, true, true);
}
-/**
- * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
- */
void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
struct GPUOffScreen *ofs,
bool display_colorspace,
@@ -587,18 +571,17 @@ GPUTexture *GPU_viewport_depth_texture(GPUViewport *viewport)
return viewport->depth_tx;
}
-/* Overlay framebuffer for drawing outside of DRW module. */
GPUFrameBuffer *GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport)
{
- GPU_framebuffer_ensure_config(&viewport->overlay_fb,
- {
- GPU_ATTACHMENT_TEXTURE(viewport->depth_tx),
- GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]),
- });
+ GPU_framebuffer_ensure_config(
+ &viewport->overlay_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(viewport->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[viewport->active_view]),
+ });
return viewport->overlay_fb;
}
-/* Must be executed inside Draw-manager OpenGL Context. */
void GPU_viewport_free(GPUViewport *viewport)
{
if (viewport->draw_data) {
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 2855d5078ff..7bb88894b81 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -412,14 +412,23 @@ static void detect_workarounds()
if (GLContext::debug_layer_support == false) {
GLContext::debug_layer_workaround = true;
}
+
+ /* Broken glGenerateMipmap on macOS 10.15.7 security update. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY) &&
+ strstr(renderer, "HD Graphics 4000")) {
+ GLContext::generate_mipmap_workaround = true;
+ }
} // namespace blender::gpu
/** Internal capabilities. */
+
GLint GLContext::max_cubemap_size = 0;
GLint GLContext::max_texture_3d_size = 0;
GLint GLContext::max_ubo_binds = 0;
GLint GLContext::max_ubo_size = 0;
+
/** Extensions. */
+
bool GLContext::base_instance_support = false;
bool GLContext::clear_texture_support = false;
bool GLContext::copy_image_support = false;
@@ -433,9 +442,12 @@ bool GLContext::texture_cube_map_array_support = false;
bool GLContext::texture_filter_anisotropic_support = false;
bool GLContext::texture_gather_support = false;
bool GLContext::vertex_attrib_binding_support = false;
+
/** Workarounds. */
+
bool GLContext::debug_layer_workaround = false;
bool GLContext::unused_fb_slot_workaround = false;
+bool GLContext::generate_mipmap_workaround = false;
float GLContext::derivative_signs[2] = {1.0f, 1.0f};
void GLBackend::capabilities_init()
diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc
index fc1d1006d0d..83cb0ddd053 100644
--- a/source/blender/gpu/opengl/gl_batch.cc
+++ b/source/blender/gpu/opengl/gl_batch.cc
@@ -74,7 +74,6 @@ void GLVaoCache::init()
vao_id_ = 0;
}
-/* Create a new VAO object and store it in the cache. */
void GLVaoCache::insert(const GLShaderInterface *interface, GLuint vao)
{
/* Now insert the cache. */
@@ -191,7 +190,6 @@ void GLVaoCache::clear()
this->init();
}
-/* Return 0 on cache miss (invalid VAO) */
GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
{
const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN;
@@ -205,8 +203,6 @@ GLuint GLVaoCache::lookup(const GLShaderInterface *interface)
return 0;
}
-/* The GLVaoCache object is only valid for one GLContext.
- * Reset the cache if trying to draw in another context; */
void GLVaoCache::context_check()
{
GLContext *ctx = GLContext::get();
@@ -276,6 +272,7 @@ GLuint GLVaoCache::vao_get(GPUBatch *batch)
return vao_id_;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh
index 704b6471dd5..a2b5f8fc15e 100644
--- a/source/blender/gpu/opengl/gl_batch.hh
+++ b/source/blender/gpu/opengl/gl_batch.hh
@@ -43,9 +43,11 @@ class GLShaderInterface;
#define GPU_VAO_STATIC_LEN 3
-/* VAO management: remembers all geometry state (vertex attribute bindings & element buffer)
- * for each shader interface. Start with a static number of vaos and fallback to dynamic count
- * if necessary. Once a batch goes dynamic it does not go back. */
+/**
+ * VAO management: remembers all geometry state (vertex attribute bindings & element buffer)
+ * for each shader interface. Start with a static number of VAO's and fallback to dynamic count
+ * if necessary. Once a batch goes dynamic it does not go back.
+ */
class GLVaoCache {
private:
/** Context for which the vao_cache_ was generated. */
@@ -80,13 +82,23 @@ class GLVaoCache {
GLuint vao_get(GPUBatch *batch);
GLuint base_instance_vao_get(GPUBatch *batch, int i_first);
+ /**
+ * Return 0 on cache miss (invalid VAO).
+ */
GLuint lookup(const GLShaderInterface *interface);
+ /**
+ * Create a new VAO object and store it in the cache.
+ */
void insert(const GLShaderInterface *interface, GLuint vao_id);
void remove(const GLShaderInterface *interface);
void clear(void);
private:
void init(void);
+ /**
+ * The #GLVaoCache object is only valid for one #GLContext.
+ * Reset the cache if trying to draw in another context;.
+ */
void context_check(void);
};
@@ -100,6 +112,7 @@ class GLBatch : public Batch {
void bind(int i_first);
/* Convenience getters. */
+
GLIndexBuf *elem_(void) const
{
return static_cast<GLIndexBuf *>(unwrap(elem));
diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh
index 0222adaba25..40107ca9ef7 100644
--- a/source/blender/gpu/opengl/gl_context.hh
+++ b/source/blender/gpu/opengl/gl_context.hh
@@ -56,11 +56,14 @@ class GLSharedOrphanLists {
class GLContext : public Context {
public:
/** Capabilities. */
+
static GLint max_cubemap_size;
static GLint max_texture_3d_size;
static GLint max_ubo_size;
static GLint max_ubo_binds;
+
/** Extensions. */
+
static bool base_instance_support;
static bool clear_texture_support;
static bool copy_image_support;
@@ -74,9 +77,12 @@ class GLContext : public Context {
static bool texture_filter_anisotropic_support;
static bool texture_gather_support;
static bool vertex_attrib_binding_support;
+
/** Workarounds. */
+
static bool debug_layer_workaround;
static bool unused_fb_slot_workaround;
+ static bool generate_mipmap_workaround;
static float derivative_signs[2];
/** VBO for missing vertex attrib binding. Avoid undefined behavior on some implementation. */
diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc
index 3e259235515..0a06d9cdb7c 100644
--- a/source/blender/gpu/opengl/gl_debug.cc
+++ b/source/blender/gpu/opengl/gl_debug.cc
@@ -142,7 +142,6 @@ static void APIENTRY debug_callback(GLenum UNUSED(source),
#undef APIENTRY
-/* This function needs to be called once per context. */
void init_gl_callbacks()
{
CLOG_ENSURE(&LOG);
diff --git a/source/blender/gpu/opengl/gl_debug.hh b/source/blender/gpu/opengl/gl_debug.hh
index 892fb1d2ddb..3964e5da550 100644
--- a/source/blender/gpu/opengl/gl_debug.hh
+++ b/source/blender/gpu/opengl/gl_debug.hh
@@ -88,8 +88,16 @@ namespace debug {
void raise_gl_error(const char *info);
void check_gl_error(const char *info);
void check_gl_resources(const char *info);
+/**
+ * This function needs to be called once per context.
+ */
void init_gl_callbacks(void);
+/**
+ * Initialize a fallback layer (to KHR_debug) that covers only some functions.
+ * We override the functions pointers by our own implementation that just checks #glGetError.
+ * Some additional functions (not overridable) are covered inside the header using wrappers.
+ */
void init_debug_layer(void);
void object_label(GLenum type, GLuint object, const char *name);
diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc
index a5225f98fd9..e624cb9ee46 100644
--- a/source/blender/gpu/opengl/gl_debug_layer.cc
+++ b/source/blender/gpu/opengl/gl_debug_layer.cc
@@ -105,11 +105,6 @@ DEBUG_FUNC_DECLARE(PFNGLUSEPROGRAMPROC, void, glUseProgram, GLuint, program);
#undef DEBUG_FUNC_DECLARE
-/**
- * Initialize a fallback layer (to KHR_debug) that covers only some functions.
- * We override the functions pointers by our own implementation that just checks #glGetError.
- * Some additional functions (not overridable) are covered inside the header using wrappers.
- */
void init_debug_layer()
{
#define DEBUG_WRAP(function) \
diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc
index 50ab5574cd2..8b000784fc8 100644
--- a/source/blender/gpu/opengl/gl_drawlist.cc
+++ b/source/blender/gpu/opengl/gl_drawlist.cc
@@ -236,5 +236,3 @@ void GLDrawList::submit()
/* Avoid keeping reference to the batch. */
batch_ = nullptr;
}
-
-/** \} */
diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc
index 8da114d9270..13f03195437 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.cc
+++ b/source/blender/gpu/opengl/gl_framebuffer.cc
@@ -110,7 +110,6 @@ void GLFrameBuffer::init()
/** \name Config
* \{ */
-/* This is a rather slow operation. Don't check in normal cases. */
bool GLFrameBuffer::check(char err_out[256])
{
this->bind(true);
@@ -451,9 +450,6 @@ void GLFrameBuffer::read(eGPUFrameBufferBits plane,
glReadPixels(UNPACK4(area), format, type, r_data);
}
-/**
- * Copy \a src at the give offset inside \a dst.
- */
void GLFrameBuffer::blit_to(
eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst_, int dst_slot, int x, int y)
{
diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh
index 7b2c73d7042..21b5931440d 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.hh
+++ b/source/blender/gpu/opengl/gl_framebuffer.hh
@@ -79,6 +79,9 @@ class GLFrameBuffer : public FrameBuffer {
void bind(bool enabled_srgb) override;
+ /**
+ * This is a rather slow operation. Don't check in normal cases.
+ */
bool check(char err_out[256]) override;
void clear(eGPUFrameBufferBits buffers,
@@ -97,6 +100,9 @@ class GLFrameBuffer : public FrameBuffer {
int slot,
void *r_data) override;
+ /**
+ * Copy \a src at the give offset inside \a dst.
+ */
void blit_to(eGPUFrameBufferBits planes,
int src_slot,
FrameBuffer *dst,
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 66a1bd5ceb7..cd2c3caad46 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -137,7 +137,6 @@ char *GLShader::glsl_patch_get(GLenum gl_stage)
return glsl_patch_default_get();
}
-/* Create, compile and attach the shader stage to the shader program. */
GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources)
{
GLuint shader = glCreateShader(gl_stage);
@@ -258,7 +257,6 @@ void GLShader::unbind()
* TODO(fclem): Should be replaced by compute shaders.
* \{ */
-/* Should be called before linking. */
void GLShader::transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type)
{
diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh
index 770bc29747e..57e33392d9f 100644
--- a/source/blender/gpu/opengl/gl_shader.hh
+++ b/source/blender/gpu/opengl/gl_shader.hh
@@ -53,13 +53,14 @@ class GLShader : public Shader {
GLShader(const char *name);
~GLShader();
- /* Return true on success. */
+ /** Return true on success. */
void vertex_shader_from_glsl(MutableSpan<const char *> sources) override;
void geometry_shader_from_glsl(MutableSpan<const char *> sources) override;
void fragment_shader_from_glsl(MutableSpan<const char *> sources) override;
void compute_shader_from_glsl(MutableSpan<const char *> sources) override;
bool finalize(void) override;
+ /** Should be called before linking. */
void transform_feedback_names_set(Span<const char *> name_list,
const eGPUShaderTFBType geom_type) override;
bool transform_feedback_enable(GPUVertBuf *buf) override;
@@ -73,12 +74,13 @@ class GLShader : public Shader {
void vertformat_from_shader(GPUVertFormat *format) const override;
- /* DEPRECATED: Kept only because of BGL API. */
+ /** DEPRECATED: Kept only because of BGL API. */
int program_handle_get(void) const override;
private:
char *glsl_patch_get(GLenum gl_stage);
+ /** Create, compile and attach the shader stage to the shader program. */
GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources);
MEM_CXX_CLASS_ALLOC_FUNCS("GLShader");
diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc
index d737cf88a13..bfc691df4b3 100644
--- a/source/blender/gpu/opengl/gl_state.cc
+++ b/source/blender/gpu/opengl/gl_state.cc
@@ -84,7 +84,6 @@ void GLStateManager::apply_state()
active_fb->apply_state();
};
-/* Will set all the states regardless of the current ones. */
void GLStateManager::force_state()
{
/* Little exception for clip distances since they need to keep the old count correct. */
@@ -482,7 +481,6 @@ void GLStateManager::texture_bind(Texture *tex_, eGPUSamplerState sampler_type,
dirty_texture_binds_ |= 1ULL << unit;
}
-/* Bind the texture to slot 0 for editing purpose. Used by legacy pipeline. */
void GLStateManager::texture_bind_temp(GLTexture *tex)
{
glActiveTexture(GL_TEXTURE0);
diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh
index 3b4b40b1d10..979644b41c9 100644
--- a/source/blender/gpu/opengl/gl_state.hh
+++ b/source/blender/gpu/opengl/gl_state.hh
@@ -72,11 +72,17 @@ class GLStateManager : public StateManager {
GLStateManager();
void apply_state(void) override;
+ /**
+ * Will set all the states regardless of the current ones.
+ */
void force_state(void) override;
void issue_barrier(eGPUBarrier barrier_bits) override;
void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override;
+ /**
+ * Bind the texture to slot 0 for editing purpose. Used by legacy pipeline.
+ */
void texture_bind_temp(GLTexture *tex);
void texture_unbind(Texture *tex) override;
void texture_unbind_all(void) override;
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index db1fda63c28..d84d21d3021 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -62,7 +62,6 @@ GLTexture::~GLTexture()
GLContext::tex_free(tex_id_);
}
-/* Return true on success. */
bool GLTexture::init_internal()
{
if ((format_ == GPU_DEPTH24_STENCIL8) && GPU_depth_blitting_workaround()) {
@@ -100,7 +99,6 @@ bool GLTexture::init_internal()
return true;
}
-/* Return true on success. */
bool GLTexture::init_internal(GPUVertBuf *vbo)
{
GLVertBuf *gl_vbo = static_cast<GLVertBuf *>(unwrap(vbo));
@@ -123,7 +121,6 @@ bool GLTexture::init_internal(GPUVertBuf *vbo)
return true;
}
-/* Will create enough mipmaps up to get to the given level. */
void GLTexture::ensure_mipmaps(int miplvl)
{
int effective_h = (type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : h_;
@@ -225,6 +222,8 @@ void GLTexture::update_sub_direct_state_access(
break;
}
}
+
+ has_pixels_ = true;
}
void GLTexture::update_sub(
@@ -288,6 +287,8 @@ void GLTexture::update_sub(
break;
}
}
+
+ has_pixels_ = true;
}
/**
@@ -307,6 +308,16 @@ void GLTexture::generate_mipmap()
return;
}
+ if (GLContext::generate_mipmap_workaround) {
+ /* Broken glGenerateMipmap, don't call it and render without mipmaps.
+ * If no top level pixels have been filled in, the levels will get filled by
+ * other means and there is no need to disable mipmapping. */
+ if (has_pixels_) {
+ this->mip_range_set(0, 0);
+ }
+ return;
+ }
+
/* Down-sample from mip 0 using implementation. */
if (GLContext::direct_state_access_support) {
glGenerateTextureMipmap(tex_id_);
@@ -337,6 +348,8 @@ void GLTexture::clear(eGPUDataFormat data_format, const void *data)
GPU_framebuffer_bind(prev_fb);
}
+
+ has_pixels_ = true;
}
void GLTexture::copy_to(Texture *dst_)
@@ -363,6 +376,8 @@ void GLTexture::copy_to(Texture *dst_)
GPU_framebuffer_blit(
src->framebuffer_get(), 0, dst->framebuffer_get(), 0, to_framebuffer_bits(format_));
}
+
+ has_pixels_ = true;
}
void *GLTexture::read(int mip, eGPUDataFormat type)
@@ -452,6 +467,7 @@ struct GPUFrameBuffer *GLTexture::framebuffer_get()
GPUTexture *gputex = reinterpret_cast<GPUTexture *>(static_cast<Texture *>(this));
framebuffer_ = GPU_framebuffer_create(name_);
GPU_framebuffer_texture_attach(framebuffer_, gputex, 0, 0);
+ has_pixels_ = true;
return framebuffer_;
}
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index 2a480e71017..eb979444f5a 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -53,6 +53,8 @@ class GLTexture : public Texture {
/** True if this texture is bound to at least one texture unit. */
/* TODO(fclem): How do we ensure thread safety here? */
bool is_bound_ = false;
+ /** True if pixels in the texture have been initialized. */
+ bool has_pixels_ = false;
public:
GLTexture(const char *name);
@@ -61,6 +63,12 @@ class GLTexture : public Texture {
void update_sub(
int mip, int offset[3], int extent[3], eGPUDataFormat type, const void *data) override;
+ /**
+ * This will create the mipmap images and populate them with filtered data from base level.
+ *
+ * \warning Depth textures are not populated but they have their mips correctly defined.
+ * \warning This resets the mipmap range.
+ */
void generate_mipmap(void) override;
void copy_to(Texture *dst) override;
void clear(eGPUDataFormat format, const void *data) override;
@@ -78,11 +86,14 @@ class GLTexture : public Texture {
static void samplers_update(void);
protected:
+ /** Return true on success. */
bool init_internal(void) override;
+ /** Return true on success. */
bool init_internal(GPUVertBuf *vbo) override;
private:
bool proxy_check(int mip);
+ /** Will create enough mipmaps up to get to the given level. */
void ensure_mipmaps(int mip);
void update_sub_direct_state_access(
int mip, int offset[3], int extent[3], GLenum gl_format, GLenum gl_type, const void *data);
@@ -292,7 +303,9 @@ inline GLenum to_gl(eGPUDataFormat format)
}
}
-/* Definitely not complete, edit according to the gl specification. */
+/**
+ * Definitely not complete, edit according to the OpenGL specification.
+ */
inline GLenum to_gl_data_format(eGPUTextureFormat format)
{
/* You can add any of the available type to this list
@@ -364,7 +377,9 @@ inline GLenum to_gl_data_format(eGPUTextureFormat format)
}
}
-/* Assume Unorm / Float target. Used with glReadPixels. */
+/**
+ * Assume Unorm / Float target. Used with #glReadPixels.
+ */
inline GLenum channel_len_to_gl(int channel_len)
{
switch (channel_len) {
diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc
index e324916b934..282ede5ba9b 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.cc
+++ b/source/blender/gpu/opengl/gl_vertex_array.cc
@@ -108,7 +108,6 @@ static uint16_t vbo_bind(const ShaderInterface *interface,
return enabled_attrib;
}
-/* Update the Attribute Binding of the currently bound VAO. */
void GLVertArray::update_bindings(const GLuint vao,
const GPUBatch *batch_, /* Should be GLBatch. */
const ShaderInterface *interface,
@@ -156,7 +155,6 @@ void GLVertArray::update_bindings(const GLuint vao,
}
}
-/* Another version of update_bindings for Immediate mode. */
void GLVertArray::update_bindings(const GLuint vao,
const uint v_first,
const GPUVertFormat *format,
diff --git a/source/blender/gpu/opengl/gl_vertex_array.hh b/source/blender/gpu/opengl/gl_vertex_array.hh
index 7037986e31e..0f9b61f9648 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.hh
+++ b/source/blender/gpu/opengl/gl_vertex_array.hh
@@ -33,11 +33,17 @@ namespace gpu {
namespace GLVertArray {
+/**
+ * Update the Attribute Binding of the currently bound VAO.
+ */
void update_bindings(const GLuint vao,
const GPUBatch *batch,
const ShaderInterface *interface,
const int base_instance);
+/**
+ * Another version of update_bindings for Immediate mode.
+ */
void update_bindings(const GLuint vao,
const uint v_first,
const GPUVertFormat *format,
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
index 44a9db76834..43f259671fa 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
@@ -13,7 +13,7 @@ uniform float dash_factor; /* if > 1.0, solid line. */
/* More advanced mode, allowing for complex, multi-colored patterns.
* Enabled when colors_len > 0. */
-/* Note: max number of steps/colors in pattern is 32! */
+/* NOTE: max number of steps/colors in pattern is 32! */
uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
uniform vec4 colors[32];
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
index 7853aae31a1..1def3abec26 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -4,13 +4,128 @@ float smootherstep(float edge0, float edge1, float x)
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
}
+vec3 smootherstep(vec3 edge0, vec3 edge1, vec3 x)
+{
+ x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
+ return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
+}
+
+void vector_map_range_linear(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+ if (use_clamp > 0.0) {
+ v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) :
+ clamp(v_result.x, v_to_min.x, v_to_max.x);
+ v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) :
+ clamp(v_result.y, v_to_min.y, v_to_max.y);
+ v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) :
+ clamp(v_result.z, v_to_min.z, v_to_max.z);
+ }
+}
+
+void vector_map_range_stepped(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = safe_divide(floor(factor * (v_steps + 1.0)), v_steps);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+ if (use_clamp > 0.0) {
+ v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) :
+ clamp(v_result.x, v_to_min.x, v_to_max.x);
+ v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) :
+ clamp(v_result.y, v_to_min.y, v_to_max.y);
+ v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) :
+ clamp(v_result.z, v_to_min.z, v_to_max.z);
+ }
+}
+
+void vector_map_range_smoothstep(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = (3.0 - 2.0 * factor) * (factor * factor);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+}
+
+void vector_map_range_smootherstep(float value,
+ float fromMin,
+ float fromMax,
+ float toMin,
+ float toMax,
+ float steps,
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
+{
+ vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
+ factor = clamp(factor, 0.0, 1.0);
+ factor = factor * factor * factor * (factor * (factor * 6.0 - 15.0) + 10.0);
+ v_result = v_to_min + factor * (v_to_max - v_to_min);
+}
+
void map_range_linear(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
@@ -26,7 +141,15 @@ void map_range_stepped(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (value - fromMin) / (fromMax - fromMin);
@@ -44,7 +167,15 @@ void map_range_smoothstep(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smoothstep(fromMax, fromMin, value) :
@@ -62,7 +193,15 @@ void map_range_smootherstep(float value,
float toMin,
float toMax,
float steps,
- out float result)
+ vec3 v_value,
+ vec3 v_from_min,
+ vec3 v_from_max,
+ vec3 v_to_min,
+ vec3 v_to_max,
+ vec3 v_steps,
+ float use_clamp,
+ out float result,
+ out vec3 v_result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smootherstep(fromMax, fromMin, value) :
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
index 942c507cc38..1dc5ff433a8 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
@@ -1,7 +1,8 @@
void node_tex_magic(
vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
{
- vec3 p = co * scale;
+ vec3 p = mod(co * scale, 2.0 * M_PI);
+
float x = sin((p.x + p.y + p.z) * 5.0);
float y = cos((-p.x + p.y - p.z) * 5.0);
float z = -cos((-p.x - p.y + p.z) * 5.0);
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index a9e1692ebf0..949efb522f3 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1876,9 +1876,10 @@ static void execute_scene(struct Depsgraph *depsgraph,
}
}
-/*---------------------------------------------------
- * plugin interface
- */
+/* -------------------------------------------------------------------- */
+/** \name Plugin Interface
+ * \{ */
+
void itasc_initialize_tree(struct Depsgraph *depsgraph,
struct Scene *scene,
Object *ob,
@@ -2012,3 +2013,5 @@ void itasc_test_constraint(struct Object *ob, struct bConstraint *cons)
break;
}
}
+
+/** \} */
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index be0e364c85f..479f4f7e82f 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/thumbs.c
intern/thumbs_blend.c
intern/thumbs_font.c
+ intern/transform.cc
intern/util.c
intern/util_gpu.c
intern/writeimage.c
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 53b0e295385..3ea8ac47f17 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -45,7 +45,9 @@ struct bContext;
struct ColorManagedDisplay;
struct ColorSpace;
-/* ** Generic functions ** */
+/* -------------------------------------------------------------------- */
+/** \name Generic Functions
+ * \{ */
void IMB_colormanagement_check_file_config(struct Main *bmain);
@@ -67,13 +69,35 @@ bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_name_is_data(const char *name);
+/**
+ * Convert a float RGB triplet to the correct luminance weighted average.
+ *
+ * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
+ * based on the luminance positions of the red, green, and blue primaries.
+ * Given that the internal reference space may be arbitrarily set, any
+ * effort to glean the luminance coefficients must be aware of the reference
+ * space primaries.
+ *
+ * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
+ */
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
+/**
+ * Byte equivalent of #IMB_colormanagement_get_luminance().
+ */
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
BLI_INLINE void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3]);
BLI_INLINE void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3]);
const float *IMB_colormanagement_get_xyz_to_rgb(void);
-/* ** Color space transformation functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Space Transformation Functions
+ * \{ */
+
+/**
+ * Convert the whole buffer from specified by name color space to another.
+ */
void IMB_colormanagement_transform(float *buffer,
int width,
int height,
@@ -81,6 +105,10 @@ void IMB_colormanagement_transform(float *buffer,
const char *from_colorspace,
const char *to_colorspace,
bool predivide);
+/**
+ * Convert the whole buffer from specified by name color space to another
+ * will do threaded conversion.
+ */
void IMB_colormanagement_transform_threaded(float *buffer,
int width,
int height,
@@ -88,6 +116,9 @@ void IMB_colormanagement_transform_threaded(float *buffer,
const char *from_colorspace,
const char *to_colorspace,
bool predivide);
+/**
+ * Similar to #IMB_colormanagement_transform_threaded, but operates on byte buffer.
+ */
void IMB_colormanagement_transform_byte(unsigned char *buffer,
int width,
int height,
@@ -100,6 +131,9 @@ void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
int channels,
const char *from_colorspace,
const char *to_colorspace);
+/**
+ * Similar to #IMB_colormanagement_transform_byte_threaded, but gets float buffer from display one.
+ */
void IMB_colormanagement_transform_from_byte(float *float_buffer,
unsigned char *byte_buffer,
int width,
@@ -118,12 +152,20 @@ void IMB_colormanagement_transform_v4(float pixel[4],
const char *from_colorspace,
const char *to_colorspace);
+/**
+ * Convert pixel from specified by descriptor color space to scene linear
+ * used by performance-critical areas such as renderer and baker.
+ */
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3],
struct ColorSpace *colorspace);
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4],
bool predivide,
struct ColorSpace *colorspace);
+/**
+ * Same as #IMB_colormanagement_colorspace_to_scene_linear_v4,
+ * but converts colors in opposite direction.
+ */
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3],
struct ColorSpace *colorspace);
@@ -150,14 +192,36 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
const struct ImBuf *ibuf,
const bool store_premultiplied);
+/**
+ * Conversion between color picking role. Typically we would expect such a
+ * requirements:
+ * - It is approximately perceptually linear, so that the HSV numbers and
+ * the HSV cube/circle have an intuitive distribution.
+ * - It has the same gamut as the scene linear color space.
+ * - Color picking values 0..1 map to scene linear values in the 0..1 range,
+ * so that picked albedo values are energy conserving.
+ */
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]);
void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]);
+/**
+ * Conversion between sRGB, for rare cases like hex color or copy/pasting
+ * between UI theme and scene linear colors.
+ */
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3]);
void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3]);
+/**
+ * Convert pixel from scene linear to display space using default view
+ * used by performance-critical areas such as color-related widgets where we want to reduce
+ * amount of per-widget allocations.
+ */
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3],
struct ColorManagedDisplay *display);
+/**
+ * Same as #IMB_colormanagement_scene_linear_to_display_v3,
+ * but converts color in opposite direction.
+ */
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3],
struct ColorManagedDisplay *display);
@@ -178,6 +242,18 @@ void IMB_colormanagement_imbuf_make_display_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
+/**
+ * Prepare image buffer to be saved on disk, applying color management if needed
+ * color management would be applied if image is saving as render result and if
+ * file format is not expecting float buffer to be in linear space (currently
+ * JPEG2000 and TIFF are such formats -- they're storing image as float but
+ * file itself stores applied color space).
+ *
+ * Both byte and float buffers would contain applied color space, and result's
+ * float_colorspace would be set to display color space. This should be checked
+ * in image format write callback and if float_colorspace is not NULL, no color
+ * space transformation should be applied on this buffer.
+ */
struct ImBuf *IMB_colormanagement_imbuf_for_write(
struct ImBuf *ibuf,
bool save_as_render,
@@ -196,7 +272,11 @@ void IMB_colormanagement_buffer_make_display_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
-/* ** Public display buffers interfaces ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Display Buffers Interfaces
+ * \{ */
void IMB_colormanagement_display_settings_from_ctx(
const struct bContext *C,
@@ -207,11 +287,17 @@ const char *IMB_colormanagement_get_display_colorspace_name(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
+/**
+ * Acquire display buffer for given image buffer using specified view and display settings.
+ */
unsigned char *IMB_display_buffer_acquire(
struct ImBuf *ibuf,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
void **cache_handle);
+/**
+ * Same as #IMB_display_buffer_acquire but gets view and display settings from context.
+ */
unsigned char *IMB_display_buffer_acquire_ctx(const struct bContext *C,
struct ImBuf *ibuf,
void **cache_handle);
@@ -227,24 +313,47 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer,
void IMB_display_buffer_release(void *cache_handle);
-/* ** Display functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Display Functions
+ * \{ */
+
int IMB_colormanagement_display_get_named_index(const char *name);
const char *IMB_colormanagement_display_get_indexed_name(int index);
const char *IMB_colormanagement_display_get_default_name(void);
+/**
+ * Used by performance-critical pixel processing areas, such as color widgets.
+ */
struct ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name);
const char *IMB_colormanagement_display_get_none_name(void);
const char *IMB_colormanagement_display_get_default_view_transform_name(
struct ColorManagedDisplay *display);
-/* ** View functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Functions
+ * \{ */
+
int IMB_colormanagement_view_get_named_index(const char *name);
const char *IMB_colormanagement_view_get_indexed_name(int index);
-/* ** Look functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Look Functions
+ * \{ */
+
int IMB_colormanagement_look_get_named_index(const char *name);
const char *IMB_colormanagement_look_get_indexed_name(int index);
-/* ** Color space functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Space Functions
+ * \{ */
+
int IMB_colormanagement_colorspace_get_named_index(const char *name);
const char *IMB_colormanagement_colorspace_get_indexed_name(int index);
const char *IMB_colormanagement_view_get_default_name(const char *display_name);
@@ -252,7 +361,12 @@ const char *IMB_colormanagement_view_get_default_name(const char *display_name);
void IMB_colormanagement_colorspace_from_ibuf_ftype(
struct ColorManagedColorspaceSettings *colorspace_settings, struct ImBuf *ibuf);
-/* ** RNA helper functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA Helper Functions
+ * \{ */
+
void IMB_colormanagement_display_items_add(struct EnumPropertyItem **items, int *totitem);
void IMB_colormanagement_view_items_add(struct EnumPropertyItem **items,
int *totitem,
@@ -262,7 +376,12 @@ void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items,
const char *view_name);
void IMB_colormanagement_colorspace_items_add(struct EnumPropertyItem **items, int *totitem);
-/* ** Tile-based buffer management ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tile-based Buffer Management
+ * \{ */
+
void IMB_partial_display_buffer_update(struct ImBuf *ibuf,
const float *linear_buffer,
const unsigned char *byte_buffer,
@@ -293,7 +412,12 @@ void IMB_partial_display_buffer_update_threaded(
void IMB_partial_display_buffer_update_delayed(
struct ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax);
-/* ** Pixel processor functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pixel Processor Functions
+ * \{ */
+
struct ColormanageProcessor *IMB_colormanagement_display_processor_new(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
@@ -321,17 +445,40 @@ void IMB_colormanagement_processor_apply_byte(struct ColormanageProcessor *cm_pr
int channels);
void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor);
-/* ** OpenGL drawing routines using GLSL for color space transform ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name OpenGL Drawing Routines Using GLSL for Color Space Transform
+ * \{ */
-/* Test if GLSL drawing is supported for combination of graphics card and this configuration */
+/**
+ * Test if GLSL drawing is supported for combination of graphics card and this configuration.
+ */
bool IMB_colormanagement_support_glsl_draw(const struct ColorManagedViewSettings *view_settings);
-/* Configures GLSL shader for conversion from scene linear to display space */
+/**
+ * Configures GLSL shader for conversion from scene linear to display space.
+ */
bool IMB_colormanagement_setup_glsl_draw(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
float dither,
bool predivide);
-/* Same as above, but display space conversion happens from a specified space */
+/**
+ * \note Same as IMB_colormanagement_setup_glsl_draw,
+ * but display space conversion happens from a specified space.
+ *
+ * Configures GLSL shader for conversion from specified to
+ * display color space
+ *
+ * Will create appropriate OCIO processor and setup GLSL shader,
+ * so further 2D texture usage will use this conversion.
+ *
+ * When there's no need to apply transform on 2D textures, use
+ * IMB_colormanagement_finish_glsl_draw().
+ *
+ * This is low-level function, use ED_draw_imbuf_ctx if you
+ * only need to display given image buffer
+ */
bool IMB_colormanagement_setup_glsl_draw_from_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
@@ -339,20 +486,31 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
float dither,
bool predivide,
bool do_overlay_merge);
-/* Same as setup_glsl_draw, but color management settings are guessing from a given context */
+/**
+ * Same as setup_glsl_draw, but color management settings are guessing from a given context.
+ */
bool IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C,
float dither,
bool predivide);
-/* Same as setup_glsl_draw_from_space,
- * but color management settings are guessing from a given context. */
+/**
+ * Same as `setup_glsl_draw_from_space`,
+ * but color management settings are guessing from a given context.
+ */
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C,
struct ColorSpace *colorspace,
float dither,
bool predivide);
-/* Finish GLSL-based display space conversion */
+/**
+ * Finish GLSL-based display space conversion.
+ */
void IMB_colormanagement_finish_glsl_draw(void);
-/* ** View transform ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Transform
+ * \{ */
+
void IMB_colormanagement_init_default_view_settings(
struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
@@ -368,6 +526,8 @@ enum {
COLOR_ROLE_DATA,
};
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 7bfd1074ac6..1f698c65382 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -199,6 +199,17 @@ bool addzbuffloatImBuf(struct ImBuf *ibuf);
size_t IMB_get_size_in_memory(struct ImBuf *ibuf);
/**
+ * \brief Get the length of the rect of the given image buffer in terms of pixels.
+ *
+ * This is the width * the height of the image buffer.
+ * This function is preferred over `ibuf->x * ibuf->y` due to overflow issues when
+ * working with large resolution images (30kx30k).
+ *
+ * \attention Defined in allocimbuf.c
+ */
+size_t IMB_get_rect_len(const struct ImBuf *ibuf);
+
+/**
*
* \attention Defined in rectop.c
*/
@@ -244,8 +255,14 @@ void IMB_blend_color_float(float dst[4],
const float src2[4],
IMB_BlendMode mode);
+/**
+ * In-place image crop.
+ */
void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop);
+/**
+ * In-place size setting (caller must fill in buffer contents).
+ */
void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]);
void IMB_rectclip(struct ImBuf *dbuf,
@@ -342,7 +359,9 @@ typedef enum eIMBInterpolationFilterMode {
IMB_FILTER_BILINEAR,
} eIMBInterpolationFilterMode;
-/* Defaults to BL_proxy within the directory of the animation. */
+/**
+ * Defaults to BL_proxy within the directory of the animation.
+ */
void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
void IMB_anim_get_fname(struct anim *anim, char *file, int size);
@@ -352,7 +371,9 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim);
struct IndexBuildContext;
-/* Prepare context for proxies/time-codes builder. */
+/**
+ * Prepare context for proxies/time-codes builder
+ */
struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
@@ -360,13 +381,17 @@ struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
const bool overwrite,
struct GSet *file_list);
-/* Will rebuild all used indices and proxies at once. */
+/**
+ * Will rebuild all used indices and proxies at once.
+ */
void IMB_anim_index_rebuild(struct IndexBuildContext *context,
short *stop,
short *do_update,
float *progress);
-/* Finish rebuilding proxies/time-codes and free temporary contexts used. */
+/**
+ * Finish rebuilding proxies/time-codes and free temporary contexts used.
+ */
void IMB_anim_index_rebuild_finish(struct IndexBuildContext *context, short stop);
/**
@@ -442,8 +467,20 @@ void IMB_free_anim(struct anim *anim);
void IMB_filter(struct ImBuf *ibuf);
void IMB_mask_filter_extend(char *mask, int width, int height);
void IMB_mask_clear(struct ImBuf *ibuf, const char *mask, int val);
+/**
+ * If alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
+ * When a mask is given, the mask will be used instead of the alpha channel, where only
+ * pixels with a mask value of 0 will be written to, and only pixels with a mask value of 1
+ * will be used for the average. The mask will be set to one for the pixels which were written.
+ */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter);
+/**
+ * Frees too (if there) and recreates new data.
+ */
void IMB_makemipmap(struct ImBuf *ibuf, int use_filter);
+/**
+ * Thread-safe version, only recreates existing maps.
+ */
void IMB_remakemipmap(struct ImBuf *ibuf, int use_filter);
struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level);
@@ -452,6 +489,9 @@ struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level);
* \attention Defined in cache.c
*/
+/**
+ * Presumed to be called when no threads are running.
+ */
void IMB_tile_cache_params(int totthread, int maxmem);
unsigned int *IMB_gettile(struct ImBuf *ibuf, int tx, int ty, int thread);
void IMB_tiles_to_rect(struct ImBuf *ibuf);
@@ -471,6 +511,8 @@ struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1);
/**
*
* \attention Defined in scaling.c
+ *
+ * Return true if \a ibuf is modified.
*/
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
@@ -478,6 +520,9 @@ bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
*
* \attention Defined in scaling.c
*/
+/**
+ * Return true if \a ibuf is modified.
+ */
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
/**
@@ -520,16 +565,27 @@ int imb_get_anim_type(const char *filepath);
*/
bool IMB_isfloat(const struct ImBuf *ibuf);
-/* Do byte/float and colorspace conversions need to take alpha into account? */
+/**
+ * Test if color-space conversions of pixels in buffer need to take into account alpha.
+ */
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
-/* create char buffer, color corrected if necessary, for ImBufs that lack one */
+/**
+ * Create char buffer, color corrected if necessary, for ImBufs that lack one.
+ */
void IMB_rect_from_float(struct ImBuf *ibuf);
void IMB_float_from_rect(struct ImBuf *ibuf);
+/**
+ * No profile conversion.
+ */
void IMB_color_to_bw(struct ImBuf *ibuf);
void IMB_saturation(struct ImBuf *ibuf, float sat);
-/* converting pixel buffers */
+/* Converting pixel buffers. */
+
+/**
+ * Float to byte pixels, output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_float(unsigned char *rect_to,
const float *rect_from,
int channels_from,
@@ -541,6 +597,9 @@ void IMB_buffer_byte_from_float(unsigned char *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to byte pixels, output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_float_mask(unsigned char *rect_to,
const float *rect_from,
int channels_from,
@@ -551,6 +610,9 @@ void IMB_buffer_byte_from_float_mask(unsigned char *rect_to,
int stride_to,
int stride_from,
char *mask);
+/**
+ * Byte to float pixels, input and output 4-channel RGBA.
+ */
void IMB_buffer_float_from_byte(float *rect_to,
const unsigned char *rect_from,
int profile_to,
@@ -560,6 +622,9 @@ void IMB_buffer_float_from_byte(float *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to float pixels, output 4-channel RGBA.
+ */
void IMB_buffer_float_from_float(float *rect_to,
const float *rect_from,
int channels_from,
@@ -580,6 +645,9 @@ void IMB_buffer_float_from_float_threaded(float *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to float pixels, output 4-channel RGBA.
+ */
void IMB_buffer_float_from_float_mask(float *rect_to,
const float *rect_from,
int channels_from,
@@ -588,6 +656,9 @@ void IMB_buffer_float_from_float_mask(float *rect_to,
int stride_to,
int stride_from,
char *mask);
+/**
+ * Byte to byte pixels, input and output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_byte(unsigned char *rect_to,
const unsigned char *rect_from,
int profile_to,
@@ -605,6 +676,8 @@ void IMB_buffer_float_premultiply(float *buf, int width, int height);
* rgba to abgr. size * 4 color bytes are reordered.
*
* \attention Defined in imageprocess.c
+ *
+ * Only this one is used liberally here, and in imbuf.
*/
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
@@ -612,27 +685,50 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
*
* \attention defined in imageprocess.c
*/
+
void bicubic_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
void nearest_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
void bilinear_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+typedef void (*InterpolationColorFunction)(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void bicubic_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+
+/* Functions assumes out to be zeroed, only does RGBA. */
+
+void nearest_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void nearest_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void nearest_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void bilinear_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void bilinear_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void bilinear_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+/**
+ * Note about wrapping, the u/v still needs to be within the image bounds,
+ * just the interpolation is wrapped.
+ * This the same as bilinear_interpolation_color except it wraps
+ * rather than using empty and emptyI.
+ */
void bilinear_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3]);
+/**
+ * Sample pixel of image using NEAREST method.
+ */
void IMB_sampleImageAtLocation(
struct ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
@@ -686,7 +782,7 @@ struct ImBuf *IMB_double_y(struct ImBuf *ibuf1);
void IMB_flipx(struct ImBuf *ibuf);
void IMB_flipy(struct ImBuf *ibuf);
-/* Premultiply alpha */
+/* Pre-multiply alpha. */
void IMB_premultiply_alpha(struct ImBuf *ibuf);
void IMB_unpremultiply_alpha(struct ImBuf *ibuf);
@@ -702,7 +798,27 @@ void IMB_freezbuffloatImBuf(struct ImBuf *ibuf);
*
* \attention Defined in rectop.c
*/
+/**
+ * Replace pixels of entire image with solid color.
+ * \param drect: An image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ */
void IMB_rectfill(struct ImBuf *drect, const float col[4]);
+/**
+ * Blend pixels of image area with solid color.
+ *
+ * For images with `uchar` buffer use color matching image color-space.
+ * For images with float buffer use color display color-space.
+ * If display color-space can not be referenced, use color in SRGB color-space.
+ *
+ * \param ibuf: an image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color.
+ * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ * \param display: color-space reference for display space.
+ */
void IMB_rectfill_area(struct ImBuf *ibuf,
const float col[4],
int x1,
@@ -710,12 +826,23 @@ void IMB_rectfill_area(struct ImBuf *ibuf,
int x2,
int y2,
struct ColorManagedDisplay *display);
+/**
+ * Replace pixels of image area with solid color.
+ * \param ibuf: an image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ */
void IMB_rectfill_area_replace(
const struct ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2);
void IMB_rectfill_alpha(struct ImBuf *ibuf, const float value);
-/* This should not be here, really,
- * we needed it for operating on render data, IMB_rectfill_area calls it. */
+/**
+ * This should not be here, really,
+ * we needed it for operating on render data, #IMB_rectfill_area calls it.
+ */
void buf_rectfill_area(unsigned char *rect,
float *rectf,
int width,
@@ -727,23 +854,34 @@ void buf_rectfill_area(unsigned char *rect,
int x2,
int y2);
-/* exported for image tools in blender, to quickly allocate 32 bits rect */
+/**
+ * Exported for image tools in blender, to quickly allocate 32 bits rect.
+ */
void *imb_alloc_pixels(
unsigned int x, unsigned int y, unsigned int channels, size_t typesize, const char *name);
bool imb_addrectImBuf(struct ImBuf *ibuf);
+/**
+ * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
+ */
void imb_freerectImBuf(struct ImBuf *ibuf);
bool imb_addrectfloatImBuf(struct ImBuf *ibuf);
+/**
+ * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
+ */
void imb_freerectfloatImBuf(struct ImBuf *ibuf);
void imb_freemipmapImBuf(struct ImBuf *ibuf);
bool imb_addtilesImBuf(struct ImBuf *ibuf);
void imb_freetilesImBuf(struct ImBuf *ibuf);
+/** Free all pixel data (associated with image size). */
void imb_freerectImbuf_all(struct ImBuf *ibuf);
-/* threaded processors */
+/**
+ * Threaded processors.
+ */
void IMB_processor_apply_threaded(
int buffer_lines,
int handle_size,
@@ -756,13 +894,48 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines,
ScanlineThreadFunc do_thread,
void *custom_data);
-void IMB_transform(struct ImBuf *src,
+/**
+ * \brief Transform modes to use for IMB_transform function.
+ *
+ * These are not flags as the combination of cropping and repeat can lead to different expectation.
+ */
+typedef enum eIMBTransformMode {
+ /** \brief Do not crop or repeat. */
+ IMB_TRANSFORM_MODE_REGULAR = 0,
+ /** \brief Crop the source buffer. */
+ IMB_TRANSFORM_MODE_CROP_SRC = 1,
+ /** \brief Wrap repeat the source buffer. Only supported in with nearest filtering. */
+ IMB_TRANSFORM_MODE_WRAP_REPEAT = 2,
+} eIMBTransformMode;
+
+/**
+ * \brief Transform source image buffer onto destination image buffer using a transform matrix.
+ *
+ * \param src Image buffer to read from.
+ * \param dst Image buffer to write to. rect or rect_float must already be initialized.
+ * - dst buffer must be a 4 channel buffers.
+ * - Only one data type buffer will be used (rect_float has priority over rect)
+ * \param mode Cropping/Wrap repeat effect to apply during transformation.
+ * \param filter Interpolation to use during sampling.
+ * \param transform_matrix Transformation matrix to use.
+ * The given matrix should transform between dst pixel space to src pixel space.
+ * One unit is one pixel.
+ * \param src_crop cropping region how to crop the source buffer. Should only be passed when mode
+ * is set to #IMB_TRANSFORM_MODE_CROP_SRC. For any other mode this should be empty.
+ *
+ * During transformation no data/color conversion will happens.
+ * When transforming between float images the number of channels of the source buffer may be
+ * between 1 and 4. When source buffer has one channel the data will be read as a gray scale value.
+ */
+void IMB_transform(const struct ImBuf *src,
struct ImBuf *dst,
- float transform_matrix[4][4],
- struct rctf *src_crop,
- const eIMBInterpolationFilterMode filter);
+ const eIMBTransformMode mode,
+ const eIMBInterpolationFilterMode filter,
+ const float transform_matrix[4][4],
+ const struct rctf *src_crop);
+
+/* FFMPEG */
-/* ffmpeg */
void IMB_ffmpeg_init(void);
const char *IMB_ffmpeg_last_error(void);
@@ -775,8 +948,17 @@ struct GPUTexture *IMB_create_gpu_texture(const char *name,
bool use_high_bitdepth,
bool use_premult,
bool limit_gl_texture_size);
+/**
+ * The `ibuf` is only here to detect the storage type. The produced texture will have undefined
+ * content. It will need to be populated by using #IMB_update_gpu_texture_sub().
+ */
struct GPUTexture *IMB_touch_gpu_texture(
const char *name, struct ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth);
+/**
+ * Will update a #GPUTexture using the content of the #ImBuf. Only one layer will be updated.
+ * Will resize the ibuf if needed.
+ * Z is the layer to update. Unused if the texture is 2D.
+ */
void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
struct ImBuf *ibuf,
int x,
@@ -788,7 +970,6 @@ void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
bool use_premult);
/**
- *
* \attention defined in stereoimbuf.c
*/
void IMB_stereo3d_write_dimensions(const char mode,
@@ -815,9 +996,15 @@ float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format,
const size_t channels,
float *rectf_left,
float *rectf_right);
+/**
+ * Left/right are always float.
+ */
struct ImBuf *IMB_stereo3d_ImBuf(struct ImageFormatData *im_format,
struct ImBuf *ibuf_left,
struct ImBuf *ibuf_right);
+/**
+ * Reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right).
+ */
void IMB_ImBufFromStereo3d(struct Stereo3dFormat *s3d,
struct ImBuf *ibuf_stereo,
struct ImBuf **r_ibuf_left,
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 9697064b445..58148743b7e 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -143,10 +143,9 @@ typedef struct ImbFormatOptions {
char quality;
} ImbFormatOptions;
-/**
- * \name Imbuf Component flags
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Component flags
* \brief These flags determine the components of an ImBuf struct.
- *
* \{ */
typedef enum eImBufFlags {
@@ -175,6 +174,11 @@ typedef enum eImBufFlags {
} eImBufFlags;
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Buffer
+ * \{ */
+
typedef struct ImBuf {
struct ImBuf *next, *prev; /** < allow lists of #ImBufs, for caches or flip-books. */
@@ -301,11 +305,14 @@ enum {
IB_PERSISTENT = (1 << 5),
};
-/**
- * \name Imbuf preset profile tags
- * \brief Some predefined color space profiles that 8 bit imbufs can represent
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Preset Profile Tags
*
+ * \brief Some predefined color space profiles that 8 bit imbufs can represent.
* \{ */
+
#define IB_PROFILE_NONE 0
#define IB_PROFILE_LINEAR_RGB 1
#define IB_PROFILE_SRGB 2
@@ -322,7 +329,7 @@ enum {
# endif /* DDS_MAKEFOURCC */
/*
- * FOURCC codes for DX compressed-texture pixel formats
+ * FOURCC codes for DX compressed-texture pixel formats.
*/
# define FOURCC_DDS (DDS_MAKEFOURCC('D', 'D', 'S', ' '))
@@ -337,13 +344,13 @@ extern const char *imb_ext_image[];
extern const char *imb_ext_movie[];
extern const char *imb_ext_audio[];
-/* image formats that can only be loaded via filepath */
+/** Image formats that can only be loaded via filepath. */
extern const char *imb_ext_image_filepath_only[];
-/**
- * \name Imbuf Color Management Flag
- * \brief Used with #ImBuf.colormanage_flag
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Color Management Flag
*
+ * \brief Used with #ImBuf.colormanage_flag
* \{ */
enum {
diff --git a/source/blender/imbuf/IMB_moviecache.h b/source/blender/imbuf/IMB_moviecache.h
index d32346a8418..156a060c621 100644
--- a/source/blender/imbuf/IMB_moviecache.h
+++ b/source/blender/imbuf/IMB_moviecache.h
@@ -70,6 +70,9 @@ void IMB_moviecache_cleanup(struct MovieCache *cache,
void *userdata),
void *userdata);
+/**
+ * Get segments of cached frames. Useful for debugging cache policies.
+ */
void IMB_moviecache_get_cache_segments(
struct MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points);
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index e1a315a0bd2..6a739002fb3 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -48,47 +48,66 @@ typedef enum ThumbSource {
THB_SOURCE_FONT,
} ThumbSource;
-/* don't generate thumbs for images bigger than this (100mb) */
+/**
+ * Don't generate thumbs for images bigger than this (100mb).
+ */
#define THUMB_SIZE_MAX (100 * 1024 * 1024)
#define PREVIEW_RENDER_DEFAULT_HEIGHT 128
#define PREVIEW_RENDER_LARGE_HEIGHT 256
-/* Note this can also be used as versioning system,
+/**
+ * Note this can also be used as versioning system,
* to force refreshing all thumbnails if e.g. we change some thumb generating code or so.
- * Only used by fonts so far. */
+ * Only used by fonts so far.
+ */
#define THUMB_DEFAULT_HASH "00000000000000000000000000000000"
-/* create thumbnail for file and returns new imbuf for thumbnail */
+/**
+ * Create thumbnail for file and returns new imbuf for thumbnail.
+ */
struct ImBuf *IMB_thumb_create(const char *path,
ThumbSize size,
ThumbSource source,
struct ImBuf *img);
-/* read thumbnail for file and returns new imbuf for thumbnail */
+/**
+ * Read thumbnail for file and returns new imbuf for thumbnail.
+ */
struct ImBuf *IMB_thumb_read(const char *path, ThumbSize size);
-/* delete all thumbs for the file */
+/**
+ * Delete all thumbs for the file.
+ */
void IMB_thumb_delete(const char *path, ThumbSize size);
-/* return the state of the thumb, needed to determine how to manage the thumb */
+/**
+ * Create the thumb if necessary and manage failed and old thumbs.
+ */
struct ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source);
-/* create the necessary dirs to store the thumbnails */
+/**
+ * Create the necessary dirs to store the thumbnails.
+ */
void IMB_thumb_makedirs(void);
-/* special function for loading a thumbnail embedded into a blend file */
+/**
+ * Special function for loading a thumbnail embedded into a blend file.
+ */
struct ImBuf *IMB_thumb_load_blend(const char *blen_path,
const char *blen_group,
const char *blen_id);
-/* special function for previewing fonts */
+/**
+ * Special function for previewing fonts.
+ */
struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y);
bool IMB_thumb_load_font_get_hash(char *r_hash);
void IMB_thumb_clear_translations(void);
void IMB_thumb_ensure_translations(void);
/* Threading */
+
void IMB_thumb_locks_acquire(void);
void IMB_thumb_locks_release(void);
void IMB_thumb_path_lock(const char *path);
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index c8f6135f330..104458ffa7a 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -22,7 +22,9 @@
#include "IMB_imbuf.h"
-/* Generic File Type */
+/* -------------------------------------------------------------------- */
+/** \name Generic File Type
+ * \{ */
struct ImBuf;
@@ -78,11 +80,19 @@ void imb_tile_cache_init(void);
void imb_tile_cache_exit(void);
void imb_loadtile(struct ImBuf *ibuf, int tx, int ty, unsigned int *rect);
+/**
+ * External free.
+ */
void imb_tile_cache_tile_free(struct ImBuf *ibuf, int tx, int ty);
+/** \} */
+
/* Type Specific Functions */
-/* png */
+/* -------------------------------------------------------------------- */
+/** \name Format: PNG (#IMB_FTYPE_PNG)
+ * \{ */
+
bool imb_is_a_png(const unsigned char *mem, const size_t size);
struct ImBuf *imb_loadpng(const unsigned char *mem,
size_t size,
@@ -90,7 +100,12 @@ struct ImBuf *imb_loadpng(const unsigned char *mem,
char colorspace[IM_MAX_SPACE]);
bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags);
-/* targa */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TARGA (#IMB_FTYPE_TGA)
+ * \{ */
+
bool imb_is_a_targa(const unsigned char *buf, const size_t size);
struct ImBuf *imb_loadtarga(const unsigned char *mem,
size_t size,
@@ -98,15 +113,28 @@ struct ImBuf *imb_loadtarga(const unsigned char *mem,
char colorspace[IM_MAX_SPACE]);
bool imb_savetarga(struct ImBuf *ibuf, const char *filepath, int flags);
-/* iris */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: IRIS (#IMB_FTYPE_IMAGIC)
+ * \{ */
+
bool imb_is_a_iris(const unsigned char *mem, const size_t size);
+/**
+ * Read in a B/W RGB or RGBA iris image file and return an image buffer.
+ */
struct ImBuf *imb_loadiris(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_saveiris(struct ImBuf *ibuf, const char *filepath, int flags);
-/* jp2 */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: JP2 (#IMB_FTYPE_JP2)
+ * \{ */
+
bool imb_is_a_jp2(const unsigned char *buf, const size_t size);
struct ImBuf *imb_load_jp2(const unsigned char *mem,
size_t size,
@@ -117,7 +145,12 @@ struct ImBuf *imb_load_jp2_filepath(const char *filepath,
char colorspace[IM_MAX_SPACE]);
bool imb_save_jp2(struct ImBuf *ibuf, const char *filepath, int flags);
-/* jpeg */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: JPEG (#IMB_FTYPE_JPG)
+ * \{ */
+
bool imb_is_a_jpeg(const unsigned char *mem, const size_t size);
bool imb_savejpeg(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
@@ -125,15 +158,26 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* bmp */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: BMP (#IMB_FTYPE_BMP)
+ * \{ */
+
bool imb_is_a_bmp(const unsigned char *buf, const size_t size);
struct ImBuf *imb_bmp_decode(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
+/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(struct ImBuf *ibuf, const char *filepath, int flags);
-/* cineon */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: CINEON (#IMB_FTYPE_CINEON)
+ * \{ */
+
bool imb_is_a_cineon(const unsigned char *buf, const size_t size);
bool imb_save_cineon(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_cineon(const unsigned char *mem,
@@ -141,7 +185,12 @@ struct ImBuf *imb_load_cineon(const unsigned char *mem,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* dpx */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: DPX (#IMB_FTYPE_DPX)
+ * \{ */
+
bool imb_is_a_dpx(const unsigned char *buf, const size_t size);
bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_dpx(const unsigned char *mem,
@@ -149,7 +198,12 @@ struct ImBuf *imb_load_dpx(const unsigned char *mem,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* hdr */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: HDR (#IMB_FTYPE_RADHDR)
+ * \{ */
+
bool imb_is_a_hdr(const unsigned char *buf, const size_t size);
struct ImBuf *imb_loadhdr(const unsigned char *mem,
size_t size,
@@ -157,13 +211,44 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
char colorspace[IM_MAX_SPACE]);
bool imb_savehdr(struct ImBuf *ibuf, const char *filepath, int flags);
-/* tiff */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TIFF (#IMB_FTYPE_TIF)
+ * \{ */
+
void imb_inittiff(void);
bool imb_is_a_tiff(const unsigned char *buf, const size_t size);
+/**
+ * Loads a TIFF file.
+ * \param mem: Memory containing the TIFF file.
+ * \param size: Size of the mem buffer.
+ * \param flags: If flags has IB_test set then the file is not actually loaded,
+ * but all other operations take place.
+ *
+ * \return A newly allocated #ImBuf structure if successful, otherwise NULL.
+ */
struct ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
void imb_loadtiletiff(
struct ImBuf *ibuf, const unsigned char *mem, size_t size, int tx, int ty, unsigned int *rect);
+/**
+ * Saves a TIFF file.
+ *
+ * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
+ * respectively) are accepted, and interpreted correctly. Note that the TIFF
+ * convention is to use pre-multiplied alpha, which can be achieved within
+ * Blender by setting "Premul" alpha handling. Other alpha conventions are
+ * not strictly correct, but are permitted anyhow.
+ *
+ * \param ibuf: Image buffer.
+ * \param filepath: Name of the TIFF file to create.
+ * \param flags: Currently largely ignored.
+ *
+ * \return 1 if the function is successful, 0 on failure.
+ */
bool imb_savetiff(struct ImBuf *ibuf, const char *filepath, int flags);
+
+/** \} */
diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h
index 556362d78c1..434750e6736 100644
--- a/source/blender/imbuf/intern/IMB_filter.h
+++ b/source/blender/imbuf/intern/IMB_filter.h
@@ -34,4 +34,7 @@ void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h);
void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h);
void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h);
+/**
+ * Result in ibuf2, scaling should be done correctly.
+ */
void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1);
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 1369f8cc0f8..197d7e6b1d5 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -93,7 +93,6 @@ void imb_freemipmapImBuf(ImBuf *ibuf)
ibuf->miptot = 0;
}
-/* any free rect frees mipmaps to be sure, creation is in render on first request */
void imb_freerectfloatImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -111,7 +110,6 @@ void imb_freerectfloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_rectfloat;
}
-/* any free rect frees mipmaps to be sure, creation is in render on first request */
void imb_freerectImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -197,7 +195,6 @@ void IMB_freezbuffloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_zbuffloat;
}
-/** Free all pixel data (associated with image size). */
void imb_freerectImbuf_all(ImBuf *ibuf)
{
imb_freerectImBuf(ibuf);
@@ -403,9 +400,10 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf)
return false;
}
-/* question; why also add zbuf? */
bool imb_addrectImBuf(ImBuf *ibuf)
{
+ /* Question; why also add ZBUF (when `planes > 32`)? */
+
if (ibuf == NULL) {
return false;
}
@@ -430,9 +428,6 @@ bool imb_addrectImBuf(ImBuf *ibuf)
return false;
}
-/**
- * \param take_ownership: When true, the buffers become owned by the resulting image.
- */
struct ImBuf *IMB_allocFromBufferOwn(
unsigned int *rect, float *rectf, unsigned int w, unsigned int h, unsigned int channels)
{
@@ -580,7 +575,6 @@ bool IMB_initImBuf(
return true;
}
-/* does no zbuffers? */
ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
{
ImBuf *ibuf2, tbuf;
@@ -669,6 +663,11 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
return ibuf2;
}
+size_t IMB_get_rect_len(const ImBuf *ibuf)
+{
+ return (size_t)ibuf->x * (size_t)ibuf->y;
+}
+
size_t IMB_get_size_in_memory(ImBuf *ibuf)
{
int a;
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index 5b9d78f5614..b44b12999bf 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -306,7 +306,6 @@ static int putShortLSB(ushort us, FILE *ofile)
return putc((us >> 8) & 0xFF, ofile);
}
-/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
{
BMPINFOHEADER infoheader;
diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c
index 02d1fe3710a..ce11e1c3f80 100644
--- a/source/blender/imbuf/intern/cache.c
+++ b/source/blender/imbuf/intern/cache.c
@@ -153,7 +153,6 @@ static void imb_global_cache_tile_unload(ImGlobalTile *gtile)
GLOBAL_CACHE.totmem -= sizeof(unsigned int) * ibuf->tilex * ibuf->tiley;
}
-/* external free */
void imb_tile_cache_tile_free(ImBuf *ibuf, int tx, int ty)
{
ImGlobalTile *gtile, lookuptile;
@@ -248,7 +247,6 @@ void imb_tile_cache_exit(void)
}
}
-/* presumed to be called when no threads are running */
void IMB_tile_cache_params(int totthread, int maxmem)
{
int a;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index c8c6f39507f..6e9e5dd3ddb 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1968,7 +1968,6 @@ static void colormanagement_transform_ex(unsigned char *byte_buffer,
IMB_colormanagement_processor_free(cm_processor);
}
-/* convert the whole buffer from specified by name color space to another */
void IMB_colormanagement_transform(float *buffer,
int width,
int height,
@@ -1981,9 +1980,6 @@ void IMB_colormanagement_transform(float *buffer,
NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
}
-/* convert the whole buffer from specified by name color space to another
- * will do threaded conversion
- */
void IMB_colormanagement_transform_threaded(float *buffer,
int width,
int height,
@@ -1996,7 +1992,6 @@ void IMB_colormanagement_transform_threaded(float *buffer,
NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
}
-/* Similar to functions above, but operates on byte buffer. */
void IMB_colormanagement_transform_byte(unsigned char *buffer,
int width,
int height,
@@ -2018,7 +2013,6 @@ void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
}
-/* Similar to above, but gets float buffer from display one. */
void IMB_colormanagement_transform_from_byte(float *float_buffer,
unsigned char *byte_buffer,
int width,
@@ -2098,9 +2092,6 @@ void IMB_colormanagement_transform_v4(float pixel[4],
IMB_colormanagement_processor_free(cm_processor);
}
-/* convert pixel from specified by descriptor color space to scene linear
- * used by performance-critical areas such as renderer and baker
- */
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
{
OCIO_ConstCPUProcessorRcPtr *processor;
@@ -2118,7 +2109,6 @@ void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpac
}
}
-/* same as above, but converts colors in opposite direction */
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
{
OCIO_ConstCPUProcessorRcPtr *processor;
@@ -2315,14 +2305,6 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
}
}
-/* Conversion between color picking role. Typically we would expect such a
- * requirements:
- * - It is approximately perceptually linear, so that the HSV numbers and
- * the HSV cube/circle have an intuitive distribution.
- * - It has the same gamut as the scene linear color space.
- * - Color picking values 0..1 map to scene linear values in the 0..1 range,
- * so that picked albedo values are energy conserving.
- */
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
{
if (!global_color_picking_state.cpu_processor_to && !global_color_picking_state.failed) {
@@ -2377,8 +2359,6 @@ void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
}
}
-/* Conversion between sRGB, for rare cases like hex color or copy/pasting
- * between UI theme and scene linear colors. */
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
{
mul_m3_v3(imbuf_rgb_to_xyz, pixel);
@@ -2393,10 +2373,6 @@ void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
mul_m3_v3(imbuf_xyz_to_rgb, pixel);
}
-/* convert pixel from scene linear to display space using default view
- * used by performance-critical areas such as color-related widgets where we want to reduce
- * amount of per-widget allocations
- */
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
@@ -2406,7 +2382,6 @@ void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManaged
}
}
-/* same as above, but converts color in opposite direction */
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_to_scene_linear_processor(display);
@@ -2468,17 +2443,6 @@ void IMB_colormanagement_imbuf_make_display_space(
colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
}
-/* prepare image buffer to be saved on disk, applying color management if needed
- * color management would be applied if image is saving as render result and if
- * file format is not expecting float buffer to be in linear space (currently
- * JPEG2000 and TIFF are such formats -- they're storing image as float but
- * file itself stores applied color space).
- *
- * Both byte and float buffers would contain applied color space, and result's
- * float_colorspace would be set to display color space. This should be checked
- * in image format write callback and if float_colorspace is not NULL, no color
- * space transformation should be applied on this buffer.
- */
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
@@ -2640,7 +2604,6 @@ void IMB_colormanagement_buffer_make_display_space(
/** \name Public Display Buffers Interfaces
* \{ */
-/* acquire display buffer for given image buffer using specified view and display settings */
unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
@@ -2738,7 +2701,6 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
return display_buffer;
}
-/* same as IMB_display_buffer_acquire but gets view and display settings from context */
unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
{
ColorManagedViewSettings *view_settings;
@@ -2899,7 +2861,6 @@ const char *IMB_colormanagement_display_get_default_name(void)
return display->name;
}
-/* used by performance-critical pixel processing areas, such as color widgets */
ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name)
{
return colormanage_display_get_named(name);
@@ -4027,19 +3988,6 @@ bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *UNUSE
return OCIO_supportGPUShader();
}
-/**
- * Configures GLSL shader for conversion from specified to
- * display color space
- *
- * Will create appropriate OCIO processor and setup GLSL shader,
- * so further 2D texture usage will use this conversion.
- *
- * When there's no need to apply transform on 2D textures, use
- * IMB_colormanagement_finish_glsl_draw().
- *
- * This is low-level function, use ED_draw_imbuf_ctx if you
- * only need to display given image buffer
- */
bool IMB_colormanagement_setup_glsl_draw_from_space(
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
@@ -4097,7 +4045,6 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
return global_gpu_state.gpu_shader_bound;
}
-/* Configures GLSL shader for conversion from scene linear to display space */
bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
float dither,
@@ -4107,10 +4054,6 @@ bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_se
view_settings, display_settings, NULL, dither, predivide, false);
}
-/**
- * Same as setup_glsl_draw_from_space,
- * but color management settings are guessing from a given context.
- */
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C,
struct ColorSpace *from_colorspace,
float dither,
@@ -4125,13 +4068,11 @@ bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C,
view_settings, display_settings, from_colorspace, dither, predivide, false);
}
-/* Same as setup_glsl_draw, but color management settings are guessing from a given context */
bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
{
return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, dither, predivide);
}
-/* Finish GLSL-based display space conversion */
void IMB_colormanagement_finish_glsl_draw(void)
{
if (global_gpu_state.gpu_shader_bound) {
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index c304ad8d8e5..6e57a8cc1b2 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -27,23 +27,11 @@
#include "BLI_math_vector.h"
#include "IMB_colormanagement_intern.h"
-/* Convert a float RGB triplet to the correct luminance weighted average.
- *
- * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
- * based on the luminance positions of the red, green, and blue primaries.
- * Given that the internal reference space may be arbitrarily set, any
- * effort to glean the luminance coefficients must be aware of the reference
- * space primaries.
- *
- * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
- */
-
float IMB_colormanagement_get_luminance(const float rgb[3])
{
return dot_v3v3(imbuf_luma_coefficients, rgb);
}
-/* Byte equivalent of IMB_colormanagement_get_luminance(). */
unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
{
float rgbf[3];
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp
index 4e4fca864a0..e471b6834ae 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.cpp
+++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp
@@ -158,7 +158,6 @@ uint BlockDXT1::evaluatePaletteNV5x(Color32 color_array[4]) const
return 3;
}
-/* Evaluate palette assuming 3 color block. */
void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
@@ -184,7 +183,6 @@ void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
color_array[3].a = 0x00;
}
-/* Evaluate palette assuming 4 color block. */
void BlockDXT1::evaluatePalette4(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
@@ -247,14 +245,12 @@ void BlockDXT1::setIndices(const int *idx)
}
}
-/** Flip DXT1 block vertically. */
inline void BlockDXT1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half DXT1 block vertically. */
inline void BlockDXT1::flip2()
{
swap(row[0], row[1]);
@@ -299,27 +295,23 @@ void AlphaBlockDXT3::decodeBlock(ColorBlock *block) const
block->color(0xF).a = (alphaF << 4) | alphaF;
}
-/** Flip DXT3 alpha block vertically. */
void AlphaBlockDXT3::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half DXT3 alpha block vertically. */
void AlphaBlockDXT3::flip2()
{
swap(row[0], row[1]);
}
-/** Flip DXT3 block vertically. */
void BlockDXT3::flip4()
{
alpha.flip4();
color.flip4();
}
-/** Flip half DXT3 block vertically. */
void BlockDXT3::flip2()
{
alpha.flip2();
@@ -458,21 +450,18 @@ void BlockDXT5::decodeBlockNV5x(ColorBlock *block) const
alpha.decodeBlock(block);
}
-/** Flip DXT5 block vertically. */
void BlockDXT5::flip4()
{
alpha.flip4();
color.flip4();
}
-/** Flip half DXT5 block vertically. */
void BlockDXT5::flip2()
{
alpha.flip2();
color.flip2();
}
-/** Decode ATI1 block. */
void BlockATI1::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
@@ -488,19 +477,16 @@ void BlockATI1::decodeBlock(ColorBlock *block) const
}
}
-/** Flip ATI1 block vertically. */
void BlockATI1::flip4()
{
alpha.flip4();
}
-/** Flip half ATI1 block vertically. */
void BlockATI1::flip2()
{
alpha.flip2();
}
-/** Decode ATI2 block. */
void BlockATI2::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
@@ -525,14 +511,12 @@ void BlockATI2::decodeBlock(ColorBlock *block) const
}
}
-/** Flip ATI2 block vertically. */
void BlockATI2::flip4()
{
x.flip4();
y.flip4();
}
-/** Flip half ATI2 block vertically. */
void BlockATI2::flip2()
{
x.flip2();
@@ -586,14 +570,12 @@ void BlockCTX1::setIndices(const int *idx)
}
}
-/** Flip CTX1 block vertically. */
inline void BlockCTX1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half CTX1 block vertically. */
inline void BlockCTX1::flip2()
{
swap(row[0], row[1]);
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
index 1fefa7c739d..eb2d5f8726c 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.h
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -69,7 +69,9 @@ struct BlockDXT1 {
uint evaluatePalette(Color32 color_array[4]) const;
uint evaluatePaletteNV5x(Color32 color_array[4]) const;
+ /** Evaluate palette assuming 3 color block. */
void evaluatePalette3(Color32 color_array[4]) const;
+ /** Evaluate palette assuming 4 color block. */
void evaluatePalette4(Color32 color_array[4]) const;
void decodeBlock(ColorBlock *block) const;
@@ -77,7 +79,9 @@ struct BlockDXT1 {
void setIndices(const int *idx);
+ /** Flip DXT1 block vertically. */
void flip4();
+ /** Flip half DXT1 block vertically. */
void flip2();
};
@@ -113,7 +117,9 @@ struct AlphaBlockDXT3 {
void decodeBlock(ColorBlock *block) const;
+ /** Flip DXT3 alpha block vertically. */
void flip4();
+ /** Flip half DXT3 alpha block vertically. */
void flip2();
};
@@ -125,7 +131,9 @@ struct BlockDXT3 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
+ /** Flip DXT3 block vertically. */
void flip4();
+ /** Flip half DXT3 block vertically. */
void flip2();
};
@@ -253,7 +261,9 @@ struct BlockDXT5 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
+ /** Flip DXT5 block vertically. */
void flip4();
+ /** Flip half DXT5 block vertically. */
void flip2();
};
@@ -261,9 +271,12 @@ struct BlockDXT5 {
struct BlockATI1 {
AlphaBlockDXT5 alpha;
+ /** Decode ATI1 block. */
void decodeBlock(ColorBlock *block) const;
+ /** Flip ATI1 block vertically. */
void flip4();
+ /** Flip half ATI1 block vertically. */
void flip2();
};
@@ -272,9 +285,12 @@ struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
+ /** Decode ATI2 block. */
void decodeBlock(ColorBlock *block) const;
+ /** Flip ATI2 block vertically. */
void flip4();
+ /** Flip half ATI2 block vertically. */
void flip2();
};
@@ -292,7 +308,9 @@ struct BlockCTX1 {
void decodeBlock(ColorBlock *block) const;
+ /** Flip CTX1 block vertically. */
void flip4();
+ /** Flip half CTX1 block vertically. */
void flip2();
};
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp
index 6974e0bf99d..0ab98c01f6f 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.cpp
+++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp
@@ -46,7 +46,6 @@ inline static uint colorDistance(Color32 c0, Color32 c1)
}
#endif
-/** Init the color block from an array of colors. */
ColorBlock::ColorBlock(const uint *linearImage)
{
for (uint i = 0; i < 16; i++) {
@@ -54,7 +53,6 @@ ColorBlock::ColorBlock(const uint *linearImage)
}
}
-/** Init the color block with the contents of the given block. */
ColorBlock::ColorBlock(const ColorBlock &block)
{
for (uint i = 0; i < 16; i++) {
@@ -62,7 +60,6 @@ ColorBlock::ColorBlock(const ColorBlock &block)
}
}
-/** Initialize this color block. */
ColorBlock::ColorBlock(const Image *img, uint x, uint y)
{
init(img, x, y);
@@ -153,7 +150,6 @@ void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
}
}
-/** Returns true if the block has a single color. */
bool ColorBlock::isSingleColor(Color32 mask /*= Color32(0xFF, 0xFF, 0xFF, 0x00) */) const
{
uint u = m_color[0].u & mask.u;
@@ -234,7 +230,6 @@ Color32 ColorBlock::averageColor() const
}
#endif
-/** Return true if the block is not fully opaque. */
bool ColorBlock::hasAlpha() const
{
for (const auto &i : m_color) {
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
index 934837bb129..1dee5c76c9e 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.h
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -35,8 +35,11 @@
/** Uncompressed 4x4 color block. */
struct ColorBlock {
ColorBlock() = default;
+ /** Init the color block from an array of colors. */
ColorBlock(const uint *linearImage);
+ /** Init the color block with the contents of the given block. */
ColorBlock(const ColorBlock &block);
+ /** Initialize this color block. */
ColorBlock(const Image *img, uint x, uint y);
void init(const Image *img, uint x, uint y);
@@ -45,7 +48,9 @@ struct ColorBlock {
void swizzle(uint x, uint y, uint z, uint w); /* 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0 */
+ /** Returns true if the block has a single color. */
bool isSingleColor(Color32 mask = Color32(0xFF, 0xFF, 0xFF, 0x00)) const;
+ /** Return true if the block is not fully opaque. */
bool hasAlpha() const;
/* Accessors */
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index b665996b18f..efa438c2af5 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -1107,8 +1107,6 @@ void DirectDrawSurface::mipmap(Image *img, uint face, uint mipmap)
}
}
-/* It was easier to copy this function from upstream than to resync.
- * This should be removed if a resync ever occurs. */
void *DirectDrawSurface::readData(uint &rsize)
{
uint header_size = 128; // sizeof(DDSHeader);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
index 381fa51f75c..343a7367f91 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.h
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -157,6 +157,10 @@ class DirectDrawSurface {
void setUserVersion(int version);
void mipmap(Image *img, uint f, uint m);
+ /**
+ * It was easier to copy this function from upstream than to resync.
+ * This should be removed if a resync ever occurs.
+ */
void *readData(uint &size);
// void mipmap(FloatImage *img, uint f, uint m);
@@ -174,7 +178,8 @@ class DirectDrawSurface {
void readBlock(ColorBlock *rgba);
private:
- Stream stream; /* Memory where DDS file resides. */
+ /** Memory where DDS file resides. */
+ Stream stream;
DDSHeader header;
};
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp
index 2acf072556a..359d6f30cdc 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.cpp
+++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp
@@ -168,7 +168,6 @@ static void FlipDXT5BlockHalf(uint8_t *block)
FlipDXT1BlockHalf(block + 8);
}
-/* Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate. */
int FlipDXTCImage(
unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data)
{
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.h b/source/blender/imbuf/intern/dds/FlipDXT.h
index d35157251bd..b4f71e4eca7 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.h
+++ b/source/blender/imbuf/intern/dds/FlipDXT.h
@@ -18,6 +18,10 @@
#include "BLI_sys_types.h"
-/* flip compressed DXT image vertically to fit OpenGL convention */
+/**
+ * Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate.
+ *
+ * Use to flip vertically to fit OpenGL convention.
+ */
int FlipDXTCImage(
unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data);
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index e6f42da1597..4841f7b5039 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -102,13 +102,11 @@ MINLINE void float_to_byte_dither_v4(
b[3] = unit_float_to_uchar_clamp(f[3]);
}
-/* Test if colorspace conversions of pixels in buffer need to take into account alpha. */
bool IMB_alpha_affects_rgb(const ImBuf *ibuf)
{
return (ibuf->flags & IB_alphamode_channel_packed) == 0;
}
-/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float(uchar *rect_to,
const float *rect_from,
int channels_from,
@@ -275,7 +273,6 @@ void IMB_buffer_byte_from_float(uchar *rect_to,
}
}
-/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float_mask(uchar *rect_to,
const float *rect_from,
int channels_from,
@@ -366,7 +363,6 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to,
}
}
-/* Byte to float pixels, input and output 4-channel RGBA. */
void IMB_buffer_float_from_byte(float *rect_to,
const uchar *rect_from,
int profile_to,
@@ -386,7 +382,7 @@ void IMB_buffer_float_from_byte(float *rect_to,
/* RGBA input */
for (y = 0; y < height; y++) {
- const uchar *from = rect_from + stride_from * y * 4;
+ const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
@@ -426,7 +422,6 @@ void IMB_buffer_float_from_byte(float *rect_to,
}
}
-/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float(float *rect_to,
const float *rect_from,
int channels_from,
@@ -592,7 +587,6 @@ void IMB_buffer_float_from_float_threaded(float *rect_to,
}
}
-/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float_mask(float *rect_to,
const float *rect_from,
int channels_from,
@@ -646,7 +640,6 @@ void IMB_buffer_float_from_float_mask(float *rect_to,
}
}
-/* byte to byte pixels, input and output 4-channel RGBA */
void IMB_buffer_byte_from_byte(uchar *rect_to,
const uchar *rect_from,
int profile_to,
@@ -791,17 +784,14 @@ void IMB_float_from_rect(ImBuf *ibuf)
*/
rect_float = ibuf->rect_float;
if (rect_float == NULL) {
- size_t size;
-
- size = ((size_t)ibuf->x) * ibuf->y;
- size = sizeof(float[4]) * size;
- ibuf->channels = 4;
-
+ const size_t size = IMB_get_rect_len(ibuf) * sizeof(float[4]);
rect_float = MEM_callocN(size, "IMB_float_from_rect");
if (rect_float == NULL) {
return;
}
+
+ ibuf->channels = 4;
}
/* first, create float buffer in non-linear space */
@@ -837,7 +827,6 @@ void IMB_float_from_rect(ImBuf *ibuf)
/** \name Color to Grayscale
* \{ */
-/* no profile conversion */
void IMB_color_to_bw(ImBuf *ibuf)
{
float *rct_fl = ibuf->rect_float;
@@ -845,13 +834,13 @@ void IMB_color_to_bw(ImBuf *ibuf)
size_t i;
if (rct_fl) {
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += 4) {
rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
}
}
if (rct) {
- for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
}
}
@@ -892,7 +881,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
if (rct) {
float rgb[3];
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
rgb_uchar_to_float(rgb, rct);
rgb_to_hsv_v(rgb, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
@@ -901,7 +890,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
}
if (rct_fl) {
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += 4) {
rgb_to_hsv_v(rct_fl, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
}
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 343c8cd8f64..324bc9806c1 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -420,12 +420,6 @@ static int check_pixel_assigned(
return res;
}
-/**
- * if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
- *
- * When a mask is given, only effect pixels with a mask value of 1,
- * defined as #BAKE_MASK_MARGIN in rendercore.c
- */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
{
const int width = ibuf->x;
@@ -557,7 +551,6 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
}
}
-/* threadsafe version, only recreates existing maps */
void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
{
ImBuf *hbuf = ibuf;
@@ -594,7 +587,6 @@ void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
}
}
-/* frees too (if there) and recreates new data */
void IMB_makemipmap(ImBuf *ibuf, int use_filter)
{
ImBuf *hbuf = ibuf;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 0ec1e4c19d8..23c4c53d602 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -40,7 +40,6 @@
#include "IMB_imbuf_types.h"
#include <math.h>
-/* Only this one is used liberally here, and in imbuf */
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
{
size_t size;
@@ -76,7 +75,8 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
}
}
-static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
+static void pixel_from_buffer(
+ const struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
{
size_t offset = ((size_t)ibuf->x) * y * 4 + 4 * x;
@@ -95,7 +95,7 @@ static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **
* \{ */
void bicubic_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
BLI_bicubic_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
@@ -105,7 +105,7 @@ void bicubic_interpolation_color(
}
}
-void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void bicubic_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -126,16 +126,16 @@ void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
/** \name Bi-Linear Interpolation
* \{ */
-BLI_INLINE void bilinear_interpolation_color_fl(
- struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+void bilinear_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
{
BLI_assert(outF);
BLI_assert(in->rect_float);
BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
}
-BLI_INLINE void bilinear_interpolation_color_char(
- struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+void bilinear_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
BLI_assert(outI);
BLI_assert(in->rect);
@@ -143,7 +143,7 @@ BLI_INLINE void bilinear_interpolation_color_char(
}
void bilinear_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
@@ -156,12 +156,8 @@ void bilinear_interpolation_color(
/* function assumes out to be zero'ed, only does RGBA */
/* BILINEAR INTERPOLATION */
-/* Note about wrapping, the u/v still needs to be within the image bounds,
- * just the interpolation is wrapped.
- * This the same as bilinear_interpolation_color except it wraps
- * rather than using empty and emptyI. */
void bilinear_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
float *row1, *row2, *row3, *row4, a, b;
unsigned char *row1I, *row2I, *row3I, *row4I;
@@ -232,7 +228,7 @@ void bilinear_interpolation_color_wrap(
}
}
-void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void bilinear_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -253,9 +249,8 @@ void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, i
/** \name Nearest Interpolation
* \{ */
-/* functions assumes out to be zero'ed, only does RGBA */
-BLI_INLINE void nearest_interpolation_color_char(
- struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+void nearest_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
BLI_assert(outI);
BLI_assert(in->rect);
@@ -269,7 +264,7 @@ BLI_INLINE void nearest_interpolation_color_char(
return;
}
- const size_t offset = (in->x * y1 + x1) * 4;
+ const size_t offset = ((size_t)in->x * y1 + x1) * 4;
const unsigned char *dataI = (unsigned char *)in->rect + offset;
outI[0] = dataI[0];
outI[1] = dataI[1];
@@ -277,8 +272,8 @@ BLI_INLINE void nearest_interpolation_color_char(
outI[3] = dataI[3];
}
-BLI_INLINE void nearest_interpolation_color_fl(
- struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+void nearest_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
{
BLI_assert(outF);
BLI_assert(in->rect_float);
@@ -292,13 +287,13 @@ BLI_INLINE void nearest_interpolation_color_fl(
return;
}
- const size_t offset = (in->x * y1 + x1) * 4;
+ const size_t offset = ((size_t)in->x * y1 + x1) * 4;
const float *dataF = in->rect_float + offset;
copy_v4_v4(outF, dataF);
}
void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
nearest_interpolation_color_fl(in, outI, outF, u, v);
@@ -309,7 +304,7 @@ void nearest_interpolation_color(
}
void nearest_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
const float *dataF;
unsigned char *dataI;
@@ -347,7 +342,7 @@ void nearest_interpolation_color_wrap(
}
}
-void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void nearest_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -362,146 +357,6 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
nearest_interpolation_color(in, outI, outF, u, v);
}
-/* -------------------------------------------------------------------- */
-/** \name Image transform
- * \{ */
-typedef struct TransformUserData {
- ImBuf *src;
- ImBuf *dst;
- float start_uv[2];
- float add_x[2];
- float add_y[2];
- rctf src_crop;
-} TransformUserData;
-
-static void imb_transform_calc_start_uv(const float transform_matrix[4][4], float r_start_uv[2])
-{
- float r_start_uv_temp[3];
- float orig[3];
- zero_v3(orig);
- mul_v3_m4v3(r_start_uv_temp, transform_matrix, orig);
- copy_v2_v2(r_start_uv, r_start_uv_temp);
-}
-
-static void imb_transform_calc_add_x(const float transform_matrix[4][4],
- const float start_uv[2],
- const int width,
- float r_add_x[2])
-{
- float r_add_x_temp[3];
- float uv_max_x[3];
- zero_v3(uv_max_x);
- uv_max_x[0] = width;
- uv_max_x[1] = 0.0f;
- mul_v3_m4v3(r_add_x_temp, transform_matrix, uv_max_x);
- sub_v2_v2(r_add_x_temp, start_uv);
- mul_v2_fl(r_add_x_temp, 1.0f / width);
- copy_v2_v2(r_add_x, r_add_x_temp);
-}
-
-static void imb_transform_calc_add_y(const float transform_matrix[4][4],
- const float start_uv[2],
- const int height,
- float r_add_y[2])
-{
- float r_add_y_temp[3];
- float uv_max_y[3];
- zero_v3(uv_max_y);
- uv_max_y[0] = 0.0f;
- uv_max_y[1] = height;
- mul_v3_m4v3(r_add_y_temp, transform_matrix, uv_max_y);
- sub_v2_v2(r_add_y_temp, start_uv);
- mul_v2_fl(r_add_y_temp, 1.0f / height);
- copy_v2_v2(r_add_y, r_add_y_temp);
-}
-
-typedef void (*InterpolationColorFunction)(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
-BLI_INLINE void imb_transform_scanlines(const TransformUserData *user_data,
- int scanline,
- InterpolationColorFunction interpolation)
-{
- const int width = user_data->dst->x;
-
- float uv[2];
- madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
-
- unsigned char *outI = NULL;
- float *outF = NULL;
- pixel_from_buffer(user_data->dst, &outI, &outF, 0, scanline);
-
- for (int xi = 0; xi < width; xi++) {
- if (uv[0] >= user_data->src_crop.xmin && uv[0] < user_data->src_crop.xmax &&
- uv[1] >= user_data->src_crop.ymin && uv[1] < user_data->src_crop.ymax) {
- interpolation(user_data->src, outI, outF, uv[0], uv[1]);
- }
- add_v2_v2(uv, user_data->add_x);
- if (outI) {
- outI += 4;
- }
- if (outF) {
- outF += 4;
- }
- }
-}
-
-static void imb_transform_nearest_scanlines(void *custom_data, int scanline)
-{
- const TransformUserData *user_data = custom_data;
- InterpolationColorFunction interpolation = NULL;
- if (user_data->dst->rect_float) {
- interpolation = nearest_interpolation_color_fl;
- }
- else {
- interpolation = nearest_interpolation_color_char;
- }
- imb_transform_scanlines(user_data, scanline, interpolation);
-}
-
-static void imb_transform_bilinear_scanlines(void *custom_data, int scanline)
-{
- const TransformUserData *user_data = custom_data;
- InterpolationColorFunction interpolation = NULL;
- if (user_data->dst->rect_float) {
- interpolation = bilinear_interpolation_color_fl;
- }
- else if (user_data->dst->rect) {
- interpolation = bilinear_interpolation_color_char;
- }
- imb_transform_scanlines(user_data, scanline, interpolation);
-}
-
-static ScanlineThreadFunc imb_transform_scanline_func(const eIMBInterpolationFilterMode filter)
-{
- ScanlineThreadFunc scanline_func = NULL;
- switch (filter) {
- case IMB_FILTER_NEAREST:
- scanline_func = imb_transform_nearest_scanlines;
- break;
- case IMB_FILTER_BILINEAR:
- scanline_func = imb_transform_bilinear_scanlines;
- break;
- }
- return scanline_func;
-}
-
-void IMB_transform(struct ImBuf *src,
- struct ImBuf *dst,
- float transform_matrix[4][4],
- struct rctf *src_crop,
- const eIMBInterpolationFilterMode filter)
-{
- TransformUserData user_data;
- user_data.src = src;
- user_data.dst = dst;
- user_data.src_crop = *src_crop;
- imb_transform_calc_start_uv(transform_matrix, user_data.start_uv);
- imb_transform_calc_add_x(transform_matrix, user_data.start_uv, src->x, user_data.add_x);
- imb_transform_calc_add_y(transform_matrix, user_data.start_uv, src->y, user_data.add_y);
- ScanlineThreadFunc scanline_func = imb_transform_scanline_func(filter);
- IMB_processor_apply_threaded_scanlines(dst->y, scanline_func, &user_data);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -643,7 +498,6 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float b
/** \name Sample Pixel
* \{ */
-/* Sample pixel of image using NEAREST method. */
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4])
{
if (ibuf->rect_float) {
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index 6a7ad87d53d..dc714e6e85a 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -251,12 +251,6 @@ bool imb_is_a_iris(const uchar *mem, size_t size)
return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC));
}
-/*
- * longimagedata -
- * read in a B/W RGB or RGBA iris image file and return a
- * pointer to an array of ints.
- */
-
struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
uint *base, *lptr = NULL;
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 8923ba98e08..f290ab1a060 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -268,6 +268,7 @@ void IMB_moviecache_destruct(void)
{
if (limitor) {
delete_MEM_CacheLimiter(limitor);
+ limitor = NULL;
}
}
@@ -495,7 +496,6 @@ void IMB_moviecache_cleanup(MovieCache *cache,
}
}
-/* get segments of cached frames. useful for debugging cache policies */
void IMB_moviecache_get_cache_segments(
MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points)
{
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index adf09f8dda8..e1b9853ac21 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -327,10 +327,6 @@ static half float_to_half_safe(const float value)
extern "C" {
-/**
- * Test presence of OpenEXR file.
- * \param mem: pointer to loaded OpenEXR bitstream
- */
bool imb_is_a_openexr(const unsigned char *mem, const size_t size)
{
/* No define is exposed for this size. */
@@ -781,9 +777,6 @@ static void imb_exr_insert_view_name(char *name_full, const char *passname, cons
}
}
-/* adds flattened ExrChannels */
-/* xstride, ystride and rect can be done in set_channel too, for tile writing */
-/* passname does not include view */
void IMB_exr_add_channel(void *handle,
const char *layname,
const char *passname,
@@ -840,7 +833,6 @@ void IMB_exr_add_channel(void *handle,
BLI_addtail(&data->channels, echan);
}
-/* used for output files (from RenderResult) (single and multilayer, single and multiview) */
bool IMB_exr_begin_write(void *handle,
const char *filename,
int width,
@@ -896,8 +888,6 @@ bool IMB_exr_begin_write(void *handle,
return (data->ofile != nullptr);
}
-/* only used for writing temp. render results (not image files)
- * (FSA and Save Buffers) */
void IMB_exrtile_begin_write(
void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
{
@@ -963,7 +953,6 @@ void IMB_exrtile_begin_write(
}
}
-/* read from file */
bool IMB_exr_begin_read(
void *handle, const char *filename, int *width, int *height, const bool parse_channels)
{
@@ -1024,8 +1013,6 @@ bool IMB_exr_begin_read(
return true;
}
-/* still clumsy name handling, layers/channels can be ordered as list in list later */
-/* passname here is the raw channel name without the layer */
void IMB_exr_set_channel(
void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{
@@ -1167,8 +1154,6 @@ void IMB_exr_write_channels(void *handle)
}
}
-/* temporary function, used for FSA and Save Buffers */
-/* called once per tile * view */
void IMB_exrtile_write_channels(
void *handle, int partx, int party, int level, const char *viewname, bool empty)
{
@@ -1937,8 +1922,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
file = new MultiPartInputFile(*membuf);
Box2i dw = file->header(0).dataWindow();
- const int width = dw.max.x - dw.min.x + 1;
- const int height = dw.max.y - dw.min.y + 1;
+ const size_t width = dw.max.x - dw.min.x + 1;
+ const size_t height = dw.max.y - dw.min.y + 1;
// printf("OpenEXR-load: image data window %d %d %d %d\n",
// dw.min.x, dw.min.y, dw.max.x, dw.max.y);
@@ -2001,8 +1986,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
const bool has_luma = exr_has_luma(*file);
FrameBuffer frameBuffer;
float *first;
- int xstride = sizeof(float[4]);
- int ystride = -xstride * width;
+ size_t xstride = sizeof(float[4]);
+ size_t ystride = -xstride * width;
imb_addrectfloatImBuf(ibuf);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index 940715690a7..14336620926 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -32,6 +32,10 @@ extern "C" {
void imb_initopenexr(void);
void imb_exitopenexr(void);
+/**
+ * Test presence of OpenEXR file.
+ * \param mem: pointer to loaded OpenEXR bit-stream.
+ */
bool imb_is_a_openexr(const unsigned char *mem, const size_t size);
bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags);
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 82a5d161ded..6694c32820b 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -23,7 +23,7 @@
#pragma once
-/* experiment with more advanced exr api */
+/* Experiment with more advanced EXR API. */
/* XXX layer+pass name max 64? */
/* This api also supports max 8 channels per pass now. easy to fix! */
@@ -41,6 +41,12 @@ struct StampData;
void *IMB_exr_get_handle(void);
void *IMB_exr_get_handle_name(const char *name);
+
+/**
+ * Adds flattened #ExrChannel's
+ * `xstride`, `ystride` and `rect` can be done in set_channel too, for tile writing.
+ * \param passname: Does not include view.
+ */
void IMB_exr_add_channel(void *handle,
const char *layname,
const char *passname,
@@ -50,17 +56,32 @@ void IMB_exr_add_channel(void *handle,
float *rect,
bool use_half_float);
+/**
+ * Read from file.
+ */
bool IMB_exr_begin_read(
void *handle, const char *filename, int *width, int *height, const bool parse_channels);
+/**
+ * Used for output files (from #RenderResult) (single and multi-layer, single and multi-view).
+ */
bool IMB_exr_begin_write(void *handle,
const char *filename,
int width,
int height,
int compress,
const struct StampData *stamp);
+/**
+ * Only used for writing temp. render results (not image files)
+ * (FSA and Save Buffers).
+ */
void IMB_exrtile_begin_write(
void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
+/**
+ * Still clumsy name handling, layers/channels can be ordered as list in list later.
+ *
+ * \param passname: Here is the raw channel name without the layer.
+ */
void IMB_exr_set_channel(void *handle,
const char *layname,
const char *passname,
@@ -74,6 +95,10 @@ float *IMB_exr_channel_rect(void *handle,
void IMB_exr_read_channels(void *handle);
void IMB_exr_write_channels(void *handle);
+/**
+ * Temporary function, used for FSA and Save Buffers.
+ * called once per `tile * view`.
+ */
void IMB_exrtile_write_channels(
void *handle, int partx, int party, int level, const char *viewname, bool empty);
void IMB_exr_clear_channels(void *handle);
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 4b5d68b9c13..1d81ee768e9 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -251,9 +251,6 @@ static void rect_crop_16bytes(void **buf_p, const int size_src[2], const rcti *c
*buf_p = (void *)MEM_reallocN(*buf_p, sizeof(uint[4]) * size_dst[0] * size_dst[1]);
}
-/**
- * In-place image crop.
- */
void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
{
const int size_src[2] = {
@@ -302,9 +299,6 @@ static void rect_realloc_16bytes(void **buf_p, const uint size[2])
*buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__);
}
-/**
- * In-place size setting (caller must fill in buffer contents).
- */
void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
{
BLI_assert(size[0] > 0 && size[1] > 0);
@@ -1070,11 +1064,6 @@ void IMB_rectblend_threaded(ImBuf *dbuf,
}
}
-/**
- * Replace pixels of entire image with solid color.
- * \param ibuf: An image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
- */
void IMB_rectfill(ImBuf *drect, const float col[4])
{
int num;
@@ -1107,15 +1096,6 @@ void IMB_rectfill(ImBuf *drect, const float col[4])
}
}
-/**
- * Replace pixels of image area with solid color.
- * \param ibuf: an image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
- * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
- * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
- * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
- * order the area between x1 and x2, and y1 and y2 is filled.
- */
void IMB_rectfill_area_replace(
const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
{
@@ -1273,21 +1253,6 @@ void buf_rectfill_area(unsigned char *rect,
}
}
-/**
- * Blend pixels of image area with solid color.
- *
- * For images with `uchar` buffer use color matching image color-space.
- * For images with float buffer use color display color-space.
- * If display color-space can not be referenced, use color in SRGB color-space.
- *
- * \param ibuf: an image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color.
- * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
- * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
- * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
- * order the area between x1 and x2, and y1 and y2 is filled.
- * \param display: color-space reference for display space.
- */
void IMB_rectfill_area(ImBuf *ibuf,
const float col[4],
int x1,
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 1c4b7af6ef1..a18ba6748de 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -372,7 +372,6 @@ MINLINE void premul_ushort_to_straight_uchar(unsigned char *result, const unsign
}
}
-/* result in ibuf2, scaling should be done correctly */
void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
{
int x, y;
@@ -912,7 +911,7 @@ static ImBuf *scaledownx(struct ImBuf *ibuf, int newx)
{
const int do_rect = (ibuf->rect != NULL);
const int do_float = (ibuf->rect_float != NULL);
- const size_t rect_size = ibuf->x * ibuf->y * 4;
+ const size_t rect_size = IMB_get_rect_len(ibuf) * 4;
uchar *rect, *_newrect, *newrect;
float *rectf, *_newrectf, *newrectf;
@@ -1053,7 +1052,7 @@ static ImBuf *scaledowny(struct ImBuf *ibuf, int newy)
{
const int do_rect = (ibuf->rect != NULL);
const int do_float = (ibuf->rect_float != NULL);
- const size_t rect_size = ibuf->x * ibuf->y * 4;
+ const size_t rect_size = IMB_get_rect_len(ibuf) * 4;
uchar *rect, *_newrect, *newrect;
float *rectf, *_newrectf, *newrectf;
@@ -1661,9 +1660,6 @@ static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy)
}
}
-/**
- * Return true if \a ibuf is modified.
- */
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
@@ -1709,9 +1705,6 @@ struct imbufRGBA {
float r, g, b, a;
};
-/**
- * Return true if \a ibuf is modified.
- */
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index d3c91b55f22..dae2604802f 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -757,7 +757,6 @@ float *IMB_stereo3d_from_rectf(ImageFormatData *im_format,
return r_rectf;
}
-/* left/right are always float */
ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
{
ImBuf *ibuf_stereo = NULL;
@@ -1275,7 +1274,6 @@ static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
/** \name Preparing To Call The Read Functions
* \{ */
-/* reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right) */
void IMB_ImBufFromStereo3d(Stereo3dFormat *s3d,
ImBuf *ibuf_stereo3d,
ImBuf **r_ibuf_left,
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index aa1da65253d..c39ce2e9a2a 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -523,7 +523,6 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
}
-/* read thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
{
char thumb[FILE_MAX];
@@ -540,7 +539,6 @@ ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
return img;
}
-/* delete all thumbs for the file */
void IMB_thumb_delete(const char *path, ThumbSize size)
{
char thumb[FILE_MAX];
@@ -559,7 +557,6 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
}
}
-/* create the thumb if necessary and manage failed and old thumbs */
ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
{
char thumb_path[FILE_MAX];
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 623c00fa670..6ad373845fc 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -553,15 +553,6 @@ void imb_inittiff(void)
}
}
-/**
- * Loads a TIFF file.
- * \param mem: Memory containing the TIFF file.
- * \param size: Size of the mem buffer.
- * \param flags: If flags has IB_test set then the file is not actually loaded,
- * but all other operations take place.
- *
- * \return A newly allocated #ImBuf structure if successful, otherwise NULL.
- */
ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
@@ -744,21 +735,6 @@ void imb_loadtiletiff(
/** \name Save TIFF
* \{ */
-/**
- * Saves a TIFF file.
- *
- * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
- * respectively) are accepted, and interpreted correctly. Note that the TIFF
- * convention is to use pre-multiplied alpha, which can be achieved within
- * Blender by setting "Premul" alpha handling. Other alpha conventions are
- * not strictly correct, but are permitted anyhow.
- *
- * \param ibuf: Image buffer.
- * \param name: Name of the TIFF file to create.
- * \param flags: Currently largely ignored.
- *
- * \return 1 if the function is successful, 0 on failure.
- */
bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
{
TIFF *image = NULL;
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
new file mode 100644
index 00000000000..e1c451a8412
--- /dev/null
+++ b/source/blender/imbuf/intern/transform.cc
@@ -0,0 +1,604 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup imbuf
+ */
+
+#include <array>
+#include <type_traits>
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+namespace blender::imbuf::transform {
+
+struct TransformUserData {
+ /** \brief Source image buffer to read from. */
+ const ImBuf *src;
+ /** \brief Destination image buffer to write to. */
+ ImBuf *dst;
+ /** \brief UV coordinates at the origin (0,0) in source image space. */
+ float start_uv[2];
+
+ /**
+ * \brief delta UV coordinates along the source image buffer, when moving a single pixel in the X
+ * axis of the dst image buffer.
+ */
+ float add_x[2];
+
+ /**
+ * \brief delta UV coordinate along the source image buffer, when moving a single pixel in the Y
+ * axes of the dst image buffer.
+ */
+ float add_y[2];
+
+ /**
+ * \brief Cropping region in source image pixel space.
+ */
+ rctf src_crop;
+
+ /**
+ * \brief Initialize the start_uv, add_x and add_y fields based on the given transform matrix.
+ */
+ void init(const float transform_matrix[4][4])
+ {
+ init_start_uv(transform_matrix);
+ init_add_x(transform_matrix);
+ init_add_y(transform_matrix);
+ }
+
+ private:
+ void init_start_uv(const float transform_matrix[4][4])
+ {
+ float start_uv_v3[3];
+ float orig[3];
+ zero_v3(orig);
+ mul_v3_m4v3(start_uv_v3, transform_matrix, orig);
+ copy_v2_v2(start_uv, start_uv_v3);
+ }
+
+ void init_add_x(const float transform_matrix[4][4])
+ {
+ const int width = src->x;
+ float add_x_v3[3];
+ float uv_max_x[3];
+ zero_v3(uv_max_x);
+ uv_max_x[0] = width;
+ uv_max_x[1] = 0.0f;
+ mul_v3_m4v3(add_x_v3, transform_matrix, uv_max_x);
+ sub_v2_v2(add_x_v3, start_uv);
+ mul_v2_fl(add_x_v3, 1.0f / width);
+ copy_v2_v2(add_x, add_x_v3);
+ }
+
+ void init_add_y(const float transform_matrix[4][4])
+ {
+ const int height = src->y;
+ float add_y_v3[3];
+ float uv_max_y[3];
+ zero_v3(uv_max_y);
+ uv_max_y[0] = 0.0f;
+ uv_max_y[1] = height;
+ mul_v3_m4v3(add_y_v3, transform_matrix, uv_max_y);
+ sub_v2_v2(add_y_v3, start_uv);
+ mul_v2_fl(add_y_v3, 1.0f / height);
+ copy_v2_v2(add_y, add_y_v3);
+ }
+};
+
+/**
+ * \brief Base class for source discarding.
+ *
+ * The class decides if a specific uv coordinate from the source buffer should be ignored.
+ * This is used to mix multiple images over a single output buffer. Discarded pixels will
+ * not change the output buffer.
+ */
+class BaseDiscard {
+ public:
+ virtual ~BaseDiscard() = default;
+
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ */
+ virtual bool should_discard(const TransformUserData &user_data, const float uv[2]) = 0;
+};
+
+/**
+ * \brief Crop uv-coordinates that are outside the user data src_crop rect.
+ */
+class CropSource : public BaseDiscard {
+ public:
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ *
+ * Uses user_data.src_crop to determine if the uv coordinate should be skipped.
+ */
+ bool should_discard(const TransformUserData &user_data, const float uv[2]) override
+ {
+ return uv[0] < user_data.src_crop.xmin || uv[0] >= user_data.src_crop.xmax ||
+ uv[1] < user_data.src_crop.ymin || uv[1] >= user_data.src_crop.ymax;
+ }
+};
+
+/**
+ * \brief Discard that does not discard anything.
+ */
+class NoDiscard : public BaseDiscard {
+ public:
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ *
+ * Will never discard any pixels.
+ */
+ bool should_discard(const TransformUserData &UNUSED(user_data),
+ const float UNUSED(uv[2])) override
+ {
+ return false;
+ }
+};
+
+/**
+ * \brief Pointer to a pixel to write to in serial.
+ */
+template<
+ /**
+ * \brief Kind of buffer.
+ * Possible options: float, unsigned char.
+ */
+ typename StorageType = float,
+
+ /**
+ * \brief Number of channels of a single pixel.
+ */
+ int NumChannels = 4>
+class PixelPointer {
+ public:
+ static const int ChannelLen = NumChannels;
+
+ private:
+ StorageType *pointer;
+
+ public:
+ void init_pixel_pointer(const ImBuf *image_buffer, int x, int y)
+ {
+ const size_t offset = (y * (size_t)image_buffer->x + x) * NumChannels;
+
+ if constexpr (std::is_same_v<StorageType, float>) {
+ pointer = image_buffer->rect_float + offset;
+ }
+ else if constexpr (std::is_same_v<StorageType, unsigned char>) {
+ pointer = const_cast<unsigned char *>(
+ static_cast<const unsigned char *>(static_cast<const void *>(image_buffer->rect)) +
+ offset);
+ }
+ else {
+ pointer = nullptr;
+ }
+ }
+
+ /**
+ * \brief Get pointer to the current pixel to write to.
+ */
+ StorageType *get_pointer()
+ {
+ return pointer;
+ }
+
+ void increase_pixel_pointer()
+ {
+ pointer += NumChannels;
+ }
+};
+
+/**
+ * \brief Wrapping mode for the uv coordinates.
+ *
+ * Subclasses have the ability to change the UV coordinates when sampling the source buffer.
+ */
+class BaseUVWrapping {
+ public:
+ /**
+ * \brief modify the given u coordinate.
+ */
+ virtual float modify_u(const ImBuf *source_buffer, float u) = 0;
+
+ /**
+ * \brief modify the given v coordinate.
+ */
+ virtual float modify_v(const ImBuf *source_buffer, float v) = 0;
+};
+
+/**
+ * \brief UVWrapping method that does not modify the UV coordinates.
+ */
+class PassThroughUV : public BaseUVWrapping {
+ public:
+ float modify_u(const ImBuf *UNUSED(source_buffer), float u) override
+ {
+ return u;
+ }
+
+ float modify_v(const ImBuf *UNUSED(source_buffer), float v) override
+ {
+ return v;
+ }
+};
+
+/**
+ * \brief UVWrapping method that wrap repeats the UV coordinates.
+ */
+class WrapRepeatUV : public BaseUVWrapping {
+ public:
+ float modify_u(const ImBuf *source_buffer, float u) override
+
+ {
+ int x = (int)floor(u);
+ x = x % source_buffer->x;
+ if (x < 0) {
+ x += source_buffer->x;
+ }
+ return x;
+ }
+
+ float modify_v(const ImBuf *source_buffer, float v) override
+ {
+ int y = (int)floor(v);
+ y = y % source_buffer->y;
+ if (y < 0) {
+ y += source_buffer->y;
+ }
+ return y;
+ }
+};
+
+/**
+ * \brief Read a sample from an image buffer.
+ *
+ * A sampler can read from an image buffer.
+ *
+ */
+template<
+ /** \brief Interpolation mode to use when sampling. */
+ eIMBInterpolationFilterMode Filter,
+
+ /** \brief storage type of a single pixel channel (unsigned char or float). */
+ typename StorageType,
+ /**
+ * \brief number of channels if the image to read.
+ *
+ * Must match the actual channels of the image buffer that is sampled.
+ */
+ int NumChannels,
+ /**
+ * \brief Wrapping method to perform
+ *
+ * Should be a subclass of BaseUVWrapper
+ */
+ typename UVWrapping>
+class Sampler {
+ UVWrapping uv_wrapper;
+
+ public:
+ using ChannelType = StorageType;
+ static const int ChannelLen = NumChannels;
+ using SampleType = std::array<StorageType, NumChannels>;
+
+ void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample)
+ {
+ if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
+ NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_NEAREST &&
+ std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_BILINEAR &&
+ std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
+ if constexpr (std::is_same_v<UVWrapping, WrapRepeatUV>) {
+ BLI_bilinear_interpolation_wrap_fl(
+ source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true);
+ }
+ else {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ BLI_bilinear_interpolation_fl(source->rect_float,
+ &r_sample[0],
+ source->x,
+ source->y,
+ NumChannels,
+ wrapped_u,
+ wrapped_v);
+ }
+ }
+ else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, float>) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ sample_nearest_float(source, wrapped_u, wrapped_v, r_sample);
+ }
+ else {
+ /* Unsupported sampler. */
+ BLI_assert_unreachable();
+ }
+ }
+
+ private:
+ void sample_nearest_float(const ImBuf *source,
+ const float u,
+ const float v,
+ SampleType &r_sample)
+ {
+ BLI_STATIC_ASSERT(std::is_same_v<StorageType, float>);
+
+ /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+ int x1 = (int)(u);
+ int y1 = (int)(v);
+
+ /* Break when sample outside image is requested. */
+ if (x1 < 0 || x1 >= source->x || y1 < 0 || y1 >= source->y) {
+ for (int i = 0; i < NumChannels; i++) {
+ r_sample[i] = 0.0f;
+ }
+ return;
+ }
+
+ const size_t offset = ((size_t)source->x * y1 + x1) * NumChannels;
+ const float *dataF = source->rect_float + offset;
+ for (int i = 0; i < NumChannels; i++) {
+ r_sample[i] = dataF[i];
+ }
+ }
+};
+
+/**
+ * \brief Change the number of channels and store it.
+ *
+ * Template class to convert and store a sample in a PixelPointer.
+ * It supports:
+ * - 4 channel unsigned char -> 4 channel unsigned char.
+ * - 4 channel float -> 4 channel float.
+ * - 3 channel float -> 4 channel float.
+ * - 2 channel float -> 4 channel float.
+ * - 1 channel float -> 4 channel float.
+ */
+template<typename StorageType, int SourceNumChannels, int DestinationNumChannels>
+class ChannelConverter {
+ public:
+ using SampleType = std::array<StorageType, SourceNumChannels>;
+ using PixelType = PixelPointer<StorageType, DestinationNumChannels>;
+
+ /**
+ * \brief Convert the number of channels of the given sample to match the pixel pointer and store
+ * it at the location the pixel_pointer points at.
+ */
+ void convert_and_store(const SampleType &sample, PixelType &pixel_pointer)
+ {
+ if constexpr (std::is_same_v<StorageType, unsigned char>) {
+ BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels.");
+ BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels.");
+
+ copy_v4_v4_uchar(pixel_pointer.get_pointer(), &sample[0]);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
+ DestinationNumChannels == 4) {
+ copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[1], sample[2], 1.0f);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 2 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[1], 0.0f, 1.0f);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 1 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[0], sample[0], 1.0f);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ }
+};
+
+/**
+ * \brief Processor for a scanline.
+ */
+template<
+ /**
+ * \brief Discard function to use.
+ *
+ * \attention Should be a subclass of BaseDiscard.
+ */
+ typename Discard,
+
+ /**
+ * \brief Color interpolation function to read from the source buffer.
+ */
+ typename Sampler,
+
+ /**
+ * \brief Kernel to store to the destination buffer.
+ * Should be an PixelPointer
+ */
+ typename OutputPixelPointer>
+class ScanlineProcessor {
+ Discard discarder;
+ OutputPixelPointer output;
+ Sampler sampler;
+
+ /**
+ * \brief Channels sizzling logic to convert between the input image buffer and the output image
+ * buffer.
+ */
+ ChannelConverter<typename Sampler::ChannelType,
+ Sampler::ChannelLen,
+ OutputPixelPointer::ChannelLen>
+ channel_converter;
+
+ public:
+ /**
+ * \brief Inner loop of the transformations, processing a full scanline.
+ */
+ void process(const TransformUserData *user_data, int scanline)
+ {
+ const int width = user_data->dst->x;
+
+ float uv[2];
+ madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
+
+ output.init_pixel_pointer(user_data->dst, 0, scanline);
+ for (int xi = 0; xi < width; xi++) {
+ if (!discarder.should_discard(*user_data, uv)) {
+ typename Sampler::SampleType sample;
+ sampler.sample(user_data->src, uv[0], uv[1], sample);
+ channel_converter.convert_and_store(sample, output);
+ }
+
+ add_v2_v2(uv, user_data->add_x);
+ output.increase_pixel_pointer();
+ }
+ }
+};
+
+/**
+ * \brief callback function for threaded transformation.
+ */
+template<typename Processor> void transform_scanline_function(void *custom_data, int scanline)
+{
+ const TransformUserData *user_data = static_cast<const TransformUserData *>(custom_data);
+ Processor processor;
+ processor.process(user_data, scanline);
+}
+
+template<eIMBInterpolationFilterMode Filter,
+ typename StorageType,
+ int SourceNumChannels,
+ int DestinationNumChannels>
+ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
+
+{
+ switch (mode) {
+ case IMB_TRANSFORM_MODE_REGULAR:
+ return transform_scanline_function<
+ ScanlineProcessor<NoDiscard,
+ Sampler<Filter, StorageType, SourceNumChannels, PassThroughUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ case IMB_TRANSFORM_MODE_CROP_SRC:
+ return transform_scanline_function<
+ ScanlineProcessor<CropSource,
+ Sampler<Filter, StorageType, SourceNumChannels, PassThroughUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ case IMB_TRANSFORM_MODE_WRAP_REPEAT:
+ return transform_scanline_function<
+ ScanlineProcessor<NoDiscard,
+ Sampler<Filter, StorageType, SourceNumChannels, WrapRepeatUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+template<eIMBInterpolationFilterMode Filter>
+ScanlineThreadFunc get_scanline_function(const TransformUserData *user_data,
+ const eIMBTransformMode mode)
+{
+ const ImBuf *src = user_data->src;
+ const ImBuf *dst = user_data->dst;
+
+ if (src->channels == 4 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 4, 4>(mode);
+ }
+ if (src->channels == 3 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 3, 4>(mode);
+ }
+ if (src->channels == 2 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 2, 4>(mode);
+ }
+ if (src->channels == 1 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 1, 4>(mode);
+ }
+ return nullptr;
+}
+
+template<eIMBInterpolationFilterMode Filter>
+static void transform_threaded(TransformUserData *user_data, const eIMBTransformMode mode)
+{
+ ScanlineThreadFunc scanline_func = nullptr;
+
+ if (user_data->dst->rect_float && user_data->src->rect_float) {
+ scanline_func = get_scanline_function<Filter>(user_data, mode);
+ }
+ else if (user_data->dst->rect && user_data->src->rect) {
+ /* Number of channels is always 4 when using unsigned char buffers (sRGB + straight alpha). */
+ scanline_func = get_scanline_function<Filter, unsigned char, 4, 4>(mode);
+ }
+
+ if (scanline_func != nullptr) {
+ IMB_processor_apply_threaded_scanlines(user_data->dst->y, scanline_func, user_data);
+ }
+}
+
+} // namespace blender::imbuf::transform
+
+extern "C" {
+
+using namespace blender::imbuf::transform;
+
+void IMB_transform(const struct ImBuf *src,
+ struct ImBuf *dst,
+ const eIMBTransformMode mode,
+ const eIMBInterpolationFilterMode filter,
+ const float transform_matrix[4][4],
+ const struct rctf *src_crop)
+{
+ BLI_assert_msg(mode != IMB_TRANSFORM_MODE_CROP_SRC || src_crop != nullptr,
+ "No source crop rect given, but crop source is requested. Or source crop rect "
+ "was given, but crop source was not requested.");
+
+ TransformUserData user_data;
+ user_data.src = src;
+ user_data.dst = dst;
+ if (mode == IMB_TRANSFORM_MODE_CROP_SRC) {
+ user_data.src_crop = *src_crop;
+ }
+ user_data.init(transform_matrix);
+
+ if (filter == IMB_FILTER_NEAREST) {
+ transform_threaded<IMB_FILTER_NEAREST>(&user_data, mode);
+ }
+ else {
+ transform_threaded<IMB_FILTER_BILINEAR>(&user_data, mode);
+ }
+}
+}
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 1bb047f1317..18ed4710e78 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -98,7 +98,7 @@ const char *imb_ext_movie[] = {
".mpg2", ".vob", ".mkv", ".flv", ".divx", ".xvid", ".mxf", ".webm", NULL,
};
-/* sort of wrong being here... */
+/** Sort of wrong having audio extensions in imbuf. */
const char *imb_ext_audio[] = {
".wav",
".ogg",
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 2b99a0aa81d..cc6fef634d5 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -162,8 +162,6 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
return data_rect;
}
-/* The ibuf is only here to detect the storage type. The produced texture will have undefined
- * content. It will need to be populated by using IMB_update_gpu_texture_sub(). */
GPUTexture *IMB_touch_gpu_texture(
const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
{
@@ -183,9 +181,6 @@ GPUTexture *IMB_touch_gpu_texture(
return tex;
}
-/* Will update a GPUTexture using the content of the ImBuf. Only one layer will be updated.
- * Will resize the ibuf if needed.
- * z is the layer to update. Unused if the texture is 2D. */
void IMB_update_gpu_texture_sub(GPUTexture *tex,
ImBuf *ibuf,
int x,
diff --git a/source/blender/io/alembic/exporter/abc_archive.cc b/source/blender/io/alembic/exporter/abc_archive.cc
index e066704cd24..c070539fc94 100644
--- a/source/blender/io/alembic/exporter/abc_archive.cc
+++ b/source/blender/io/alembic/exporter/abc_archive.cc
@@ -51,7 +51,7 @@ static MetaData create_abc_metadata(const Main *bmain, double scene_fps)
{
MetaData abc_metadata;
- std::string abc_user_description(bmain->name);
+ std::string abc_user_description(bmain->filepath);
if (abc_user_description.empty()) {
abc_user_description = "unknown";
}
diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
index 8073e157c13..bd12f3c10d3 100644
--- a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
+++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc
@@ -72,8 +72,6 @@ void SubdivModifierDisabler::disable_modifiers()
}
}
-/* Check if the mesh is a subsurf, ignoring disabled modifiers and
- * displace if it's after subsurf. */
ModifierData *SubdivModifierDisabler::get_subdiv_modifier(Scene *scene, Object *ob)
{
ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last);
diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.h b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
index 3556df7ff31..c6541fd8afe 100644
--- a/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
+++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h
@@ -45,6 +45,10 @@ class SubdivModifierDisabler final {
void disable_modifiers();
+ /**
+ * Check if the mesh is a subsurf, ignoring disabled modifiers and
+ * displace if it's after subsurf.
+ */
static ModifierData *get_subdiv_modifier(Scene *scene, Object *ob);
};
diff --git a/source/blender/io/alembic/exporter/abc_writer_points.cc b/source/blender/io/alembic/exporter/abc_writer_points.cc
index 70608fdbe92..2db9ad4ffab 100644
--- a/source/blender/io/alembic/exporter/abc_writer_points.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_points.cc
@@ -112,7 +112,7 @@ void ABCPointsWriter::do_write(HierarchyContext &context)
}
state.time = DEG_get_ctime(args_.depsgraph);
- if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
+ if (psys_get_particle_state(&sim, p, &state, false) == 0) {
continue;
}
diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.cc b/source/blender/io/alembic/intern/abc_axis_conversion.cc
index 23b24d2fd9a..78ea7166faf 100644
--- a/source/blender/io/alembic/intern/abc_axis_conversion.cc
+++ b/source/blender/io/alembic/intern/abc_axis_conversion.cc
@@ -75,8 +75,6 @@ void create_swapped_rotation_matrix(float rot_x_mat[3][3],
} // namespace
// alembicvoidcreate_swapped_rotation_matrix(floatrot_x_mat[3][3],floatrot_y_mat[3][3],floatrot_z_mat[3][3],constfloateuler[3],AbcAxisSwapModemode)
-/* Convert matrix from Z=up to Y=up or vice versa.
- * Use yup_mat = zup_mat for in-place conversion. */
void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
{
float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
@@ -139,8 +137,6 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod
mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
}
-/* Recompute transform matrix of object in new coordinate system
- * (from Z-Up to Y-Up). */
void create_transform_matrix(Object *obj,
float r_yup_mat[4][4],
AbcMatrixMode mode,
diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.h b/source/blender/io/alembic/intern/abc_axis_conversion.h
index 30988222fb7..21b95ec717e 100644
--- a/source/blender/io/alembic/intern/abc_axis_conversion.h
+++ b/source/blender/io/alembic/intern/abc_axis_conversion.h
@@ -70,20 +70,27 @@ BLI_INLINE void copy_yup_from_zup(short yup[3], const short zup[3])
}
/* Names are given in (dst, src) order, just like
- * the parameters of copy_m44_axis_swap() */
+ * the parameters of copy_m44_axis_swap(). */
+
typedef enum {
ABC_ZUP_FROM_YUP = 1,
ABC_YUP_FROM_ZUP = 2,
} AbcAxisSwapMode;
-/* Create a rotation matrix for each axis from euler angles.
- * Euler angles are swapped to change coordinate system. */
+/**
+ * Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swapped to change coordinate system.
+ */
void create_swapped_rotation_matrix(float rot_x_mat[3][3],
float rot_y_mat[3][3],
float rot_z_mat[3][3],
const float euler[3],
AbcAxisSwapMode mode);
+/**
+ * Convert matrix from Z=up to Y=up or vice versa.
+ * Use yup_mat = zup_mat for in-place conversion.
+ */
void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode);
typedef enum {
@@ -91,6 +98,10 @@ typedef enum {
ABC_MATRIX_LOCAL = 2,
} AbcMatrixMode;
+/**
+ * Recompute transform matrix of object in new coordinate system
+ * (from Z-Up to Y-Up).
+ */
void create_transform_matrix(Object *obj,
float r_yup_mat[4][4],
AbcMatrixMode mode,
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index 188e8daac8f..830ec731e20 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
+#include "BKE_mesh.h"
/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
* Although Alembic only allows for a single UV layer per {I|O}Schema, and does
@@ -253,7 +254,8 @@ static void write_mcol(const OCompoundProperty &prop,
void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config)
{
- const void *customdata = CustomData_get_layer(&config.mesh->vdata, CD_ORCO);
+ Mesh *mesh = config.mesh;
+ const void *customdata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
if (customdata == nullptr) {
/* Data not available, so don't even bother creating an Alembic property for it. */
return;
@@ -268,6 +270,11 @@ void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &
coords[vertex_idx].setValue(orco_yup[0], orco_yup[1], orco_yup[2]);
}
+ /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
+ * unnormalized, so we need to unnormalize (invert transform) them. */
+ BKE_mesh_orco_verts_transform(
+ mesh, reinterpret_cast<float(*)[3]>(&coords[0]), mesh->totvert, true);
+
if (!config.abc_orco.valid()) {
/* Create the Alembic property and keep a reference so future frames can reuse it. */
config.abc_orco = OV3fGeomParam(prop, propNameOriginalCoordinates, false, kVertexScope, 1);
@@ -536,13 +543,14 @@ void read_generated_coordinates(const ICompoundProperty &prop,
IV3fGeomParam::Sample sample = param.getExpandedValue(iss);
Alembic::AbcGeom::V3fArraySamplePtr abc_ocro = sample.getVals();
const size_t totvert = abc_ocro.get()->size();
+ Mesh *mesh = config.mesh;
void *cd_data;
- if (CustomData_has_layer(&config.mesh->vdata, CD_ORCO)) {
- cd_data = CustomData_get_layer(&config.mesh->vdata, CD_ORCO);
+ if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
+ cd_data = CustomData_get_layer(&mesh->vdata, CD_ORCO);
}
else {
- cd_data = CustomData_add_layer(&config.mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert);
+ cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert);
}
float(*orcodata)[3] = static_cast<float(*)[3]>(cd_data);
@@ -550,6 +558,10 @@ void read_generated_coordinates(const ICompoundProperty &prop,
const Imath::V3f &abc_coords = (*abc_ocro)[vertex_idx];
copy_zup_from_yup(orcodata[vertex_idx], abc_coords.getValue());
}
+
+ /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
+ * unnormalized, so we need to normalize them. */
+ BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
}
void read_custom_data(const std::string &iobject_full_name,
@@ -591,12 +603,6 @@ void read_custom_data(const std::string &iobject_full_name,
}
}
-/* UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
- * vertex). The first case is the most common, as this is the standard way of storing this data
- * given that some vertices might be on UV seams and have multiple possible UV coordinates; the
- * second case can happen when the mesh is split according to the UV islands, in which case storing
- * a single UV value per vertex allows to deduplicate data and thus to reduce the file size since
- * vertices are guaranteed to only have a single UV coordinate. */
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
const CDStreamConfig &config,
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h
index 5eae6307474..97a9235753f 100644
--- a/source/blender/io/alembic/intern/abc_customdata.h
+++ b/source/blender/io/alembic/intern/abc_customdata.h
@@ -132,6 +132,14 @@ typedef enum {
ABC_UV_SCOPE_VERTEX,
} AbcUvScope;
+/**
+ * UVs can be defined per-loop (one value per vertex per face), or per-vertex (one value per
+ * vertex). The first case is the most common, as this is the standard way of storing this data
+ * given that some vertices might be on UV seams and have multiple possible UV coordinates; the
+ * second case can happen when the mesh is split according to the UV islands, in which case storing
+ * a single UV value per vertex allows to de-duplicate data and thus to reduce the file size since
+ * vertices are guaranteed to only have a single UV coordinate.
+ */
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
const CDStreamConfig &config,
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices);
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.cc b/source/blender/io/alembic/intern/abc_reader_curves.cc
index d2ec7fb84db..bd1e57da648 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.cc
+++ b/source/blender/io/alembic/intern/abc_reader_curves.cc
@@ -274,12 +274,6 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
}
}
-/* NOTE: Alembic only stores data about control points, but the Mesh
- * passed from the cache modifier contains the displist, which has more data
- * than the control points, so to avoid corrupting the displist we modify the
- * object directly and create a new Mesh from that. Also we might need to
- * create new or delete existing NURBS in the curve.
- */
Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
const ISampleSelector &sample_sel,
int /*read_flag*/,
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.h b/source/blender/io/alembic/intern/abc_reader_curves.h
index df5d68d7850..6bc0691a870 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.h
+++ b/source/blender/io/alembic/intern/abc_reader_curves.h
@@ -43,6 +43,13 @@ class AbcCurveReader final : public AbcObjectReader {
const char **err_str) const override;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
+ /**
+ * \note Alembic only stores data about control points, but the Mesh
+ * passed from the cache modifier contains the displist, which has more data
+ * than the control points, so to avoid corrupting the displist we modify the
+ * object directly and create a new Mesh from that. Also we might need to
+ * create new or delete existing NURBS in the curve.
+ */
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
const int read_flag,
diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc
index a6d46c4b42a..4a359c49d26 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.cc
+++ b/source/blender/io/alembic/intern/abc_reader_object.cc
@@ -67,7 +67,6 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
determine_inherits_xform();
}
-/* Determine whether we can inherit our parent's XForm */
void AbcObjectReader::determine_inherits_xform()
{
m_inherits_xform = false;
diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h
index 6e97f841a88..f1c07da0764 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.h
+++ b/source/blender/io/alembic/intern/abc_reader_object.h
@@ -171,6 +171,7 @@ class AbcObjectReader {
void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant);
protected:
+ /** Determine whether we can inherit our parent's XForm. */
void determine_inherits_xform();
};
diff --git a/source/blender/io/alembic/intern/abc_util.cc b/source/blender/io/alembic/intern/abc_util.cc
index 3d3ba0347c5..952fe1fa783 100644
--- a/source/blender/io/alembic/intern/abc_util.cc
+++ b/source/blender/io/alembic/intern/abc_util.cc
@@ -63,15 +63,6 @@ std::string get_valid_abc_name(const char *name)
return name_string;
}
-/**
- * \brief get_object_dag_path_name returns the name under which the object
- * will be exported in the Alembic file. It is of the form
- * "[../grandparent/]parent/object" if dupli_parent is NULL, or
- * "dupli_parent/[../grandparent/]parent/object" otherwise.
- * \param ob:
- * \param dupli_parent:
- * \return
- */
std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent)
{
std::string name = get_id_name(ob);
diff --git a/source/blender/io/alembic/intern/abc_util.h b/source/blender/io/alembic/intern/abc_util.h
index ced9fde0f85..3a0b2852eea 100644
--- a/source/blender/io/alembic/intern/abc_util.h
+++ b/source/blender/io/alembic/intern/abc_util.h
@@ -35,6 +35,15 @@ struct ImportSettings;
std::string get_id_name(const ID *const id);
std::string get_id_name(const Object *const ob);
std::string get_valid_abc_name(const char *name);
+/**
+ * \brief get_object_dag_path_name returns the name under which the object
+ * will be exported in the Alembic file. It is of the form
+ * "[../grandparent/]parent/object" if dupli_parent is NULL, or
+ * "dupli_parent/[../grandparent/]parent/object" otherwise.
+ * \param ob:
+ * \param dupli_parent:
+ * \return
+ */
std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent);
/* Convert from float to Alembic matrix representations. Does NOT convert from Z-up to Y-up. */
diff --git a/source/blender/io/collada/AnimationExporter.cpp b/source/blender/io/collada/AnimationExporter.cpp
index 56274e7e6ca..56fd0938eea 100644
--- a/source/blender/io/collada/AnimationExporter.cpp
+++ b/source/blender/io/collada/AnimationExporter.cpp
@@ -126,7 +126,6 @@ bool AnimationExporter::exportAnimations()
return animation_count;
}
-/* called for each exported object */
void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
{
bool container_is_open = false;
@@ -165,16 +164,6 @@ void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
close_animation_container(container_is_open);
}
-/*
- * Export all animation FCurves of an Object.
- *
- * NOTE: This uses the keyframes as sample points,
- * and exports "baked keyframes" while keeping the tangent information
- * of the FCurves intact. This works for simple cases, but breaks
- * especially when negative scales are involved in the animation.
- * And when parent inverse matrices are involved (when exporting
- * object hierarchies)
- */
void AnimationExporter::export_curve_animation_set(Object *ob,
BCAnimationSampler &sampler,
bool export_as_matrix)
@@ -254,7 +243,6 @@ BC_global_rotation_type AnimationExporter::get_global_rotation_type(Object *ob)
return (apply_global_rotation) ? BC_DATA_ROTATION : BC_OBJECT_ROTATION;
}
-/* Write bone animations in transform matrix sources. */
void AnimationExporter::export_bone_animations_recursive(Object *ob,
Bone *bone,
BCAnimationSampler &sampler)
@@ -277,14 +265,6 @@ void AnimationExporter::export_bone_animations_recursive(Object *ob,
}
}
-/**
- * In some special cases the exported Curve needs to be replaced
- * by a modified curve (for collada purposes)
- * This method checks if a conversion is necessary and if applicable
- * returns a pointer to the modified BCAnimationCurve.
- * IMPORTANT: the modified curve must be deleted by the caller when no longer needed
- * if no conversion is needed this method returns a NULL;
- */
BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob,
BCAnimationCurve &curve,
BCAnimationCurveMap &curves)
@@ -657,9 +637,6 @@ std::string AnimationExporter::collada_source_from_values(
return source_id;
}
-/*
- * Create a collada matrix source for a set of samples
- */
std::string AnimationExporter::collada_source_from_values(
BCMatrixSampleMap &samples,
const std::string &anim_id,
@@ -823,10 +800,6 @@ std::string AnimationExporter::get_collada_name(std::string channel_type) const
return tm_name;
}
-/*
- * Assign sid of the animated parameter or transform for rotation,
- * axis name is always appended and the value of append_axis is ignored
- */
std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve,
const std::string axis_name)
{
diff --git a/source/blender/io/collada/AnimationExporter.h b/source/blender/io/collada/AnimationExporter.h
index fd691184e8b..11732af33ba 100644
--- a/source/blender/io/collada/AnimationExporter.h
+++ b/source/blender/io/collada/AnimationExporter.h
@@ -100,7 +100,7 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
bool exportAnimations();
- /* called for each exported object */
+ /** Called for each exported object. */
void operator()(Object *ob);
protected:
@@ -148,25 +148,34 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
std::vector<std::vector<std::string>> anim_meta;
- /* Main entry point into Animation export (called for each exported object) */
+ /** Main entry point into Animation export (called for each exported object). */
void exportAnimation(Object *ob, BCAnimationSampler &sampler);
- /* export animation as separate trans/rot/scale curves */
+ /**
+ * Export all animation FCurves of an Object.
+ *
+ * \note This uses the keyframes as sample points,
+ * and exports "baked keyframes" while keeping the tangent information
+ * of the FCurves intact. This works for simple cases, but breaks
+ * especially when negative scales are involved in the animation.
+ * And when parent inverse matrices are involved (when exporting
+ * object hierarchies)
+ */
void export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix);
- /* export one single curve */
+ /** Export one single curve. */
void export_curve_animation(Object *ob, BCAnimationCurve &curve);
- /* export animation as matrix data */
+ /** Export animation as matrix data. */
void export_matrix_animation(Object *ob, BCAnimationSampler &sampler);
- /* step through the bone hierarchy */
+ /** Write bone animations in transform matrix sources (step through the bone hierarchy). */
void export_bone_animations_recursive(Object *ob_arm, Bone *bone, BCAnimationSampler &sampler);
- /* Export for one bone */
+ /** Export for one bone. */
void export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples);
- /* call to the low level collada exporter */
+ /** Call to the low level collada exporter. */
void export_collada_curve_animation(std::string id,
std::string name,
std::string target,
@@ -174,7 +183,7 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
BCAnimationCurve &curve,
BC_global_rotation_type global_rotation_type);
- /* call to the low level collada exporter */
+ /** Call to the low level collada exporter. */
void export_collada_matrix_animation(std::string id,
std::string name,
std::string target,
@@ -183,29 +192,38 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
BC_global_rotation_type global_rotation_type,
Matrix &parentinv);
+ /**
+ * In some special cases the exported Curve needs to be replaced
+ * by a modified curve (for collada purposes)
+ * This method checks if a conversion is necessary and if applicable
+ * returns a pointer to the modified BCAnimationCurve.
+ * IMPORTANT: the modified curve must be deleted by the caller when no longer needed
+ * if no conversion is needed this method returns a NULL;
+ */
BCAnimationCurve *get_modified_export_curve(Object *ob,
BCAnimationCurve &curve,
BCAnimationCurveMap &curves);
- /* Helper functions */
+ /* Helper functions. */
+
void openAnimationWithClip(std::string id, std::string name);
bool open_animation_container(bool has_container, Object *ob);
void close_animation_container(bool has_container);
- /* Input and Output sources (single valued) */
+ /** Input and Output sources (single valued). */
std::string collada_source_from_values(BC_animation_source_type source_type,
COLLADASW::InputSemantic::Semantics semantic,
std::vector<float> &values,
const std::string &anim_id,
const std::string axis_name);
- /* Output sources (matrix data) */
+ /** Output sources (matrix data). * Create a collada matrix source for a set of samples. */
std::string collada_source_from_values(BCMatrixSampleMap &samples,
const std::string &anim_id,
BC_global_rotation_type global_rotation_type,
Matrix &parentinv);
- /* Interpolation sources */
+ /** Interpolation sources. */
std::string collada_linear_interpolation_source(int tot, const std::string &anim_id);
/* source ID = animation_name + semantic_suffix */
@@ -240,6 +258,10 @@ class AnimationExporter : COLLADASW::LibraryAnimations {
std::string get_axis_name(std::string channel, int id);
std::string get_collada_name(std::string channel_type) const;
+ /**
+ * Assign sid of the animated parameter or transform for rotation,
+ * axis name is always appended and the value of append_axis is ignored.
+ */
std::string get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name);
/* ===================================== */
diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp
index 5b6391c1b9c..870db4a15d3 100644
--- a/source/blender/io/collada/AnimationImporter.cpp
+++ b/source/blender/io/collada/AnimationImporter.cpp
@@ -81,7 +81,6 @@ void AnimationImporter::add_bezt(FCurve *fcu,
calchandles_fcurve(fcu);
}
-/* create one or several fcurves depending on the number of parameters being animated */
void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
{
COLLADAFW::FloatOrDoubleArray &input = curve->getInputValues();
@@ -323,7 +322,6 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim)
return true;
}
-/* called on post-process stage after writeVisualScenes */
bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *animlist)
{
const COLLADAFW::UniqueId &animlist_id = animlist->getUniqueId();
@@ -343,11 +341,6 @@ bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *ani
return true;
}
-/**
- * \todo refactor read_node_transform to not automatically apply anything,
- * but rather return the transform matrix, so caller can do with it what is
- * necessary. Same for \ref get_node_mat
- */
void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob)
{
float mat[4][4];
@@ -463,7 +456,6 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
}
#endif
-/* sets the rna_path and array index to curve */
void AnimationImporter::modify_fcurve(std::vector<FCurve *> *curves,
const char *rna_path,
int array_index,
@@ -535,8 +527,6 @@ static int get_animation_axis_index(const COLLADABU::Math::Vector3 &axis)
return index;
}
-/* creates the rna_paths and array indices of fcurves from animations using transformation and
- * bound animation class of each animation. */
void AnimationImporter::Assign_transform_animations(
COLLADAFW::Transformation *transform,
const COLLADAFW::AnimationList::AnimationBinding *binding,
@@ -654,8 +644,6 @@ void AnimationImporter::Assign_transform_animations(
}
}
-/* creates the rna_paths and array indices of fcurves from animations using color and bound
- * animation class of each animation. */
void AnimationImporter::Assign_color_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type)
@@ -765,11 +753,6 @@ float AnimationImporter::convert_to_focal_length(float in_xfov,
return fov_to_focallength(xfov, sensorx);
}
-/*
- * Lens animations must be stored in COLLADA by using FOV,
- * while blender internally uses focal length.
- * The imported animation curves must be converted appropriately.
- */
void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const double aspect,
@@ -1403,8 +1386,6 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob,
chan->rotmode = ROT_MODE_QUAT;
}
-/* Check if object is animated by checking if animlist_map
- * holds the animlist_id of node transforms */
AnimationImporter::AnimMix *AnimationImporter::get_animation_type(
const COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map)
@@ -1514,7 +1495,6 @@ int AnimationImporter::setAnimType(const COLLADAFW::Animatable *prop, int types,
return anim_type;
}
-/* Is not used anymore. */
void AnimationImporter::find_frames_old(std::vector<float> *frames,
COLLADAFW::Node *node,
COLLADAFW::Transformation::TransformationType tm_type)
@@ -1579,9 +1559,6 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames,
}
}
-/* prerequisites:
- * animlist_map - map animlist id -> animlist
- * curve_map - map anim id -> curve(s) */
Object *AnimationImporter::translate_animation_OLD(
COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object *> &object_map,
@@ -1854,9 +1831,6 @@ Object *AnimationImporter::translate_animation_OLD(
return job;
}
-/* internal, better make it private
- * warning: evaluates only rotation and only assigns matrix transforms now
- * prerequisites: animlist_map, curve_map */
void AnimationImporter::evaluate_transform_at_frame(float mat[4][4],
COLLADAFW::Node *node,
float fra)
@@ -1915,7 +1889,6 @@ static void report_class_type_unsupported(const char *path,
}
}
-/* return true to indicate that mat contains a sane value */
bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm,
float mat[4][4],
float fra,
@@ -2063,7 +2036,6 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm,
return false;
}
-/* gives a world-space mat of joint at rest position */
void AnimationImporter::get_joint_rest_mat(float mat[4][4],
COLLADAFW::Node *root,
COLLADAFW::Node *node)
@@ -2079,7 +2051,6 @@ void AnimationImporter::get_joint_rest_mat(float mat[4][4],
}
}
-/* gives a world-space mat, end's mat not included */
bool AnimationImporter::calc_joint_parent_mat_rest(float mat[4][4],
float par[4][4],
COLLADAFW::Node *node,
diff --git a/source/blender/io/collada/AnimationImporter.h b/source/blender/io/collada/AnimationImporter.h
index 44001366adc..a4624a18cd5 100644
--- a/source/blender/io/collada/AnimationImporter.h
+++ b/source/blender/io/collada/AnimationImporter.h
@@ -75,7 +75,9 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
float value,
eBezTriple_Interpolation ipo = BEZT_IPO_LIN);
- /* create one or several fcurves depending on the number of parameters being animated */
+ /**
+ * Create one or several fcurves depending on the number of parameters being animated.
+ */
void animation_to_fcurves(COLLADAFW::AnimationCurve *curve);
void fcurve_deg_to_rad(FCurve *cu);
@@ -143,9 +145,14 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
void set_import_from_version(std::string import_from_version);
bool write_animation(const COLLADAFW::Animation *anim);
- /* called on post-process stage after writeVisualScenes */
+ /** Called on post-process stage after writeVisualScenes. */
bool write_animation_list(const COLLADAFW::AnimationList *animlist);
+ /**
+ * \todo refactor read_node_transform to not automatically apply anything,
+ * but rather return the transform matrix, so caller can do with it what is
+ * necessary. Same for \ref get_node_mat
+ */
void read_node_transform(COLLADAFW::Node *node, Object *ob);
#if 0
virtual void change_eul_to_quat(Object *ob, bAction *act);
@@ -157,6 +164,10 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map,
std::map<COLLADAFW::UniqueId, Material *> uid_material_map);
+ /**
+ * Check if object is animated by checking if animlist_map
+ * holds the animlist_id of node transforms.
+ */
AnimMix *get_animation_type(
const COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map);
@@ -173,18 +184,31 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
COLLADAFW::Node *node,
COLLADAFW::Transformation *tm);
+ /**
+ * Creates the rna_paths and array indices of fcurves from animations using transformation and
+ * bound animation class of each animation.
+ */
void Assign_transform_animations(COLLADAFW::Transformation *transform,
const COLLADAFW::AnimationList::AnimationBinding *binding,
std::vector<FCurve *> *curves,
bool is_joint,
char *joint_path);
+ /**
+ * Creates the rna_paths and array indices of fcurves from animations using color and bound
+ * animation class of each animation.
+ */
void Assign_color_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type);
void Assign_float_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const char *anim_type);
+ /**
+ * Lens animations must be stored in COLLADA by using FOV,
+ * while blender internally uses focal length.
+ * The imported animation curves must be converted appropriately.
+ */
void Assign_lens_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
const double aspect,
@@ -194,14 +218,17 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
int setAnimType(const COLLADAFW::Animatable *prop, int type, int addition);
+ /** Sets the rna_path and array index to curve. */
void modify_fcurve(std::vector<FCurve *> *curves,
const char *rna_path,
int array_index,
int scale = 1);
void unused_fcurve(std::vector<FCurve *> *curves);
- /* prerequisites:
+ /**
+ * Prerequisites:
* animlist_map - map animlist id -> animlist
- * curve_map - map anim id -> curve(s) */
+ * curve_map - map anim id -> curve(s).
+ */
Object *translate_animation_OLD(COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object *> &object_map,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> &root_map,
@@ -209,24 +236,27 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
Object *par_job = NULL);
void find_frames(std::vector<float> *frames, std::vector<FCurve *> *curves);
+ /** Is not used anymore. */
void find_frames_old(std::vector<float> *frames,
COLLADAFW::Node *node,
COLLADAFW::Transformation::TransformationType tm_type);
- /* internal, better make it private
- * warning: evaluates only rotation
- * prerequisites: animlist_map, curve_map */
+ /**
+ * Internal, better make it private
+ * warning: evaluates only rotation and only assigns matrix transforms now
+ * prerequisites: animlist_map, curve_map.
+ */
void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra);
- /* return true to indicate that mat contains a sane value */
+ /** Return true to indicate that mat contains a sane value. */
bool evaluate_animation(COLLADAFW::Transformation *tm,
float mat[4][4],
float fra,
const char *node_id);
- /* gives a world-space mat of joint at rest position */
+ /** Gives a world-space mat of joint at rest position. */
void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node);
- /* gives a world-space mat, end's mat not included */
+ /** * Gives a world-space mat, end's mat not included. */
bool calc_joint_parent_mat_rest(float mat[4][4],
float par[4][4],
COLLADAFW::Node *node,
@@ -239,8 +269,10 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
#endif
#if 0
- /* recursively evaluates joint tree until end is found, mat then is world-space matrix of end
- * mat must be identity on enter, node must be root */
+ /**
+ * Recursively evaluates joint tree until end is found, mat then is world-space matrix of end
+ * mat must be identity on enter, node must be root.
+ */
bool evaluate_joint_world_transform_at_frame(
float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra);
#endif
diff --git a/source/blender/io/collada/ArmatureExporter.cpp b/source/blender/io/collada/ArmatureExporter.cpp
index 28f5f9d40bc..5da70211bfd 100644
--- a/source/blender/io/collada/ArmatureExporter.cpp
+++ b/source/blender/io/collada/ArmatureExporter.cpp
@@ -40,7 +40,6 @@
#include "GeometryExporter.h"
#include "SceneExporter.h"
-/* write bone nodes */
void ArmatureExporter::add_armature_bones(Object *ob_arm,
ViewLayer *view_layer,
SceneExporter *se,
@@ -144,7 +143,6 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm,
}
#endif
-/* parent_mat is armature-space */
void ArmatureExporter::add_bone_node(Bone *bone,
Object *ob_arm,
SceneExporter *se,
diff --git a/source/blender/io/collada/ArmatureExporter.h b/source/blender/io/collada/ArmatureExporter.h
index b994741f342..c1b58f0071c 100644
--- a/source/blender/io/collada/ArmatureExporter.h
+++ b/source/blender/io/collada/ArmatureExporter.h
@@ -62,6 +62,7 @@ class ArmatureExporter : public COLLADASW::LibraryControllers,
{
}
+ /* write bone nodes */
void add_armature_bones(Object *ob_arm,
ViewLayer *view_layer,
SceneExporter *se,
@@ -83,8 +84,11 @@ class ArmatureExporter : public COLLADASW::LibraryControllers,
void find_objects_using_armature(Object *ob_arm, std::vector<Object *> &objects, Scene *sce);
#endif
- /* Scene, SceneExporter and the list of child_objects
- * are required for writing bone parented objects */
+ /**
+ * Scene, SceneExporter and the list of child_objects
+ * are required for writing bone parented objects.
+ * \param parent_mat: is armature-space.
+ */
void add_bone_node(Bone *bone,
Object *ob_arm,
SceneExporter *se,
diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp
index 72fb8820be5..cfe9ed6b2e0 100644
--- a/source/blender/io/collada/ArmatureImporter.cpp
+++ b/source/blender/io/collada/ArmatureImporter.cpp
@@ -220,12 +220,6 @@ int ArmatureImporter::create_bone(SkinInfo *skin,
return chain_length + 1;
}
-/**
- * Collada only knows Joints, hence bones at the end of a bone chain
- * don't have a defined length. This function guesses reasonable
- * tail locations for the affected bones (nodes which don't have any connected child)
- * Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
- */
void ArmatureImporter::fix_leaf_bone_hierarchy(bArmature *armature,
Bone *bone,
bool fix_orientation)
@@ -757,11 +751,6 @@ bool ArmatureImporter::node_is_decomposed(const COLLADAFW::Node *node)
return true;
}
-/**
- * root - if this joint is the top joint in hierarchy, if a joint
- * is a child of a node (not joint), root should be true since
- * this is where we build armature bones from
- */
void ArmatureImporter::add_root_joint(COLLADAFW::Node *node, Object *parent)
{
root_joints.push_back(node);
@@ -786,7 +775,6 @@ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node)
}
#endif
-/* here we add bones to armatures, having armatures previously created in write_controller */
void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &objects_to_scale)
{
Main *bmain = CTX_data_main(C);
@@ -1042,7 +1030,6 @@ void ArmatureImporter::get_rna_path_for_joint(COLLADAFW::Node *node,
BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", bone_name_esc);
}
-/* gives a world-space mat */
bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint)
{
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
diff --git a/source/blender/io/collada/ArmatureImporter.h b/source/blender/io/collada/ArmatureImporter.h
index 16265e66a8e..ea78efeb5d7 100644
--- a/source/blender/io/collada/ArmatureImporter.h
+++ b/source/blender/io/collada/ArmatureImporter.h
@@ -111,6 +111,12 @@ class ArmatureImporter : private TransformReader {
std::vector<std::string> &layer_labels,
BoneExtensionMap &extended_bones);
+ /**
+ * Collada only knows Joints, hence bones at the end of a bone chain
+ * don't have a defined length. This function guesses reasonable
+ * tail locations for the affected bones (nodes which don't have any connected child)
+ * Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
+ */
void fix_leaf_bone_hierarchy(bArmature *armature, Bone *bone, bool fix_orientation);
void fix_leaf_bone(bArmature *armature, EditBone *ebone, BoneExtended *be, bool fix_orientation);
void fix_parent_connect(bArmature *armature, Bone *bone);
@@ -152,15 +158,20 @@ class ArmatureImporter : private TransformReader {
const ImportSettings *import_settings);
~ArmatureImporter();
+ /**
+ * root - if this joint is the top joint in hierarchy, if a joint
+ * is a child of a node (not joint), root should be true since
+ * this is where we build armature bones from
+ */
void add_root_joint(COLLADAFW::Node *node, Object *parent);
- /* here we add bones to armatures, having armatures previously created in write_controller */
+ /** Here we add bones to armatures, having armatures previously created in write_controller. */
void make_armatures(bContext *C, std::vector<Object *> &objects_to_scale);
void make_shape_keys(bContext *C);
#if 0
- /* link with meshes, create vertex groups, assign weights */
+ /** Link with meshes, create vertex groups, assign weights. */
void link_armature(Object *ob_arm,
const COLLADAFW::UniqueId &geom_id,
const COLLADAFW::UniqueId &controller_data_id);
@@ -176,7 +187,7 @@ class ArmatureImporter : private TransformReader {
void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count);
- /* gives a world-space mat */
+ /** Gives a world-space mat. */
bool get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint);
void set_tags_map(TagsMap &tags_map);
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index 953af5adffc..a2d711050cb 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -418,11 +418,6 @@ void BCAnimationSampler::generate_transforms(Object *ob, Bone *bone, BCAnimation
}
}
-/**
- * Collect all keyframes from all animation curves related to the object.
- * The bc_get... functions check for NULL and correct object type.
- * The #add_keyframes_from() function checks for NULL.
- */
void BCAnimationSampler::initialize_keyframes(BCFrameSet &frameset, Object *ob)
{
frameset.clear();
@@ -517,7 +512,6 @@ BCSample &BCSampleFrame::add(Object *ob)
return *sample;
}
-/* Get the matrix for the given key, returns Unity when the key does not exist */
const BCSample *BCSampleFrame::get_sample(Object *ob) const
{
BCSampleMap::const_iterator it = sampleMap.find(ob);
@@ -537,7 +531,6 @@ const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob) const
return &sample->get_matrix();
}
-/* Get the matrix for the given Bone, returns Unity when the Object is not sampled. */
const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
{
BCSampleMap::const_iterator it = sampleMap.find(ob);
@@ -550,13 +543,11 @@ const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
return bc_bone;
}
-/* Check if the key is in this BCSampleFrame */
bool BCSampleFrame::has_sample_for(Object *ob) const
{
return sampleMap.find(ob) != sampleMap.end();
}
-/* Check if the Bone is in this BCSampleFrame */
bool BCSampleFrame::has_sample_for(Object *ob, Bone *bone) const
{
const BCMatrix *bc_bone = get_sample_matrix(ob, bone);
@@ -575,7 +566,6 @@ BCSample &BCSampleFrameContainer::add(Object *ob, int frame_index)
/* Below are the getters which we need to export the data */
/* ====================================================== */
-/* Return either the BCSampleFrame or NULL if frame does not exist. */
BCSampleFrame *BCSampleFrameContainer::get_frame(int frame_index)
{
BCSampleFrameMap::iterator it = sample_frames.find(frame_index);
@@ -583,7 +573,6 @@ BCSampleFrame *BCSampleFrameContainer::get_frame(int frame_index)
return frame;
}
-/* Return a list of all frames that need to be sampled */
int BCSampleFrameContainer::get_frames(std::vector<int> &frames) const
{
frames.clear(); /* safety; */
diff --git a/source/blender/io/collada/BCAnimationSampler.h b/source/blender/io/collada/BCAnimationSampler.h
index 19b1bc35264..c78590b8e37 100644
--- a/source/blender/io/collada/BCAnimationSampler.h
+++ b/source/blender/io/collada/BCAnimationSampler.h
@@ -89,11 +89,16 @@ class BCSampleFrame {
BCSample &add(Object *ob);
/* Following methods return NULL if object is not in the sampleMap. */
+
+ /** Get the matrix for the given key, returns Unity when the key does not exist. */
const BCSample *get_sample(Object *ob) const;
const BCMatrix *get_sample_matrix(Object *ob) const;
+ /** Get the matrix for the given Bone, returns Unity when the Object is not sampled. */
const BCMatrix *get_sample_matrix(Object *ob, Bone *bone) const;
+ /** Check if the key is in this BCSampleFrame. */
bool has_sample_for(Object *ob) const;
+ /** Check if the Bone is in this BCSampleFrame. */
bool has_sample_for(Object *ob, Bone *bone) const;
};
@@ -134,8 +139,10 @@ class BCSampleFrameContainer {
}
BCSample &add(Object *ob, int frame_index);
- BCSampleFrame *get_frame(int frame_index); /* returns NULL if frame does not exist */
+ /** Return either the #BCSampleFrame or NULL if frame does not exist. */
+ BCSampleFrame *get_frame(int frame_index);
+ /** Return a list of all frames that need to be sampled. */
int get_frames(std::vector<int> &frames) const;
int get_frames(Object *ob, BCFrames &frames) const;
int get_frames(Object *ob, Bone *bone, BCFrames &frames) const;
@@ -159,6 +166,11 @@ class BCAnimationSampler {
void generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves);
void initialize_curves(BCAnimationCurveMap &curves, Object *ob);
+ /**
+ * Collect all keyframes from all animation curves related to the object.
+ * The bc_get... functions check for NULL and correct object type.
+ * The #add_keyframes_from() function checks for NULL.
+ */
void initialize_keyframes(BCFrameSet &frameset, Object *ob);
BCSample &sample_object(Object *ob, int frame_index, bool for_opensim);
void update_animation_curves(BCAnimation &animation,
diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp
index 51c86ee53f2..c3ee3355a41 100644
--- a/source/blender/io/collada/BCMath.cpp
+++ b/source/blender/io/collada/BCMath.cpp
@@ -183,8 +183,6 @@ void BCMatrix::unit()
quat_to_eul(this->rot, this->q);
}
-/* We need double here because the OpenCollada API needs it.
- * precision = -1 indicates to not limit the precision. */
void BCMatrix::get_matrix(DMatrix &mat, const bool transposed, const int precision) const
{
for (int i = 0; i < 4; i++) {
diff --git a/source/blender/io/collada/BCMath.h b/source/blender/io/collada/BCMath.h
index c57d5c6301f..503a76541fd 100644
--- a/source/blender/io/collada/BCMath.h
+++ b/source/blender/io/collada/BCMath.h
@@ -78,6 +78,10 @@ class BCMatrix {
BCMatrix(Object *ob);
BCMatrix();
+ /**
+ * We need double here because the OpenCollada API needs it.
+ * precision = -1 indicates to not limit the precision.
+ */
void get_matrix(DMatrix &matrix, const bool transposed = false, const int precision = -1) const;
void get_matrix(Matrix &matrix,
const bool transposed = false,
diff --git a/source/blender/io/collada/BCSampleData.cpp b/source/blender/io/collada/BCSampleData.cpp
index 339dc829742..9915514dc01 100644
--- a/source/blender/io/collada/BCSampleData.cpp
+++ b/source/blender/io/collada/BCSampleData.cpp
@@ -39,7 +39,6 @@ void BCSample::add_bone_matrix(Bone *bone, Matrix &mat)
bonemats[bone] = matrix;
}
-/* Get channel value */
bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const
{
std::string bname = bc_string_before(channel_target, ".");
diff --git a/source/blender/io/collada/BCSampleData.h b/source/blender/io/collada/BCSampleData.h
index 06d234e2c3e..dccc5228c4f 100644
--- a/source/blender/io/collada/BCSampleData.h
+++ b/source/blender/io/collada/BCSampleData.h
@@ -53,6 +53,7 @@ class BCSample {
void add_bone_matrix(Bone *bone, Matrix &mat);
+ /** Get channel value. */
bool get_value(std::string channel_target, const int array_index, float *val) const;
const BCMatrix &get_matrix() const;
const BCMatrix *get_matrix(Bone *bone) const; /* returns NULL if bone is not animated */
diff --git a/source/blender/io/collada/BlenderContext.cpp b/source/blender/io/collada/BlenderContext.cpp
index ab420e79ba7..2a1968d00d2 100644
--- a/source/blender/io/collada/BlenderContext.cpp
+++ b/source/blender/io/collada/BlenderContext.cpp
@@ -31,12 +31,6 @@ bool bc_is_base_node(LinkNode *export_set, Object *ob, ViewLayer *view_layer)
return (root == ob);
}
-/**
- * Returns the highest selected ancestor
- * returns NULL if no ancestor is selected
- * IMPORTANT: This function expects that all exported objects have set:
- * ob->id.tag & LIB_TAG_DOIT
- */
Object *bc_get_highest_exported_ancestor_or_self(LinkNode *export_set,
Object *ob,
ViewLayer *view_layer)
diff --git a/source/blender/io/collada/BlenderContext.h b/source/blender/io/collada/BlenderContext.h
index 9163b30c86f..86738bbd242 100644
--- a/source/blender/io/collada/BlenderContext.h
+++ b/source/blender/io/collada/BlenderContext.h
@@ -38,6 +38,12 @@ static const BC_global_up_axis BC_DEFAULT_UP = BC_GLOBAL_UP_Z;
bool bc_is_in_Export_set(LinkNode *export_set, Object *ob, ViewLayer *view_layer);
bool bc_is_base_node(LinkNode *export_set, Object *ob, ViewLayer *view_layer);
+/**
+ * Returns the highest selected ancestor
+ * returns NULL if no ancestor is selected
+ * IMPORTANT: This function expects that all exported objects have set:
+ * `ob->id.tag & LIB_TAG_DOIT`
+ */
Object *bc_get_highest_exported_ancestor_or_self(LinkNode *export_set,
Object *ob,
ViewLayer *view_layer);
diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp
index d768d2e44e8..6c13c83fbc7 100644
--- a/source/blender/io/collada/ControllerExporter.cpp
+++ b/source/blender/io/collada/ControllerExporter.cpp
@@ -161,8 +161,6 @@ std::string ControllerExporter::get_controller_id(Key *key, Object *ob)
return translate_id(id_name(ob)) + MORPH_CONTROLLER_ID_SUFFIX;
}
-/* ob should be of type OB_MESH
- * both args are required */
void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
{
/* joint names
@@ -377,7 +375,6 @@ std::string ControllerExporter::add_morph_weights(Key *key, Object *ob)
return source_id;
}
-/* Added to implement support for animations. */
void ControllerExporter::add_weight_extras(Key *key)
{
/* can also try the base element and param alternative */
diff --git a/source/blender/io/collada/ControllerExporter.h b/source/blender/io/collada/ControllerExporter.h
index 0aec9e8d179..d262d21012b 100644
--- a/source/blender/io/collada/ControllerExporter.h
+++ b/source/blender/io/collada/ControllerExporter.h
@@ -91,8 +91,7 @@ class ControllerExporter : public COLLADASW::LibraryControllers,
std::string get_controller_id(Key *key, Object *ob);
- /* ob should be of type OB_MESH
- * both args are required */
+ /** `ob` should be of type OB_MESH, both arguments are required. */
void export_skin_controller(Object *ob, Object *ob_arm);
void export_morph_controller(Object *ob, Key *key);
@@ -107,6 +106,9 @@ class ControllerExporter : public COLLADASW::LibraryControllers,
std::string add_morph_weights(Key *key, Object *ob);
+ /**
+ * Added to implement support for animations.
+ */
void add_weight_extras(Key *key);
std::string add_joints_source(Object *ob_arm,
diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp
index 35bdc0a4e06..013df2fa2b7 100644
--- a/source/blender/io/collada/DocumentImporter.cpp
+++ b/source/blender/io/collada/DocumentImporter.cpp
@@ -320,10 +320,6 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node,
}
}
-/**
- * If the imported file was made with Blender, return the Blender version used,
- * otherwise return an empty std::string
- */
std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asset)
{
const char AUTORING_TOOL[] = "authoring_tool";
@@ -347,10 +343,6 @@ std::string DocumentImporter::get_import_version(const COLLADAFW::FileInfo *asse
return "";
}
-/**
- * When this method is called, the writer must write the global document asset.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
{
unit_converter.read_asset(asset);
@@ -359,10 +351,6 @@ bool DocumentImporter::writeGlobalAsset(const COLLADAFW::FileInfo *asset)
return true;
}
-/**
- * When this method is called, the writer must write the scene.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeScene(const COLLADAFW::Scene *scene)
{
/* XXX could store the scene id, but do nothing for now */
@@ -476,8 +464,6 @@ Object *DocumentImporter::create_instance_node(Object *source_ob,
return obn;
}
-/* to create constraints off node <extra> tags. Assumes only constraint data in
- * current <extra> with blender profile. */
void DocumentImporter::create_constraints(ExtraTags *et, Object *ob)
{
if (et && et->isProfile("blender")) {
@@ -712,10 +698,6 @@ finally:
return root_objects;
}
-/**
- * When this method is called, the writer must write the entire visual scene.
- * Return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene)
{
if (mImportStage == Fetching_Controller_data) {
@@ -738,11 +720,6 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen
return true;
}
-/**
- * When this method is called, the writer must handle all nodes contained in the
- * library nodes.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
{
if (mImportStage == Fetching_Controller_data) {
@@ -762,10 +739,6 @@ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryN
return true;
}
-/**
- * When this method is called, the writer must write the geometry.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
{
if (mImportStage == Fetching_Controller_data) {
@@ -775,10 +748,6 @@ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
return mesh_importer.write_geometry(geom);
}
-/**
- * When this method is called, the writer must write the material.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
{
if (mImportStage == Fetching_Controller_data) {
@@ -821,10 +790,6 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
matNode.update_material_nodetree();
}
-/**
- * When this method is called, the writer must write the effect.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
{
if (mImportStage == Fetching_Controller_data) {
@@ -860,10 +825,6 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
return true;
}
-/**
- * When this method is called, the writer must write the camera.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
{
if (mImportStage == Fetching_Controller_data) {
@@ -973,10 +934,6 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
return true;
}
-/**
- * When this method is called, the writer must write the image.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1013,10 +970,6 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
return true;
}
-/**
- * When this method is called, the writer must write the light.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1164,7 +1117,6 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
return true;
}
-/* this function is called only for animations that pass COLLADAFW::validate */
bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1174,7 +1126,6 @@ bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
return anim_importer.write_animation(anim);
}
-/* called on post-process stage after writeVisualScenes */
bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList)
{
if (mImportStage == Fetching_Controller_data) {
@@ -1186,10 +1137,10 @@ bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animat
}
#if WITH_OPENCOLLADA_ANIMATION_CLIP
-/* Since opencollada 1.6.68
- * called on post-process stage after writeVisualScenes */
bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animationClip)
{
+ /* Since opencollada 1.6.68: called on post-process stage after writeVisualScenes. */
+
if (mImportStage == Fetching_Controller_data) {
return true;
}
@@ -1200,16 +1151,11 @@ bool DocumentImporter::writeAnimationClip(const COLLADAFW::AnimationClip *animat
}
#endif
-/**
- * When this method is called, the writer must write the skin controller data.
- * \return The writer should return true, if writing succeeded, false otherwise.
- */
bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerData *skin)
{
return armature_importer.write_skin_controller_data(skin);
}
-/* this is called on postprocess, before writeVisualScenes */
bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
{
if (mImportStage == Fetching_Controller_data) {
diff --git a/source/blender/io/collada/DocumentImporter.h b/source/blender/io/collada/DocumentImporter.h
index 8e553f1ce7a..63faaca4711 100644
--- a/source/blender/io/collada/DocumentImporter.h
+++ b/source/blender/io/collada/DocumentImporter.h
@@ -64,6 +64,10 @@ class DocumentImporter : COLLADAFW::IWriter {
Object *create_camera_object(COLLADAFW::InstanceCamera *, Scene *);
Object *create_light_object(COLLADAFW::InstanceLight *, Scene *);
Object *create_instance_node(Object *, COLLADAFW::Node *, COLLADAFW::Node *, Scene *, bool);
+ /**
+ * To create constraints off node <extra> tags. Assumes only constraint data in
+ * current <extra> with blender profile.
+ */
void create_constraints(ExtraTags *et, Object *ob);
std::vector<Object *> *write_node(COLLADAFW::Node *, COLLADAFW::Node *, Scene *, Object *, bool);
void write_profile_COMMON(COLLADAFW::EffectCommon *, Material *);
@@ -86,17 +90,44 @@ class DocumentImporter : COLLADAFW::IWriter {
*/
void finish();
+ /**
+ * When this method is called, the writer must write the global document asset.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeGlobalAsset(const COLLADAFW::FileInfo *);
+ /**
+ * If the imported file was made with Blender, return the Blender version used,
+ * otherwise return an empty std::string
+ */
std::string get_import_version(const COLLADAFW::FileInfo *asset);
+ /**
+ * When this method is called, the writer must write the scene.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeScene(const COLLADAFW::Scene *);
+ /**
+ * When this method is called, the writer must write the entire visual scene.
+ * Return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeVisualScene(const COLLADAFW::VisualScene *);
+ /**
+ * When this method is called, the writer must handle all nodes contained in the
+ * library nodes.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeLibraryNodes(const COLLADAFW::LibraryNodes *);
+ /**
+ * This function is called only for animations that pass COLLADAFW::validate.
+ */
bool writeAnimation(const COLLADAFW::Animation *);
+ /**
+ * Called on post-process stage after writeVisualScenes.
+ */
bool writeAnimationList(const COLLADAFW::AnimationList *);
#if WITH_OPENCOLLADA_ANIMATION_CLIP
@@ -105,20 +136,49 @@ class DocumentImporter : COLLADAFW::IWriter {
bool writeAnimationClip(const COLLADAFW::AnimationClip *animationClip);
#endif
+ /**
+ * When this method is called, the writer must write the geometry.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeGeometry(const COLLADAFW::Geometry *);
+ /**
+ * When this method is called, the writer must write the material.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeMaterial(const COLLADAFW::Material *);
+ /**
+ * When this method is called, the writer must write the effect.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeEffect(const COLLADAFW::Effect *);
+ /**
+ * When this method is called, the writer must write the camera.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeCamera(const COLLADAFW::Camera *);
+ /**
+ * When this method is called, the writer must write the image.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeImage(const COLLADAFW::Image *);
+ /**
+ * When this method is called, the writer must write the light.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeLight(const COLLADAFW::Light *);
+ /**
+ * When this method is called, the writer must write the skin controller data.
+ * \return The writer should return true, if writing succeeded, false otherwise.
+ */
bool writeSkinControllerData(const COLLADAFW::SkinControllerData *);
+ /** This is called on post-process, before writeVisualScenes. */
bool writeController(const COLLADAFW::Controller *);
bool writeFormulas(const COLLADAFW::Formulas *);
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index 382bb8a6e36..eeee220fd2c 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -324,7 +324,6 @@ std::string GeometryExporter::makeVertexColorSourceId(std::string &geom_id, char
return result;
}
-/* powerful because it handles both cases when there is material and when there's not */
void GeometryExporter::create_mesh_primitive_list(short material_index,
bool has_uvs,
bool has_color,
@@ -441,7 +440,6 @@ void GeometryExporter::create_mesh_primitive_list(short material_index,
finish_and_delete_primitive_List(is_triangulated, primitive_list);
}
-/* creates <source> for positions */
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
{
#if 0
@@ -542,7 +540,6 @@ std::string GeometryExporter::makeTexcoordSourceId(std::string &geom_id,
return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
}
-/* creates <source> for texcoords */
void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
{
@@ -593,7 +590,6 @@ bool operator<(const Normal &a, const Normal &b)
return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
}
-/* creates <source> for normals */
void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal> &nor)
{
#if 0
diff --git a/source/blender/io/collada/GeometryExporter.h b/source/blender/io/collada/GeometryExporter.h
index 948aafa760d..e6e08f2b977 100644
--- a/source/blender/io/collada/GeometryExporter.h
+++ b/source/blender/io/collada/GeometryExporter.h
@@ -72,7 +72,7 @@ class GeometryExporter : COLLADASW::LibraryGeometries {
void createLooseEdgeList(Object *ob, Mesh *me, std::string &geom_id);
- /* powerful because it handles both cases when there is material and when there's not */
+ /** Powerful because it handles both cases when there is material and when there's not. */
void create_mesh_primitive_list(short material_index,
bool has_uvs,
bool has_color,
@@ -81,17 +81,17 @@ class GeometryExporter : COLLADASW::LibraryGeometries {
std::string &geom_id,
std::vector<BCPolygonNormalsIndices> &norind);
- /* creates <source> for positions */
+ /** Creates <source> for positions. */
void createVertsSource(std::string geom_id, Mesh *me);
void createVertexColorSource(std::string geom_id, Mesh *me);
std::string makeTexcoordSourceId(std::string &geom_id, int layer_index, bool is_single_layer);
- /* creates <source> for texcoords */
+ /** Creates <source> for texcoords. */
void createTexcoordsSource(std::string geom_id, Mesh *me);
- /* creates <source> for normals */
+ /** Creates <source> for normals. */
void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal> &nor);
void create_normals(std::vector<Normal> &nor,
diff --git a/source/blender/io/collada/Materials.cpp b/source/blender/io/collada/Materials.cpp
index 81f0cc608d2..1f358accc4e 100644
--- a/source/blender/io/collada/Materials.cpp
+++ b/source/blender/io/collada/Materials.cpp
@@ -91,7 +91,6 @@ void MaterialNode::setShaderType()
#endif
}
-/* returns null if material already has a node tree */
bNodeTree *MaterialNode::prepare_material_nodetree()
{
if (material->nodetree) {
diff --git a/source/blender/io/collada/Materials.h b/source/blender/io/collada/Materials.h
index 1886acb7a6a..e68f67bf049 100644
--- a/source/blender/io/collada/Materials.h
+++ b/source/blender/io/collada/Materials.h
@@ -45,6 +45,7 @@ class MaterialNode {
bNode *shader_node;
bNode *output_node;
+ /** Returns null if material already has a node tree. */
bNodeTree *prepare_material_nodetree();
bNode *add_node(int node_type, int locx, int locy, std::string label);
void add_link(bNode *from_node, int from_index, bNode *to_node, int to_index);
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index ef486375ce3..036819af6a3 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -267,7 +267,6 @@ void MeshImporter::print_index_list(COLLADAFW::IndexList &index_list)
}
#endif
-/* checks if mesh has supported primitive types: lines, polylist, triangles, triangle_fans */
bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh)
{
COLLADAFW::MeshPrimitiveArray &prim_arr = mesh->getMeshPrimitives();
@@ -356,12 +355,6 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
}
}
-/* =====================================================================
- * condition 1: The Primitive has normals
- * condition 2: The number of normals equals the number of faces.
- * return true if both conditions apply.
- * return false otherwise.
- * ===================================================================== */
bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp)
{
@@ -385,10 +378,6 @@ bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp)
return has_useable_normals;
}
-/* =====================================================================
- * Assume that only TRIANGLES, TRIANGLE_FANS, POLYLIST and POLYGONS
- * have faces. (to be verified)
- * ===================================================================== */
bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp)
{
@@ -420,12 +409,6 @@ static std::string extract_vcolname(const COLLADAFW::String &collada_id)
return colname;
}
-/* =================================================================
- * Return the number of faces by summing up
- * the face-counts of the parts.
- * hint: This is done because `mesh->getFacesCount()` does
- * count loose edges as extra faces, which is not what we want here.
- * ================================================================= */
void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
@@ -554,13 +537,6 @@ unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh)
return loose_edge_count;
}
-/* =================================================================
- * This function is copied from source/blender/editors/mesh/mesh_data.c
- *
- * TODO: (As discussed with sergey-) :
- * Maybe move this function to blenderkernel/intern/mesh.c
- * and add definition to BKE_mesh.c
- * ================================================================= */
void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
{
CustomData edata;
@@ -594,12 +570,6 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
mesh->totedge = totedge;
}
-/* =================================================================
- * Read all loose edges.
- * Important: This function assumes that all edges from existing
- * faces have already been generated and added to me->medge
- * So this function MUST be called after read_faces() (see below)
- * ================================================================= */
void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
{
unsigned int loose_edge_count = get_loose_edge_count(mesh);
@@ -633,13 +603,6 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
}
}
-/* =======================================================================
- * Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
- * Important: This function MUST be called before read_lines()
- * Otherwise we will lose all edges from faces (see read_lines() above)
- *
- * TODO: import uv set names
- * ======================================================================== */
void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
unsigned int i;
@@ -965,11 +928,6 @@ static void bc_remove_materials_from_object(Object *ob, Mesh *me)
}
}
-/**
- * Returns the list of Users of the given Mesh object.
- * NOTE: This function uses the object user flag to control
- * which objects have already been processed.
- */
std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
{
std::vector<Object *> mesh_users;
@@ -985,24 +943,6 @@ std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh)
return mesh_users;
}
-/**
- *
- * During import all materials have been assigned to Object.
- * Now we iterate over the imported objects and optimize
- * the assignments as follows:
- *
- * for each imported geometry:
- * if number of users is 1:
- * get the user (object)
- * move the materials from Object to Data
- * else:
- * determine which materials are assigned to the first user
- * check if all other users have the same materials in the same order
- * if the check is positive:
- * Add the materials of the first user to the geometry
- * adjust all other users accordingly.
- *
- */
void MeshImporter::optimize_material_assignements()
{
for (Object *ob : imported_objects) {
@@ -1035,14 +975,6 @@ void MeshImporter::optimize_material_assignements()
}
}
-/**
- * We do not know in advance which objects will share geometries.
- * And we do not know either if the objects which share geometries
- * come along with different materials. So we first create the objects
- * and assign the materials to Object, then in a later cleanup we decide
- * which materials shall be moved to the created geometries. Also see
- * optimize_material_assignements() above.
- */
void MeshImporter::assign_material_to_geom(
COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
@@ -1165,7 +1097,6 @@ Object *MeshImporter::create_mesh_object(
return ob;
}
-/* create a mesh storing a pointer in a map so it can be retrieved later by geometry UID */
bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
{
diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h
index 6f4f62b7f0f..95ac32a1b4c 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -122,23 +122,60 @@ class MeshImporter : public MeshImporterBase {
void print_index_list(COLLADAFW::IndexList &index_list);
#endif
+ /** Checks if mesh has supported primitive types: lines, polylist, triangles, triangle_fans. */
bool is_nice_mesh(COLLADAFW::Mesh *mesh);
void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me);
+ /**
+ * Condition 1: The Primitive has normals
+ * condition 2: The number of normals equals the number of faces.
+ * return true if both conditions apply.
+ * return false otherwise.
+ */
bool primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp);
+ /**
+ * Assume that only TRIANGLES, TRIANGLE_FANS, POLYLIST and POLYGONS
+ * have faces. (to be verified).
+ */
bool primitive_has_faces(COLLADAFW::MeshPrimitive *mp);
+ /**
+ * This function is copied from source/blender/editors/mesh/mesh_data.c
+ *
+ * TODO: (As discussed with sergey-) :
+ * Maybe move this function to `blenderkernel/intern/mesh.c`.
+ * and add definition to BKE_mesh.c.
+ */
static void mesh_add_edges(Mesh *mesh, int len);
unsigned int get_loose_edge_count(COLLADAFW::Mesh *mesh);
CustomData create_edge_custom_data(EdgeHash *eh);
+ /**
+ * Return the number of faces by summing up
+ * the face-counts of the parts.
+ * hint: This is done because `mesh->getFacesCount()` does
+ * count loose edges as extra faces, which is not what we want here.
+ */
void allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me);
/* TODO: import uv set names */
+ /**
+ * Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
+ * Important: This function MUST be called before read_lines()
+ * Otherwise we will lose all edges from faces (see read_lines() above)
+ *
+ * TODO: import uv set names.
+ */
void read_polys(COLLADAFW::Mesh *mesh, Mesh *me);
+ /**
+ * Read all loose edges.
+ * Important: This function assumes that all edges from existing
+ * faces have already been generated and added to me->medge
+ * So this function MUST be called after read_faces() (see below)
+ */
void read_lines(COLLADAFW::Mesh *mesh, Mesh *me);
unsigned int get_vertex_count(COLLADAFW::Polygons *mp, int index);
@@ -146,6 +183,11 @@ class MeshImporter : public MeshImporterBase {
bool is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData &nor, int count);
+ /**
+ * Returns the list of Users of the given Mesh object.
+ * NOTE: This function uses the object user flag to control
+ * which objects have already been processed.
+ */
std::vector<Object *> get_all_users_of(Mesh *reference_mesh);
public:
@@ -159,8 +201,34 @@ class MeshImporter : public MeshImporterBase {
virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid);
+ /**
+ *
+ * During import all materials have been assigned to Object.
+ * Now we iterate over the imported objects and optimize
+ * the assignments as follows:
+ *
+ * for each imported geometry:
+ * if number of users is 1:
+ * get the user (object)
+ * move the materials from Object to Data
+ * else:
+ * determine which materials are assigned to the first user
+ * check if all other users have the same materials in the same order
+ * if the check is positive:
+ * Add the materials of the first user to the geometry
+ * adjust all other users accordingly.
+ *
+ */
void optimize_material_assignements();
+ /**
+ * We do not know in advance which objects will share geometries.
+ * And we do not know either if the objects which share geometries
+ * come along with different materials. So we first create the objects
+ * and assign the materials to Object, then in a later cleanup we decide
+ * which materials shall be moved to the created geometries. Also see
+ * optimize_material_assignements() above.
+ */
void assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
Object *ob,
@@ -172,7 +240,7 @@ class MeshImporter : public MeshImporterBase {
bool isController,
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map);
- /* create a mesh storing a pointer in a map so it can be retrieved later by geometry UID */
+ /** Create a mesh storing a pointer in a map so it can be retrieved later by geometry UID. */
bool write_geometry(const COLLADAFW::Geometry *geom);
std::string *get_geometry_name(const std::string &mesh_name);
};
diff --git a/source/blender/io/collada/SkinInfo.cpp b/source/blender/io/collada/SkinInfo.cpp
index f0e1c5e4c26..3b740b9cd8c 100644
--- a/source/blender/io/collada/SkinInfo.cpp
+++ b/source/blender/io/collada/SkinInfo.cpp
@@ -53,9 +53,6 @@ template<class T> static const char *bc_get_joint_name(T *node)
return id.empty() ? node->getOriginalId().c_str() : id.c_str();
}
-/* This is used to store data passed in write_controller_data.
- * Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
- * so that arrays don't get freed until we free them explicitly. */
SkinInfo::SkinInfo() = default;
SkinInfo::SkinInfo(const SkinInfo &skin)
@@ -77,7 +74,6 @@ SkinInfo::SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(nullptr),
{
}
-/* nobody owns the data after this, so it should be freed manually with releaseMemory */
template<class T> void SkinInfo::transfer_array_data(T &src, T &dest)
{
dest.setData(src.getData(), src.getCount());
@@ -85,7 +81,6 @@ template<class T> void SkinInfo::transfer_array_data(T &src, T &dest)
dest.yieldOwnerShip();
}
-/* when src is const we cannot src.yieldOwnerShip, this is used by copy constructor */
void SkinInfo::transfer_int_array_data_const(const COLLADAFW::IntValuesArray &src,
COLLADAFW::IntValuesArray &dest)
{
@@ -124,9 +119,6 @@ void SkinInfo::free()
// weights.releaseMemory();
}
-/* using inverse bind matrices to construct armature
- * it is safe to invert them to get the original matrices
- * because if they are inverse matrices, they can be inverted */
void SkinInfo::add_joint(const COLLADABU::Math::Matrix4 &matrix)
{
JointData jd;
@@ -152,7 +144,6 @@ void SkinInfo::set_controller(const COLLADAFW::SkinController *co)
}
}
-/* called from write_controller */
Object *SkinInfo::create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
ob_arm = bc_add_object(bmain, scene, view_layer, OB_ARMATURE, nullptr);
@@ -193,11 +184,6 @@ const COLLADAFW::UniqueId &SkinInfo::get_controller_uid()
return controller_uid;
}
-/* check if this skin controller references a joint or any descendant of it
- *
- * some nodes may not be referenced by SkinController,
- * in this case to determine if the node belongs to this armature,
- * we need to search down the tree */
bool SkinInfo::uses_joint_or_descendant(COLLADAFW::Node *node)
{
const COLLADAFW::UniqueId &uid = node->getUniqueId();
diff --git a/source/blender/io/collada/SkinInfo.h b/source/blender/io/collada/SkinInfo.h
index 7ce66b22a5f..49a820f2fcd 100644
--- a/source/blender/io/collada/SkinInfo.h
+++ b/source/blender/io/collada/SkinInfo.h
@@ -35,9 +35,11 @@
#include "TransformReader.h"
#include "collada_internal.h"
-/* This is used to store data passed in write_controller_data.
- * Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
- * so that arrays don't get freed until we free them explicitly. */
+/**
+ * This is used to store data passed in write_controller_data.
+ * Arrays from #COLLADAFW::SkinControllerData lose ownership, so do this class members
+ * so that arrays don't get freed until we free them explicitly.
+ */
class SkinInfo {
private:
/* to build armature bones from inverse bind matrices */
@@ -69,10 +71,10 @@ class SkinInfo {
SkinInfo(const SkinInfo &skin);
SkinInfo(UnitConverter *conv);
- /* nobody owns the data after this, so it should be freed manually with releaseMemory */
+ /** Nobody owns the data after this, so it should be freed manually with releaseMemory. */
template<typename T> void transfer_array_data(T &src, T &dest);
- /* when src is const we cannot src.yieldOwnerShip, this is used by copy constructor */
+ /** When src is const we cannot `src.yieldOwnerShip`, this is used by copy constructor. */
void transfer_int_array_data_const(const COLLADAFW::IntValuesArray &src,
COLLADAFW::IntValuesArray &dest);
@@ -83,14 +85,16 @@ class SkinInfo {
void free();
- /* using inverse bind matrices to construct armature
+ /**
+ * Using inverse bind matrices to construct armature
* it is safe to invert them to get the original matrices
- * because if they are inverse matrices, they can be inverted */
+ * because if they are inverse matrices, they can be inverted.
+ */
void add_joint(const COLLADABU::Math::Matrix4 &matrix);
void set_controller(const COLLADAFW::SkinController *co);
- /* called from write_controller */
+ /** Called from write_controller. */
Object *create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer);
Object *set_armature(Object *ob_arm);
@@ -101,11 +105,13 @@ class SkinInfo {
const COLLADAFW::UniqueId &get_controller_uid();
- /* check if this skin controller references a joint or any descendant of it
+ /**
+ * Check if this skin controller references a joint or any descendant of it
*
* some nodes may not be referenced by SkinController,
* in this case to determine if the node belongs to this armature,
- * we need to search down the tree */
+ * we need to search down the tree.
+ */
bool uses_joint_or_descendant(COLLADAFW::Node *node);
void link_armature(bContext *C,
diff --git a/source/blender/io/collada/collada_internal.cpp b/source/blender/io/collada/collada_internal.cpp
index bd6f496c8ec..5592f5393a2 100644
--- a/source/blender/io/collada/collada_internal.cpp
+++ b/source/blender/io/collada/collada_internal.cpp
@@ -213,7 +213,6 @@ void clear_global_id_map()
global_id_map.clear();
}
-/** Look at documentation of translate_map */
std::string translate_id(const char *idString)
{
std::string id = std::string(idString);
diff --git a/source/blender/io/collada/collada_internal.h b/source/blender/io/collada/collada_internal.h
index e3894093507..cdd19ebe9a7 100644
--- a/source/blender/io/collada/collada_internal.h
+++ b/source/blender/io/collada/collada_internal.h
@@ -76,6 +76,7 @@ class UnitConverter {
extern void clear_global_id_map();
/** Look at documentation of translate_map */
extern std::string translate_id(const std::string &id);
+/** Look at documentation of translate_map */
extern std::string translate_id(const char *idString);
extern std::string id_name(void *id);
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index c1f25ea9a26..d3655c10655 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -92,9 +92,10 @@ float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray &array, unsigned in
return array.getDoubleValues()->getData()[index];
}
-/* copied from /editors/object/object_relations.c */
int bc_test_parent_loop(Object *par, Object *ob)
{
+ /* Copied from /editors/object/object_relations.c */
+
/* test if 'ob' is a parent somewhere in par's parents */
if (par == nullptr) {
@@ -289,9 +290,10 @@ bool bc_has_object_type(LinkNode *export_set, short obtype)
return false;
}
-/* Use bubble sort algorithm for sorting the export set */
void bc_bubble_sort_by_Object_name(LinkNode *export_set)
{
+ /* Use bubble sort algorithm for sorting the export set. */
+
bool sorted = false;
LinkNode *node;
for (node = export_set; node->next && !sorted; node = node->next) {
@@ -312,11 +314,6 @@ void bc_bubble_sort_by_Object_name(LinkNode *export_set)
}
}
-/* Check if a bone is the top most exportable bone in the bone hierarchy.
- * When deform_bones_only == false, then only bones with NO parent
- * can be root bones. Otherwise the top most deform bones in the hierarchy
- * are root bones.
- */
bool bc_is_root_bone(Bone *aBone, bool deform_bones_only)
{
if (deform_bones_only) {
@@ -360,12 +357,6 @@ std::string bc_replace_string(std::string data,
return data;
}
-/**
- * Calculate a rescale factor such that the imported scene's scale
- * is preserved. I.e. 1 meter in the import will also be
- * 1 meter in the current scene.
- */
-
void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene)
{
if (scale_to_scene) {
@@ -386,9 +377,6 @@ void bc_match_scale(std::vector<Object *> *objects_done,
}
}
-/*
- * Convenience function to get only the needed components of a matrix
- */
void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size)
{
if (size) {
@@ -408,17 +396,6 @@ void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], floa
}
}
-/*
- * Create rotation_quaternion from a delta rotation and a reference quat
- *
- * Input:
- * mat_from: The rotation matrix before rotation
- * mat_to : The rotation matrix after rotation
- * qref : the quat corresponding to mat_from
- *
- * Output:
- * rot : the calculated result (quaternion)
- */
void bc_rotate_from_reference_quat(float quat_to[4], float quat_from[4], float mat_to[4][4])
{
float qd[4];
@@ -457,9 +434,6 @@ void bc_triangulate_mesh(Mesh *me)
BM_mesh_free(bm);
}
-/*
- * A bone is a leaf when it has no children or all children are not connected.
- */
bool bc_is_leaf_bone(Bone *bone)
{
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
@@ -501,11 +475,6 @@ int bc_set_layer(int bitfield, int layer, bool enable)
return bitfield;
}
-/**
- * This method creates a new extension map when needed.
- * \note The ~BoneExtensionManager destructor takes care
- * to delete the created maps when the manager is removed.
- */
BoneExtensionMap &BoneExtensionManager::getExtensionMap(bArmature *armature)
{
std::string key = armature->id.name;
@@ -535,7 +504,6 @@ BoneExtensionManager::~BoneExtensionManager()
* See ArmatureImporter::fix_leaf_bones()
* and ArmatureImporter::connect_bone_chains()
*/
-
BoneExtended::BoneExtended(EditBone *aBone)
{
this->set_name(aBone->name);
@@ -697,9 +665,6 @@ int BoneExtended::get_use_connect()
return this->use_connect;
}
-/**
- * Stores a 4*4 matrix as a custom bone property array of size 16
- */
void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4])
{
IDProperty *idgroup = (IDProperty *)ebone->prop;
@@ -745,19 +710,11 @@ static void bc_set_IDProperty(EditBone *ebone, const char *key, float value)
}
#endif
-/**
- * Get a custom property when it exists.
- * This function is also used to check if a property exists.
- */
IDProperty *bc_get_IDProperty(Bone *bone, std::string key)
{
return (bone->prop == nullptr) ? nullptr : IDP_GetPropertyFromGroup(bone->prop, key.c_str());
}
-/**
- * Read a custom bone property and convert to float
- * Return def if the property does not exist.
- */
float bc_get_property(Bone *bone, std::string key, float def)
{
float result = def;
@@ -780,14 +737,6 @@ float bc_get_property(Bone *bone, std::string key, float def)
return result;
}
-/**
- * Read a custom bone property and convert to matrix
- * Return true if conversion was successful
- *
- * Return false if:
- * - the property does not exist
- * - is not an array of size 16
- */
bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
{
IDProperty *property = bc_get_IDProperty(bone, key);
@@ -803,9 +752,6 @@ bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4])
return false;
}
-/**
- * get a vector that is stored in 3 custom properties (used in Blender <= 2.78)
- */
void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3])
{
val[0] = bc_get_property(bone, key + "_x", def[0]);
@@ -1014,12 +960,6 @@ void bc_apply_global_transform(Vector &to_vec, const BCMatrix &global_transform,
mul_v3_m4v3(to_vec, transform, to_vec);
}
-/**
- * Check if custom information about bind matrix exists and modify the from_mat
- * accordingly.
- *
- * NOTE: This is old style for Blender <= 2.78 only kept for compatibility
- */
void bc_create_restpose_mat(BCExportSettings &export_settings,
Bone *bone,
float to_mat[4][4],
diff --git a/source/blender/io/collada/collada_utils.h b/source/blender/io/collada/collada_utils.h
index d0a5d37d6d2..cf62ea0a275 100644
--- a/source/blender/io/collada/collada_utils.h
+++ b/source/blender/io/collada/collada_utils.h
@@ -143,6 +143,12 @@ extern char *bc_CustomData_get_layer_name(const CustomData *data, int type, int
extern char *bc_CustomData_get_active_layer_name(const CustomData *data, int type);
extern void bc_bubble_sort_by_Object_name(LinkNode *export_set);
+/**
+ * Check if a bone is the top most exportable bone in the bone hierarchy.
+ * When deform_bones_only == false, then only bones with NO parent
+ * can be root bones. Otherwise the top most deform bones in the hierarchy
+ * are root bones.
+ */
extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only);
extern int bc_get_active_UVLayer(Object *ob);
@@ -195,17 +201,39 @@ extern std::string bc_replace_string(std::string data,
const std::string &pattern,
const std::string &replacement);
extern std::string bc_url_encode(std::string data);
+/**
+ * Calculate a rescale factor such that the imported scene's scale
+ * is preserved. I.e. 1 meter in the import will also be
+ * 1 meter in the current scene.
+ */
extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene);
extern void bc_match_scale(std::vector<Object *> *objects_done,
UnitConverter &bc_unit,
bool scale_to_scene);
+/**
+ * Convenience function to get only the needed components of a matrix.
+ */
extern void bc_decompose(float mat[4][4], float *loc, float eul[3], float quat[4], float *size);
+/**
+ * Create rotation_quaternion from a delta rotation and a reference quat
+ *
+ * Input:
+ * mat_from: The rotation matrix before rotation
+ * mat_to : The rotation matrix after rotation
+ * qref : the quat corresponding to mat_from
+ *
+ * Output:
+ * rot : the calculated result (quaternion).
+ */
extern void bc_rotate_from_reference_quat(float quat_to[4],
float quat_from[4],
float mat_to[4][4]);
extern void bc_triangulate_mesh(Mesh *me);
+/**
+ * A bone is a leaf when it has no children or all children are not connected.
+ */
extern bool bc_is_leaf_bone(Bone *bone);
extern EditBone *bc_get_edit_bone(bArmature *armature, char *name);
extern int bc_set_layer(int bitfield, int layer, bool enable);
@@ -224,12 +252,34 @@ void bc_copy_v44_m4d(std::vector<std::vector<double>> &r, double (&a)[4][4]);
void bc_sanitize_v3(double v[3], int precision);
void bc_sanitize_v3(float v[3], int precision);
+/**
+ * Get a custom property when it exists.
+ * This function is also used to check if a property exists.
+ */
extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key);
extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value);
+/**
+ * Stores a 4*4 matrix as a custom bone property array of size 16.
+ */
extern void bc_set_IDPropertyMatrix(EditBone *ebone, const char *key, float mat[4][4]);
+/**
+ * Read a custom bone property and convert to float
+ * Return def if the property does not exist.
+ */
extern float bc_get_property(Bone *bone, std::string key, float def);
+/**
+ * Get a vector that is stored in 3 custom properties (used in Blender <= 2.78).
+ */
extern void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]);
+/**
+ * Read a custom bone property and convert to matrix
+ * Return true if conversion was successful
+ *
+ * Return false if:
+ * - the property does not exist
+ * - is not an array of size 16
+ */
extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]);
extern void bc_enable_fcurves(bAction *act, char *bone_name);
@@ -258,6 +308,12 @@ extern void bc_apply_global_transform(Matrix &to_mat,
extern void bc_apply_global_transform(Vector &to_vec,
const BCMatrix &global_transform,
const bool invert = false);
+/**
+ * Check if custom information about bind matrix exists and modify the from_mat
+ * accordingly.
+ *
+ * \note This is old style for Blender <= 2.78 only kept for compatibility.
+ */
extern void bc_create_restpose_mat(BCExportSettings &export_settings,
Bone *bone,
float to_mat[4][4],
@@ -364,6 +420,11 @@ class BoneExtensionManager {
std::map<std::string, BoneExtensionMap *> extended_bone_maps;
public:
+ /**
+ * This method creates a new extension map when needed.
+ * \note The ~BoneExtensionManager destructor takes care
+ * to delete the created maps when the manager is removed.
+ */
BoneExtensionMap &getExtensionMap(bArmature *armature);
~BoneExtensionManager();
};
diff --git a/source/blender/io/gpencil/gpencil_io.h b/source/blender/io/gpencil/gpencil_io.h
index cb004910c1e..ea328a531c6 100644
--- a/source/blender/io/gpencil/gpencil_io.h
+++ b/source/blender/io/gpencil/gpencil_io.h
@@ -85,7 +85,13 @@ typedef enum eGpencilExportFrame {
GP_EXPORT_FRAME_SCENE = 2,
} eGpencilExportFrame;
+/**
+ * Main export entry point function.
+ */
bool gpencil_io_export(const char *filename, struct GpencilIOParams *iparams);
+/**
+ * Main import entry point function.
+ */
bool gpencil_io_import(const char *filename, struct GpencilIOParams *iparams);
#ifdef __cplusplus
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc
index 294f6bfccb7..f031648d2ed 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc
@@ -145,7 +145,6 @@ void GpencilIO::prepare_camera_params(Scene *scene, const GpencilIOParams *ipara
}
}
-/** Create a list of selected objects sorted from back to front */
void GpencilIO::create_object_list()
{
ViewLayer *view_layer = CTX_data_view_layer(params_.C);
@@ -194,17 +193,12 @@ void GpencilIO::create_object_list()
});
}
-/**
- * Set file input_text full path.
- * \param filename: Path of the file provided by save dialog.
- */
void GpencilIO::filename_set(const char *filename)
{
BLI_strncpy(filename_, filename, FILE_MAX);
BLI_path_abs(filename_, BKE_main_blendfile_path(bmain_));
}
-/** Convert to screenspace. */
bool GpencilIO::gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co)
{
float3 parent_co = diff_mat_ * co;
@@ -244,7 +238,6 @@ bool GpencilIO::gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co)
return false;
}
-/** Convert to render space. */
float2 GpencilIO::gpencil_3D_point_to_render_space(const float3 co)
{
float3 parent_co = diff_mat_ * co;
@@ -266,7 +259,6 @@ float2 GpencilIO::gpencil_3D_point_to_render_space(const float3 co)
return r_co;
}
-/** Convert to 2D. */
float2 GpencilIO::gpencil_3D_point_to_2D(const float3 co)
{
const bool is_camera = (bool)(rv3d_->persp == RV3D_CAMOB);
@@ -278,7 +270,6 @@ float2 GpencilIO::gpencil_3D_point_to_2D(const float3 co)
return result;
}
-/** Get radius of point. */
float GpencilIO::stroke_point_radius_get(bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt = &gps->points[0];
@@ -338,7 +329,6 @@ bool GpencilIO::is_camera_mode()
return is_camera_;
}
-/* Calculate selected strokes boundbox. */
void GpencilIO::selected_objects_boundbox_calc()
{
const float gap = 10.0f;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.hh b/source/blender/io/gpencil/intern/gpencil_io_base.hh
index 02758883f19..6437796648d 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.hh
@@ -87,11 +87,16 @@ class GpencilIO {
float stroke_color_[4], fill_color_[4];
/* Geometry functions. */
+ /** Convert to screenspace. */
bool gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co);
+ /** Convert to render space. */
float2 gpencil_3D_point_to_render_space(const float3 co);
+ /** Convert to 2D. */
float2 gpencil_3D_point_to_2D(const float3 co);
+ /** Get radius of point. */
float stroke_point_radius_get(struct bGPDlayer *gpl, struct bGPDstroke *gps);
+ /** Create a list of selected objects sorted from back to front */
void create_object_list();
bool is_camera_mode();
@@ -101,8 +106,13 @@ class GpencilIO {
void prepare_layer_export_matrix(struct Object *ob, struct bGPDlayer *gpl);
void prepare_stroke_export_colors(struct Object *ob, struct bGPDstroke *gps);
+ /* Calculate selected strokes boundbox. */
void selected_objects_boundbox_calc();
void selected_objects_boundbox_get(rctf *boundbox);
+ /**
+ * Set file input_text full path.
+ * \param filename: Path of the file provided by save dialog.
+ */
void filename_set(const char *filename);
private:
diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
index 95f5839682f..92ce165e059 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_capi.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
@@ -177,7 +177,6 @@ static bool gpencil_io_export_frame_svg(GpencilExporterSVG *exporter,
}
#endif
-/* Main import entry point function. */
bool gpencil_io_import(const char *filename, GpencilIOParams *iparams)
{
GpencilImporterSVG importer = GpencilImporterSVG(filename, iparams);
@@ -185,7 +184,6 @@ bool gpencil_io_import(const char *filename, GpencilIOParams *iparams)
return gpencil_io_import_frame(&importer, *iparams);
}
-/* Main export entry point function. */
bool gpencil_io_export(const char *filename, GpencilIOParams *iparams)
{
Depsgraph *depsgraph_ = CTX_data_depsgraph_pointer(iparams->C);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
index 82f8444d43e..7539fba1343 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
@@ -109,7 +109,6 @@ bool GpencilExporterPDF::write()
return (res == 0) ? true : false;
}
-/* Create pdf document. */
bool GpencilExporterPDF::create_document()
{
pdf_ = HPDF_New(error_handler, nullptr);
@@ -120,7 +119,6 @@ bool GpencilExporterPDF::create_document()
return true;
}
-/* Add page. */
bool GpencilExporterPDF::add_page()
{
/* Add a new page object. */
@@ -136,7 +134,6 @@ bool GpencilExporterPDF::add_page()
return true;
}
-/* Main layer loop. */
void GpencilExporterPDF::export_gpencil_layers()
{
/* If is doing a set of frames, the list of objects can change for each frame. */
@@ -229,10 +226,6 @@ void GpencilExporterPDF::export_gpencil_layers()
}
}
-/**
- * Export a stroke using polyline or polygon
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
bGPDstroke *gps,
const bool is_stroke,
@@ -288,10 +281,6 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
HPDF_Page_GRestore(page_);
}
-/**
- * Set color.
- * \param do_fill: True if the stroke is only fill.
- */
void GpencilExporterPDF::color_set(bGPDlayer *gpl, const bool do_fill)
{
const float fill_opacity = fill_color_[3] * gpl->opacity;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
index 89d97f79783..18de321914c 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
@@ -45,20 +45,31 @@ class GpencilExporterPDF : public GpencilExporter {
protected:
private:
- /* PDF document. */
+ /** PDF document. */
HPDF_Doc pdf_;
- /* PDF page. */
+ /** PDF page. */
HPDF_Page page_;
+ /** Create PDF document. */
bool create_document();
+ /** Add page. */
bool add_page();
+ /** Main layer loop. */
void export_gpencil_layers();
+ /**
+ * Export a stroke using poly-line or polygon
+ * \param do_fill: True if the stroke is only fill
+ */
void export_stroke_to_polyline(bGPDlayer *gpl,
bGPDstroke *gps,
const bool is_stroke,
const bool do_fill,
const bool normalize);
+ /**
+ * Set color.
+ * \param do_fill: True if the stroke is only fill.
+ */
void color_set(bGPDlayer *gpl, const bool do_fill);
};
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
index a9745415d40..09eac7a2813 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
@@ -97,7 +97,6 @@ bool GpencilExporterSVG::write()
return result;
}
-/* Create document header and main svg node. */
void GpencilExporterSVG::create_document_header()
{
/* Add a custom document declaration node. */
@@ -133,7 +132,6 @@ void GpencilExporterSVG::create_document_header()
main_node_.append_attribute("viewBox").set_value(viewbox.c_str());
}
-/* Main layer loop. */
void GpencilExporterSVG::export_gpencil_layers()
{
const bool is_clipping = is_camera_mode() && (params_.flag & GP_EXPORT_CLIP_CAMERA) != 0;
@@ -254,11 +252,6 @@ void GpencilExporterSVG::export_gpencil_layers()
}
}
-/**
- * Export a stroke using SVG path
- * \param node_gpl: Node of the layer.
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterSVG::export_stroke_to_path(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gpl,
@@ -303,11 +296,6 @@ void GpencilExporterSVG::export_stroke_to_path(bGPDlayer *gpl,
node_gps.append_attribute("d").set_value(txt.c_str());
}
-/**
- * Export a stroke using polyline or polygon
- * \param node_gpl: Node of the layer.
- * \param do_fill: True if the stroke is only fill
- */
void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gpl,
@@ -351,11 +339,6 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
node_gps.append_attribute("points").set_value(txt.c_str());
}
-/**
- * Set color SVG string for stroke
- * \param node_gps: Stroke node.
- * \param do_fill: True if the stroke is only fill.
- */
void GpencilExporterSVG::color_string_set(bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gps,
@@ -392,16 +375,6 @@ void GpencilExporterSVG::color_string_set(bGPDlayer *gpl,
}
}
-/**
- * Create a SVG rectangle
- * \param node: Parent node
- * \param x: X location
- * \param y: Y location
- * \param width: width of the rectangle
- * \param height: Height of the rectangle
- * \param thickness: Thickness of the line
- * \param hexcolor: Color of the line
- */
void GpencilExporterSVG::add_rect(pugi::xml_node node,
float x,
float y,
@@ -422,15 +395,6 @@ void GpencilExporterSVG::add_rect(pugi::xml_node node,
}
}
-/**
- * Create SVG text
- * \param node: Parent node
- * \param x: X location
- * \param y: Y location
- * \param text: Text to include
- * \param size: Size of the text
- * \param hexcolor: Color of the text
- */
void GpencilExporterSVG::add_text(pugi::xml_node node,
float x,
float y,
@@ -448,7 +412,6 @@ void GpencilExporterSVG::add_text(pugi::xml_node node,
nodetxt.text().set(text.c_str());
}
-/** Convert a color to Hex value (#FFFFFF). */
std::string GpencilExporterSVG::rgb_to_hexstr(const float color[3])
{
uint8_t r = color[0] * 255.0f;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
index 6d8a0c2f6ac..b3175978072 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
@@ -42,6 +42,16 @@ class GpencilExporterSVG : public GpencilExporter {
bool write();
protected:
+ /**
+ * Create a SVG rectangle
+ * \param node: Parent node
+ * \param x: X location
+ * \param y: Y location
+ * \param width: width of the rectangle
+ * \param height: Height of the rectangle
+ * \param thickness: Thickness of the line
+ * \param hexcolor: Color of the line
+ */
static void add_rect(pugi::xml_node node,
float x,
float y,
@@ -50,6 +60,15 @@ class GpencilExporterSVG : public GpencilExporter {
float thickness,
std::string hexcolor);
+ /**
+ * Create SVG text
+ * \param node: Parent node
+ * \param x: X location
+ * \param y: Y location
+ * \param text: Text to include
+ * \param size: Size of the text
+ * \param hexcolor: Color of the text
+ */
static void add_text(pugi::xml_node node,
float x,
float y,
@@ -58,31 +77,49 @@ class GpencilExporterSVG : public GpencilExporter {
std::string hexcolor);
private:
- /* XML doc. */
+ /** XML doc. */
pugi::xml_document main_doc_;
- /* Main document node. */
+ /** Main document node. */
pugi::xml_node main_node_;
/** Frame node. */
pugi::xml_node frame_node_;
+ /** Create document header and main SVG node. */
void create_document_header();
+ /** Main layer loop. */
void export_gpencil_layers();
+ /**
+ * Export a stroke using SVG path
+ * \param node_gpl: Node of the layer.
+ * \param do_fill: True if the stroke is only fill
+ */
void export_stroke_to_path(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gpl,
const bool do_fill);
+ /**
+ * Export a stroke using poly-line or polygon
+ * \param node_gpl: Node of the layer.
+ * \param do_fill: True if the stroke is only fill
+ */
void export_stroke_to_polyline(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gpl,
const bool is_stroke,
const bool do_fill);
+ /**
+ * Set color SVG string for stroke
+ * \param node_gps: Stroke node.
+ * \param do_fill: True if the stroke is only fill.
+ */
void color_string_set(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gps,
const bool do_fill);
+ /** Convert a color to Hex value (#FFFFFF). */
std::string rgb_to_hexstr(const float color[3]);
};
diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc
index efa31df25c1..0cc3fde8c6c 100644
--- a/source/blender/io/usd/intern/usd_capi_export.cc
+++ b/source/blender/io/usd/intern/usd_capi_export.cc
@@ -223,7 +223,7 @@ bool USD_export(bContext *C,
return export_ok;
}
-int USD_get_version(void)
+int USD_get_version()
{
/* USD 19.11 defines:
*
diff --git a/source/blender/io/usd/intern/usd_reader_curve.cc b/source/blender/io/usd/intern/usd_reader_curve.cc
index 12de1d82c72..5007d204020 100644
--- a/source/blender/io/usd/intern/usd_reader_curve.cc
+++ b/source/blender/io/usd/intern/usd_reader_curve.cc
@@ -108,11 +108,11 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
* Perhaps to be replaced by Blender/USD Schema. */
if (!usdNormals.empty()) {
/* Set extrusion to 1.0f. */
- curve_->ext1 = 1.0f;
+ curve_->extrude = 1.0f;
}
else {
/* Set bevel depth to 1.0f. */
- curve_->ext2 = 1.0f;
+ curve_->bevel_radius = 1.0f;
}
size_t idx = 0;
@@ -164,7 +164,7 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime
bp->f1 = SELECT;
bp->weight = weight;
- float radius = curve_->width;
+ float radius = curve_->offset;
if (idx < usdWidths.size()) {
radius = usdWidths[idx];
}
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc
index 317dfd2a62b..db0c5785a68 100644
--- a/source/blender/io/usd/intern/usd_reader_material.cc
+++ b/source/blender/io/usd/intern/usd_reader_material.cc
@@ -298,7 +298,6 @@ Material *USDMaterialReader::add_material(const pxr::UsdShadeMaterial &usd_mater
return mtl;
}
-/* Create the Principled BSDF shader node network. */
void USDMaterialReader::import_usd_preview(Material *mtl,
const pxr::UsdShadeShader &usd_shader) const
{
@@ -416,7 +415,6 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled,
}
}
-/* Convert the given USD shader input to an input on the given Blender node. */
void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -484,8 +482,6 @@ void USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
}
}
-/* Follow the connected source of the USD input to create corresponding inputs
- * for the given Blender node. */
void USDMaterialReader::follow_connection(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -594,8 +590,6 @@ void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_sh
}
}
-/* Load the texture image node's texture from the path given by the USD shader's
- * file input value. */
void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
bNode *tex_image) const
{
@@ -653,10 +647,6 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
}
}
-/* This function creates a Blender UV Map node, under the simplifying assumption that
- * UsdPrimvarReader_float2 shaders output UV coordinates.
- * TODO(makowalski): investigate supporting conversion to other Blender node types
- * (e.g., Attribute Nodes) if needed. */
void USDMaterialReader::convert_usd_primvar_reader_float2(
const pxr::UsdShadeShader &usd_shader,
const pxr::TfToken & /* usd_source_name */,
diff --git a/source/blender/io/usd/intern/usd_reader_material.h b/source/blender/io/usd/intern/usd_reader_material.h
index a17504bd590..fb40b4f2f6d 100644
--- a/source/blender/io/usd/intern/usd_reader_material.h
+++ b/source/blender/io/usd/intern/usd_reader_material.h
@@ -90,12 +90,14 @@ class USDMaterialReader {
Material *add_material(const pxr::UsdShadeMaterial &usd_material) const;
protected:
+ /** Create the Principled BSDF shader node network. */
void import_usd_preview(Material *mtl, const pxr::UsdShadeShader &usd_shader) const;
void set_principled_node_inputs(bNode *principled_node,
bNodeTree *ntree,
const pxr::UsdShadeShader &usd_shader) const;
+ /** Convert the given USD shader input to an input on the given Blender node. */
void set_node_input(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -103,6 +105,10 @@ class USDMaterialReader {
int column,
NodePlacementContext *r_ctx) const;
+ /**
+ * Follow the connected source of the USD input to create corresponding inputs
+ * for the given Blender node.
+ */
void follow_connection(const pxr::UsdShadeInput &usd_input,
bNode *dest_node,
const char *dest_socket_name,
@@ -118,8 +124,18 @@ class USDMaterialReader {
int column,
NodePlacementContext *r_ctx) const;
+ /**
+ * Load the texture image node's texture from the path given by the USD shader's
+ * file input value.
+ */
void load_tex_image(const pxr::UsdShadeShader &usd_shader, bNode *tex_image) const;
+ /**
+ * This function creates a Blender UV Map node, under the simplifying assumption that
+ * UsdPrimvarReader_float2 shaders output UV coordinates.
+ * TODO(makowalski): investigate supporting conversion to other Blender node types
+ * (e.g., Attribute Nodes) if needed.
+ */
void convert_usd_primvar_reader_float2(const pxr::UsdShadeShader &usd_shader,
const pxr::TfToken &usd_source_name,
bNode *dest_node,
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 5c8bd88e87a..3ad1d4adf18 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -589,7 +589,6 @@ void USDMeshReader::process_normals_face_varying(Mesh *mesh)
MEM_freeN(lnors);
}
-/* Set USD uniform (per-face) normals as Blender loop normals. */
void USDMeshReader::process_normals_uniform(Mesh *mesh)
{
if (normals_.empty()) {
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
index 54ad144d191..9ed73ba5a28 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.h
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -75,6 +75,7 @@ class USDMeshReader : public USDGeomReader {
private:
void process_normals_vertex_varying(Mesh *mesh);
void process_normals_face_varying(Mesh *mesh);
+ /** Set USD uniform (per-face) normals as Blender loop normals. */
void process_normals_uniform(Mesh *mesh);
void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime);
void assign_facesets_to_mpoly(double motionSampleTime,
diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.cc b/source/blender/io/usd/intern/usd_reader_nurbs.cc
index d6977d9c91a..8370804b776 100644
--- a/source/blender/io/usd/intern/usd_reader_nurbs.cc
+++ b/source/blender/io/usd/intern/usd_reader_nurbs.cc
@@ -112,11 +112,11 @@ void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime)
* Perhaps to be replaced by Blender USD Schema. */
if (!usdNormals.empty()) {
/* Set extrusion to 1. */
- curve_->ext1 = 1.0f;
+ curve_->extrude = 1.0f;
}
else {
/* Set bevel depth to 1. */
- curve_->ext2 = 1.0f;
+ curve_->bevel_radius = 1.0f;
}
size_t idx = 0;
diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc
index 8c4cc18a9af..9df5611bec9 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.cc
+++ b/source/blender/io/usd/intern/usd_reader_stage.cc
@@ -110,11 +110,6 @@ USDPrimReader *USDStageReader::create_reader(const pxr::UsdPrim &prim)
return nullptr;
}
-/* Returns true if the given prim should be included in the
- * traversal based on the import options and the prim's visibility
- * attribute. Note that the prim will be trivially included
- * if it has no visibility attribute or if the visibility
- * is inherited. */
bool USDStageReader::include_by_visibility(const pxr::UsdGeomImageable &imageable) const
{
if (!params_.import_visible_only) {
@@ -140,11 +135,6 @@ bool USDStageReader::include_by_visibility(const pxr::UsdGeomImageable &imageabl
return visibility != pxr::UsdGeomTokens->invisible;
}
-/* Returns true if the given prim should be included in the
- * traversal based on the import options and the prim's purpose
- * attribute. E.g., return false (to exclude the prim) if the prim
- * represents guide geometry and the 'Import Guide' option is
- * toggled off. */
bool USDStageReader::include_by_purpose(const pxr::UsdGeomImageable &imageable) const
{
if (params_.import_guide && params_.import_proxy && params_.import_render) {
diff --git a/source/blender/io/usd/intern/usd_reader_stage.h b/source/blender/io/usd/intern/usd_reader_stage.h
index ba223962c0c..df5f83067c1 100644
--- a/source/blender/io/usd/intern/usd_reader_stage.h
+++ b/source/blender/io/usd/intern/usd_reader_stage.h
@@ -82,8 +82,22 @@ class USDStageReader {
private:
USDPrimReader *collect_readers(Main *bmain, const pxr::UsdPrim &prim);
+ /**
+ * Returns true if the given prim should be included in the
+ * traversal based on the import options and the prim's visibility
+ * attribute. Note that the prim will be trivially included
+ * if it has no visibility attribute or if the visibility
+ * is inherited.
+ */
bool include_by_visibility(const pxr::UsdGeomImageable &imageable) const;
+ /**
+ * Returns true if the given prim should be included in the
+ * traversal based on the import options and the prim's purpose
+ * attribute. E.g., return false (to exclude the prim) if the prim
+ * represents guide geometry and the 'Import Guide' option is
+ * toggled off.
+ */
bool include_by_purpose(const pxr::UsdGeomImageable &imageable) const;
};
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc
index 6965ecf6249..2b5326eb4c1 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.cc
+++ b/source/blender/io/usd/intern/usd_writer_abstract.cc
@@ -121,7 +121,6 @@ void USDAbstractWriter::write_visibility(const HierarchyContext &context,
usd_value_writer_.SetAttribute(attr_visibility, pxr::VtValue(visibility), timecode);
}
-/* Reference the original data instead of writing a copy. */
bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim)
{
BLI_assert(context.is_instance());
@@ -134,7 +133,7 @@ bool USDAbstractWriter::mark_as_instance(const HierarchyContext &context, const
pxr::SdfPath ref_path(context.original_export_path);
if (!prim.GetReferences().AddInternalReference(ref_path)) {
- /* See this URL for a description fo why referencing may fail"
+ /* See this URL for a description for why referencing may fail"
* https://graphics.pixar.com/usd/docs/api/class_usd_references.html#Usd_Failing_References
*/
printf("USD Export warning: unable to add reference from %s to %s, not instancing object\n",
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h
index 6f143a7e241..dd81dd47c83 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.h
+++ b/source/blender/io/usd/intern/usd_writer_abstract.h
@@ -52,13 +52,15 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
virtual void write(HierarchyContext &context) override;
- /* Returns true if the data to be written is actually supported. This would, for example, allow a
+ /**
+ * Returns true if the data to be written is actually supported. This would, for example, allow a
* hypothetical camera writer accept a perspective camera but reject an orthogonal one.
*
* Returning false from a transform writer will prevent the object and all its descendants from
* being exported. Returning false from a data writer (object data, hair, or particles) will
* only prevent that data from being written (and thus cause the object to be exported as an
- * Empty). */
+ * Empty).
+ */
virtual bool is_supported(const HierarchyContext *context) const;
const pxr::SdfPath &usd_path() const;
@@ -73,8 +75,12 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
const pxr::UsdTimeCode timecode,
pxr::UsdGeomImageable &usd_geometry);
- /* Turn `prim` into an instance referencing `context.original_export_path`.
- * Return true when the instancing was successful, false otherwise. */
+ /**
+ * Turn `prim` into an instance referencing `context.original_export_path`.
+ * Return true when the instancing was successful, false otherwise.
+ *
+ * Reference the original data instead of writing a copy.
+ */
virtual bool mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim);
};
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 2c04d0b06ef..6a478f9abb5 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -461,7 +461,7 @@ typedef struct LibraryWeakReference {
enum ePreviewImage_Flag {
PRV_CHANGED = (1 << 0),
PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */
- PRV_UNFINISHED = (1 << 2), /* The preview is not done rendering yet. */
+ PRV_RENDERING = (1 << 2), /* Rendering was invoked. Cleared on file read. */
};
/* for PreviewImage->tag */
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index e899e6bd3ec..8e7551e1703 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -682,6 +682,10 @@ typedef struct bAction {
int idroot;
char _pad[4];
+ /** Start and end of the manually set intended playback frame range. Used by UI and
+ * some editing tools, but doesn't directly affect animation evaluation in any way. */
+ float frame_start, frame_end;
+
PreviewImage *preview;
} bAction;
@@ -695,6 +699,10 @@ typedef enum eAction_Flags {
ACT_MUTED = (1 << 9),
/* ACT_PROTECTED = (1 << 10), */ /* UNUSED */
/* ACT_DISABLED = (1 << 11), */ /* UNUSED */
+ /** The action has a manually set intended playback frame range. */
+ ACT_FRAME_RANGE = (1 << 12),
+ /** The action is intended to be a cycle (requires ACT_FRAME_RANGE). */
+ ACT_CYCLIC = (1 << 13),
} eAction_Flags;
/* ************************************************ */
diff --git a/source/blender/makesdna/DNA_curve_defaults.h b/source/blender/makesdna/DNA_curve_defaults.h
index 557615fd047..614653db2b8 100644
--- a/source/blender/makesdna/DNA_curve_defaults.h
+++ b/source/blender/makesdna/DNA_curve_defaults.h
@@ -34,7 +34,7 @@
.pathlen = 100, \
.resolu = 12, \
.resolv = 12, \
- .width = 1.0, \
+ .offset = 1.0, \
.wordspace = 1.0, \
.spacing = 1.0f, \
.linedist = 1.0, \
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index a2433dbbbbd..c1c8fe06121 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -228,16 +228,15 @@ typedef struct Curve {
/** Creation-time type of curve datablock. */
short type;
- /** Keep a short because of BKE_object_obdata_texspace_get(). */
- short texflag;
- char _pad0[6];
+ char texflag;
+ char _pad0[7];
short twist_mode;
float twist_smooth, smallcaps_scale;
int pathlen;
short bevresol, totcol;
int flag;
- float width, ext1, ext2;
+ float offset, extrude, bevel_radius;
/* default */
short resolu, resolv;
@@ -421,10 +420,8 @@ enum {
enum {
CU_POLY = 0,
CU_BEZIER = 1,
- CU_BSPLINE = 2,
- CU_CARDINAL = 3,
CU_NURBS = 4,
- CU_TYPE = (CU_POLY | CU_BEZIER | CU_BSPLINE | CU_CARDINAL | CU_NURBS),
+ CU_TYPE = (CU_POLY | CU_BEZIER | CU_NURBS),
/* only for adding */
CU_PRIMITIVE = 0xF00,
@@ -457,6 +454,8 @@ enum {
typedef enum eBezTriple_Flag {
/* SELECT */
BEZT_FLAG_TEMP_TAG = (1 << 1), /* always clear. */
+ /* Can be used to ignore keyframe points for certain operations. */
+ BEZT_FLAG_IGNORE_TAG = (1 << 2),
} eBezTriple_Flag;
/* h1 h2 (beztriple) */
diff --git a/source/blender/makesdna/DNA_defaults.h b/source/blender/makesdna/DNA_defaults.h
index 1549e33b267..6e986129143 100644
--- a/source/blender/makesdna/DNA_defaults.h
+++ b/source/blender/makesdna/DNA_defaults.h
@@ -36,7 +36,9 @@ extern "C" {
extern const void *DNA_default_table[SDNA_TYPE_MAX];
-char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str);
+uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
+ size_t size,
+ const char *alloc_str);
/**
* Wrap with macro that casts correctly.
diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h
index 3de13169616..2e086a2834c 100644
--- a/source/blender/makesdna/DNA_effect_types.h
+++ b/source/blender/makesdna/DNA_effect_types.h
@@ -27,7 +27,7 @@
extern "C" {
#endif
-/* Don't forget, new effects also in writefile.c for DNA! */
+/* Don't forget, new effects also in `writefile.c` for DNA! */
#define PAF_MAXMULT 4
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index a0285215ff9..3b6fb60cc2e 100644
--- a/source/blender/makesdna/DNA_fileglobal_types.h
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -50,7 +50,7 @@ typedef struct FileGlobal {
/** Hash from buildinfo. */
char build_hash[16];
/** File path where this was saved, for recover (1024 = FILE_MAX). */
- char filename[1024];
+ char filepath[1024];
} FileGlobal;
/* minversion: in file, the oldest past blender version you can use compliant */
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index fda1cbaeae6..5e0cff9fd83 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -83,6 +83,9 @@ enum eSDNA_StructCompare {
SDNA_CMP_UNKNOWN = 3,
};
+/**
+ * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
+ */
struct SDNA *DNA_sdna_from_data(const void *data,
const int data_len,
bool do_endian_swap,
@@ -97,22 +100,58 @@ const struct SDNA *DNA_sdna_current_get(void);
void DNA_sdna_current_free(void);
struct DNA_ReconstructInfo;
+/**
+ * Pre-process information about how structs in \a newsdna can be reconstructed from structs in
+ * \a oldsdna. This information is then used to speedup #DNA_struct_reconstruct.
+ */
struct DNA_ReconstructInfo *DNA_reconstruct_info_create(const struct SDNA *oldsdna,
const struct SDNA *newsdna,
const char *compare_flags);
void DNA_reconstruct_info_free(struct DNA_ReconstructInfo *reconstruct_info);
+/**
+ * Returns the index of the struct info for the struct with the specified name.
+ */
int DNA_struct_find_nr_ex(const struct SDNA *sdna, const char *str, unsigned int *index_last);
int DNA_struct_find_nr(const struct SDNA *sdna, const char *str);
+/**
+ * Does endian swapping on the fields of a struct value.
+ *
+ * \param sdna: SDNA of the struct_nr belongs to
+ * \param struct_nr: Index of struct info within sdna
+ * \param data: Struct data that is to be converted
+ */
void DNA_struct_switch_endian(const struct SDNA *sdna, int struct_nr, char *data);
+/**
+ * Constructs and returns an array of byte flags with one element for each struct in oldsdna,
+ * indicating how it compares to newsdna.
+ */
const char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA *newsdna);
+/**
+ * \param reconstruct_info: Information preprocessed by #DNA_reconstruct_info_create.
+ * \param old_struct_nr: Index of struct info within oldsdna.
+ * \param blocks: The number of array elements.
+ * \param old_blocks: Array of struct data.
+ * \return An allocated reconstructed struct.
+ */
void *DNA_struct_reconstruct(const struct DNA_ReconstructInfo *reconstruct_info,
int old_struct_nr,
int blocks,
const void *old_blocks);
+/**
+ * Returns the offset of the field with the specified name and type within the specified
+ * struct type in #SDNA, -1 on failure.
+ */
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
+/**
+ * Returns the size of struct fields of the specified type and name.
+ *
+ * \param type: Index into sdna->types/types_size
+ * \param name: Index into sdna->names,
+ * needed to extract possible pointer/array information.
+ */
int DNA_elem_size_nr(const struct SDNA *sdna, short type, short name);
bool DNA_struct_find(const struct SDNA *sdna, const char *stype);
@@ -121,11 +160,22 @@ bool DNA_struct_elem_find(const struct SDNA *sdna,
const char *vartype,
const char *name);
+/**
+ * Returns the size in bytes of a primitive type.
+ */
int DNA_elem_type_size(const eSDNA_Type elem_nr);
+/**
+ * Rename a struct
+ */
bool DNA_sdna_patch_struct(struct SDNA *sdna,
const char *struct_name_old,
const char *struct_name_new);
+/**
+ * Replace \a elem_old with \a elem_new for struct \a struct_name
+ * handles search & replace, maintaining surrounding non-identifier characters
+ * such as pointer & array size.
+ */
bool DNA_sdna_patch_struct_member(struct SDNA *sdna,
const char *struct_name,
const char *elem_old,
@@ -134,14 +184,28 @@ bool DNA_sdna_patch_struct_member(struct SDNA *sdna,
void DNA_sdna_alias_data_ensure(struct SDNA *sdna);
/* Alias lookups (using runtime struct member names). */
+
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
int DNA_struct_alias_find_nr_ex(const struct SDNA *sdna,
const char *str,
unsigned int *index_last);
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
int DNA_struct_alias_find_nr(const struct SDNA *sdna, const char *str);
+/**
+ * \note requires #DNA_sdna_alias_data_ensure_structs_map to be called.
+ */
bool DNA_struct_alias_elem_find(const struct SDNA *sdna,
const char *stype,
const char *vartype,
const char *name);
+/**
+ * Separated from #DNA_sdna_alias_data_ensure because it's not needed
+ * unless we want to lookup aliased struct names (#DNA_struct_alias_find_nr and friends).
+ */
void DNA_sdna_alias_data_ensure_structs_map(struct SDNA *sdna);
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 1ad884bee8f..88eb164c2b4 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -333,6 +333,11 @@
.point_density = 30.0f,\
.segment_influence = 0.0f,\
.max_angle = DEG2RAD(170.0f),\
+ .rand_start_fac = 0.0f,\
+ .rand_end_fac = 0.0f,\
+ .rand_offset = 0.0f,\
+ .seed = 0,\
+ .step = 4,\
}
#define _DNA_DEFAULT_DashGpencilModifierData \
@@ -353,5 +358,26 @@
.mat_nr = -1, \
}
+#define _DNA_DEFAULT_ShrinkwrapGpencilModifierData \
+ { \
+ .target = NULL, \
+ .aux_target = NULL, \
+ .keep_dist = 0.05f, \
+ .shrink_type = MOD_SHRINKWRAP_NEAREST_SURFACE, \
+ .shrink_opts = MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR, \
+ .shrink_mode = 0, \
+ .proj_limit = 0.0f, \
+ .proj_axis = 0, \
+ .subsurf_levels = 0, \
+ .material = NULL, \
+ .layername = "", \
+ .vgname = "", \
+ .pass_index = 0, \
+ .flag = 0, \
+ .layer_pass = 0, \
+ .smooth_factor = 0.05f, \
+ .smooth_step = 1, \
+ }
+
/* clang-format off */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 339714da255..0f69a256f56 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -28,6 +28,7 @@ extern "C" {
#endif
struct LatticeDeformData;
+struct ShrinkwrapTreeData;
/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
* (ONLY ADD NEW ITEMS AT THE END)
@@ -58,6 +59,7 @@ typedef enum GpencilModifierType {
eGpencilModifierType_WeightProximity = 21,
eGpencilModifierType_Dash = 22,
eGpencilModifierType_WeightAngle = 23,
+ eGpencilModifierType_Shrinkwrap = 24,
/* Keep last. */
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@@ -490,10 +492,17 @@ typedef struct LengthGpencilModifierData {
int layer_pass;
/** Length. */
float start_fac, end_fac;
+ /** Random length factors. */
+ float rand_start_fac, rand_end_fac, rand_offset;
/** Overshoot trajectory factor. */
float overshoot_fac;
+ /** (first element is the index) random values. */
+ int seed;
+ /** How many frames before recalculate randoms. */
+ int step;
/** Modifier mode. */
int mode;
+ char _pad[4];
/* Curvature parameters. */
float point_density;
float segment_influence;
@@ -507,6 +516,7 @@ typedef enum eLengthGpencil_Flag {
GP_LENGTH_INVERT_MATERIAL = (1 << 3),
GP_LENGTH_USE_CURVATURE = (1 << 4),
GP_LENGTH_INVERT_CURVATURE = (1 << 5),
+ GP_LENGTH_USE_RANDOM = (1 << 6),
} eLengthGpencil_Flag;
typedef enum eLengthGpencil_Type {
@@ -728,7 +738,7 @@ typedef struct SmoothGpencilModifierData {
int pass_index;
/** Several flags. */
int flag;
- /** Factor of noise. */
+ /** Factor of smooth. */
float factor;
/** How many times apply smooth. */
int step;
@@ -1073,6 +1083,60 @@ typedef struct LineartGpencilModifierData {
} LineartGpencilModifierData;
+typedef struct ShrinkwrapGpencilModifierData {
+ GpencilModifierData modifier;
+ /** Shrink target. */
+ struct Object *target;
+ /** Additional shrink target. */
+ struct Object *aux_target;
+ /** Material for filtering. */
+ struct Material *material;
+ /** Layer name. */
+ char layername[64];
+ /** Optional vertexgroup filter name, MAX_VGROUP_NAME. */
+ char vgname[64];
+ /** Custom index for passes. */
+ int pass_index;
+ /** Flags. */
+ int flag;
+ /** Custom index for passes. */
+ int layer_pass;
+ /** Distance offset to keep from mesh/projection point. */
+ float keep_dist;
+ /** Shrink type projection. */
+ short shrink_type;
+ /** Shrink options. */
+ char shrink_opts;
+ /** Shrink to surface mode. */
+ char shrink_mode;
+ /** Limit the projection ray cast. */
+ float proj_limit;
+ /** Axis to project over. */
+ char proj_axis;
+
+ /** If using projection over vertex normal this controls the level of subsurface that must be
+ * done before getting the vertex coordinates and normal
+ */
+ char subsurf_levels;
+ char _pad[6];
+ /** Factor of smooth. */
+ float smooth_factor;
+ /** How many times apply smooth. */
+ int smooth_step;
+
+ /** Runtime only. */
+ struct ShrinkwrapTreeData *cache_data;
+} ShrinkwrapGpencilModifierData;
+
+typedef enum eShrinkwrapGpencil_Flag {
+ GP_SHRINKWRAP_INVERT_LAYER = (1 << 0),
+ GP_SHRINKWRAP_INVERT_PASS = (1 << 1),
+ GP_SHRINKWRAP_INVERT_LAYERPASS = (1 << 3),
+ GP_SHRINKWRAP_INVERT_MATERIAL = (1 << 4),
+ /* Keep next bit as is to be equals to mesh modifier flag to reuse functions. */
+ GP_SHRINKWRAP_INVERT_VGROUP = (1 << 6),
+} eShrinkwrapGpencil_Flag;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 3943c063c39..77cb553c7c7 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -74,7 +74,7 @@ struct MLoopTri_Store {
int len_alloc;
};
-/* not saved in file! */
+/* Runtime data, not saved in files. */
typedef struct Mesh_Runtime {
/* Evaluated mesh for objects which do not have effective modifiers.
* This mesh is used as a result of modifier stack evaluation.
@@ -82,27 +82,33 @@ typedef struct Mesh_Runtime {
struct Mesh *mesh_eval;
void *eval_mutex;
- struct EditMeshData *edit_data;
- void *batch_cache;
+ /** Needed to ensure some thread-safety during render data pre-processing. */
+ void *render_mutex;
- struct SubdivCCG *subdiv_ccg;
- void *_pad1;
- int subdiv_ccg_tot_level;
- char _pad2[4];
+ /** Lazily initialized SoA data from the #edit_mesh field in #Mesh. */
+ struct EditMeshData *edit_data;
- int64_t cd_dirty_vert;
- int64_t cd_dirty_edge;
- int64_t cd_dirty_loop;
- int64_t cd_dirty_poly;
+ /**
+ * Data used to efficiently draw the mesh in the viewport, especially useful when
+ * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.c`.
+ */
+ void *batch_cache;
+ /** Cache for derived triangulation of the mesh. */
struct MLoopTri_Store looptris;
- /** `BVHCache` defined in 'BKE_bvhutil.c' */
+ /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */
struct BVHCache *bvh_cache;
- /** Non-manifold boundary data for Shrinkwrap Target Project. */
+ /** Cache of non-manifold boundary data for Shrinkwrap Target Project. */
struct ShrinkwrapBoundaryData *shrinkwrap_data;
+ /** Needed in case we need to lazily initialize the mesh. */
+ CustomData_MeshMasks cd_mask_extra;
+
+ struct SubdivCCG *subdiv_ccg;
+ int subdiv_ccg_tot_level;
+
/** Set by modifier stack if only deformed from original. */
char deformed_only;
/**
@@ -122,14 +128,15 @@ typedef struct Mesh_Runtime {
*/
char wrapper_type_finalize;
- char _pad[4];
-
- /** Needed in case we need to lazily initialize the mesh. */
- CustomData_MeshMasks cd_mask_extra;
+ /**
+ * Used to mark when derived data needs to be recalculated for a certain layer.
+ * Currently only normals.
+ */
- /** Needed to ensure some thread-safety during render data pre-processing. */
- void *render_mutex;
- void *_pad3;
+ int64_t cd_dirty_vert;
+ int64_t cd_dirty_edge;
+ int64_t cd_dirty_loop;
+ int64_t cd_dirty_poly;
} Mesh_Runtime;
@@ -141,101 +148,191 @@ typedef struct Mesh {
/** Old animation system, deprecated for 2.5. */
struct Ipo *ipo DNA_DEPRECATED;
struct Key *key;
- struct Material **mat;
- struct MSelect *mselect;
- /* BMESH ONLY */
- /* New face structures. */
- struct MPoly *mpoly;
- struct MLoop *mloop;
- struct MLoopUV *mloopuv;
- struct MLoopCol *mloopcol;
- /* END BMESH ONLY */
+ /**
+ * An array of materials, with length #totcol. These can be overridden by material slots
+ * on #Object. Indices in #MPoly.mat_nr control which material is used for every face.
+ */
+ struct Material **mat;
/**
- * Legacy face storage (quads & tries only),
- * faces are now stored in #Mesh.mpoly & #Mesh.mloop arrays.
- *
- * \note This would be marked deprecated however the particles still use this at run-time
- * for placing particles on the mesh (something which should be eventually upgraded).
+ * Array of vertices. Edges and faces are defined by indices into this array.
+ * \note This pointer is for convenient access to the #CD_MVERT layer in #vdata.
*/
- struct MFace *mface;
- /** Store tessellation face UV's and texture here. */
- struct MTFace *mtface;
- /** Deprecated, use mtface. */
- struct TFace *tface DNA_DEPRECATED;
- /** Array of verts. */
struct MVert *mvert;
- /** Array of edges. */
+ /**
+ * Array of edges, containing vertex indices. For simple triangle or quad meshes, edges could be
+ * calculated from the #MPoly and #MLoop arrays, however, edges need to be stored explicitly to
+ * edge domain attributes and to support loose edges that aren't connected to faces.
+ * \note This pointer is for convenient access to the #CD_MEDGE layer in #edata.
+ */
struct MEdge *medge;
- /** Deform-group vertices. */
- struct MDeformVert *dvert;
- /** List of bDeformGroup names and flag only. */
- ListBase vertex_group_names;
+ /**
+ * Face topology storage of the size and offset of each face's section of the #mloop face corner
+ * array. Also stores various flags and the `material_index` attribute.
+ * \note This pointer is for convenient access to the #CD_MPOLY layer in #pdata.
+ */
+ struct MPoly *mpoly;
+ /**
+ * The vertex and edge index at each face corner.
+ * \note This pointer is for convenient access to the #CD_MLOOP layer in #ldata.
+ */
+ struct MLoop *mloop;
- /* array of colors for the tessellated faces, must be number of tessellated
- * faces * 4 in length */
- struct MCol *mcol;
- struct Mesh *texcomesh;
+ /** The number of vertices (#MVert) in the mesh, and the size of #vdata. */
+ int totvert;
+ /** The number of edges (#MEdge) in the mesh, and the size of #edata. */
+ int totedge;
+ /** The number of polygons/faces (#MPoly) in the mesh, and the size of #pdata. */
+ int totpoly;
+ /** The number of face corners (#MLoop) in the mesh, and the size of #ldata. */
+ int totloop;
- /* When the object is available, the preferred access method is: BKE_editmesh_from_object(ob) */
- /** Not saved in file. */
- struct BMEditMesh *edit_mesh;
+ CustomData vdata, edata, pdata, ldata;
+
+ /** "Vertex group" vertices. */
+ struct MDeformVert *dvert;
+ /**
+ * List of vertex group (#bDeformGroup) names and flags only. Actual weights are stored in dvert.
+ * \note This pointer is for convenient access to the #CD_MDEFORMVERT layer in #vdata.
+ */
+ ListBase vertex_group_names;
+ /** The active index in the #vertex_group_names list. */
+ int vertex_group_active_index;
- struct CustomData vdata, edata, fdata;
+ /**
+ * The index of the active attribute in the UI. The attribute list is a combination of the
+ * generic type attributes from vertex, edge, face, and corner custom data.
+ */
+ int attributes_active_index;
- /* BMESH ONLY */
- struct CustomData pdata, ldata;
- /* END BMESH ONLY */
+ /**
+ * 2D vector data used for UVs. "UV" data can also be stored as generic attributes in #ldata.
+ * \note This pointer is for convenient access to the #CD_MLOOPUV layer in #ldata.
+ */
+ struct MLoopUV *mloopuv;
+ /**
+ * The active vertex corner color layer, if it exists. Also called "Vertex Color" in Blender's
+ * UI, even though it is stored per face corner.
+ * \note This pointer is for convenient access to the #CD_MLOOPCOL layer in #ldata.
+ */
+ struct MLoopCol *mloopcol;
- int totvert, totedge, totface, totselect;
+ /**
+ * Runtime storage of the edit mode mesh. If it exists, it generally has the most up-to-date
+ * information about the mesh.
+ * \note When the object is available, the preferred access method is #BKE_editmesh_from_object.
+ */
+ struct BMEditMesh *edit_mesh;
- /* BMESH ONLY */
- int totpoly, totloop;
- /* END BMESH ONLY */
+ /**
+ * This array represents the selection order when the user manually picks elements in edit-mode,
+ * some tools take advantage of this information. All elements in this array are expected to be
+ * selected, see #BKE_mesh_mselect_validate which ensures this. For procedurally created meshes,
+ * this is generally empty (selections are stored as boolean attributes in the corresponding
+ * custom data).
+ */
+ struct MSelect *mselect;
- int attributes_active_index;
- int vertex_group_active_index;
+ /** The length of the #mselect array. */
+ int totselect;
- /* the last selected vertex/edge/face are used for the active face however
- * this means the active face must always be selected, this is to keep track
- * of the last selected face and is similar to the old active face flag where
- * the face does not need to be selected, -1 is inactive */
+ /**
+ * In most cases the last selected element (see #mselect) represents the active element.
+ * For faces we make an exception and store the active face separately so it can be active
+ * even when no faces are selected. This is done to prevent flickering in the material properties
+ * and UV Editor which base the content they display on the current material which is controlled
+ * by the active face.
+ *
+ * \note This is mainly stored for use in edit-mode.
+ */
int act_face;
- /* texture space, copied as one block in editobject.c */
+ /**
+ * An optional mesh owned elsewhere (by #Main) that can be used to override
+ * the texture space #loc and #size.
+ * \note Vertex indices should be aligned for this to work usefully.
+ */
+ struct Mesh *texcomesh;
+
+ /** Texture space location and size, used for procedural coordinates when rendering. */
float loc[3];
float size[3];
+ char texflag;
- short texflag, flag;
+ /** Various flags used when editing the mesh. */
+ char editflag;
+ /** Mostly more flags used when editing or displaying the mesh. */
+ short flag;
+
+ /**
+ * The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
+ */
float smoothresh;
- /* customdata flag, for bevel-weight and crease, which are now optional */
- char cd_flag, _pad;
+ /**
+ * Flag for choosing whether or not so store bevel weight and crease as custom data layers in the
+ * edit mesh (they are always stored in #MVert and #MEdge currently). In the future, this data
+ * may be stored as generic named attributes (see T89054 and T93602).
+ */
+ char cd_flag;
- char subdiv DNA_DEPRECATED, subdivr DNA_DEPRECATED;
- /** Only kept for backwards compat, not used anymore. */
- char subsurftype DNA_DEPRECATED;
- char editflag;
+ /**
+ * User-defined symmetry flag (#eMeshSymmetryType) that causes editing operations to maintain
+ * symmetrical geometry. Supported by operations such as transform and weight-painting.
+ */
+ char symmetry;
+ /** The length of the #mat array. */
short totcol;
- float remesh_voxel_size;
- float remesh_voxel_adaptivity;
+ /** Choice between different remesh methods in the UI. */
char remesh_mode;
- /* Indicates the symmetry that a mesh has, according to the artist, so that tools can
- * consistently ensure that this symmetry is maintained. */
- char symmetry;
+ char subdiv DNA_DEPRECATED;
+ char subdivr DNA_DEPRECATED;
+ char subsurftype DNA_DEPRECATED;
- char _pad1[2];
+ /**
+ * Deprecated. Store of runtime data for tessellation face UVs and texture.
+ *
+ * \note This would be marked deprecated, however the particles still use this at run-time
+ * for placing particles on the mesh (something which should be eventually upgraded).
+ */
+ struct MTFace *mtface;
+ /** Deprecated, use mtface. */
+ struct TFace *tface DNA_DEPRECATED;
+
+ /* Deprecated. Array of colors for the tessellated faces, must be number of tessellated
+ * faces * 4 in length. This is stored in #fdata, and deprecated. */
+ struct MCol *mcol;
+
+ /**
+ * Deprecated face storage (quads & triangles only);
+ * faces are now pointed to by #Mesh.mpoly and #Mesh.mloop.
+ *
+ * \note This would be marked deprecated, however the particles still use this at run-time
+ * for placing particles on the mesh (something which should be eventually upgraded).
+ */
+ struct MFace *mface;
+ /* Deprecated storage of old faces (only triangles or quads). */
+ CustomData fdata;
+ /* Deprecated size of #fdata. */
+ int totface;
+
+ /** Per-mesh settings for voxel remesh. */
+ float remesh_voxel_size;
+ float remesh_voxel_adaptivity;
int face_sets_color_seed;
/* Stores the initial Face Set to be rendered white. This way the overlay can be enabled by
* default and Face Sets can be used without affecting the color of the mesh. */
int face_sets_color_default;
+ char _pad1[4];
+
void *_pad2;
+
Mesh_Runtime runtime;
} Mesh;
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 4bc1de3b78e..03991dff0ce 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -106,19 +106,15 @@ enum {
};
/**
- * Mesh Loops.
- * Each loop represents the corner of a polygon (#MPoly).
+ * Mesh Face Corners.
+ * "Loop" is an internal name for the corner of a polygon (#MPoly).
*
* Typically accessed from #Mesh.mloop.
*/
typedef struct MLoop {
- /** Vertex index. */
+ /** Vertex index into an #MVert array. */
unsigned int v;
- /**
- * Edge index.
- *
- * \note The e here is because we want to move away from relying on edge hashes.
- */
+ /** Edge index into an #MEdge array. */
unsigned int e;
} MLoop;
@@ -291,8 +287,22 @@ typedef struct MDeformWeight {
float weight;
} MDeformWeight;
+/**
+ * Stores all of an element's vertex groups, and their weight values.
+ */
typedef struct MDeformVert {
+ /**
+ * Array of weight indices and values.
+ * - There must not be any duplicate #def_nr indices.
+ * - Groups in the array are unordered.
+ * - Indices outside the usable range of groups are ignored.
+ */
struct MDeformWeight *dw;
+ /**
+ * The length of the #dw array.
+ * \note This is not necessarily the same length as the total number of vertex groups.
+ * However, generally it isn't larger.
+ */
int totweight;
/** Flag is only in use as a run-time tag at the moment. */
int flag;
diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h
index d257363b6ef..e489ba7d7ac 100644
--- a/source/blender/makesdna/DNA_meta_types.h
+++ b/source/blender/makesdna/DNA_meta_types.h
@@ -83,8 +83,8 @@ typedef struct MetaBall {
char flag, flag2;
short totcol;
/** Used to store MB_AUTOSPACE. */
- short texflag;
- char _pad[1];
+ char texflag;
+ char _pad[2];
/**
* ID data is older than edit-mode data (TODO: move to edit-mode struct).
diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index 5b2694f420b..78ab41031a6 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -429,6 +429,7 @@
.uv_offset = {0.0f, 0.0f}, \
.uv_offset_copy = {0.0f, 0.0f}, \
.mirror_ob = NULL, \
+ .use_correct_order_on_merge = true, \
}
#define _DNA_DEFAULT_MultiresModifierData \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 631db64ddd3..f7a468264c3 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -374,7 +374,15 @@ typedef struct MirrorModifierData {
short flag;
float tolerance;
float bisect_threshold;
- char _pad[4];
+
+ /** Mirror modifier used to merge the old vertex into its new copy, which would break code
+ * relying on access to the original geometry vertices. However, modifying this behavior to the
+ * correct one (i.e. merging the copy vertices into their original sources) has several potential
+ * effects on other modifiers and tools, so we need to keep that incorrect behavior for existing
+ * modifiers, and only use the new correct one for new modifiers. */
+ uint8_t use_correct_order_on_merge;
+
+ char _pad[3];
float uv_offset[2];
float uv_offset_copy[2];
struct Object *mirror_ob;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 59cf4da26f6..dc5acb9d5b2 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -304,8 +304,6 @@ typedef struct bNode {
/** Entire boundbox (world-space). */
rctf totr;
- /** Optional buttons area. */
- rctf butr;
/** Optional preview area. */
rctf prvr;
/**
@@ -325,8 +323,6 @@ typedef struct bNode {
char branch_tag;
/** Used at runtime when iterating over node branches. */
char iter_flag;
- /** Runtime during drawing. */
- struct uiBlock *block;
/**
* XXX: eevee only, id of screen space reflection layer,
@@ -375,8 +371,7 @@ typedef struct bNode {
/* node is disabled */
#define NODE_MUTED 512
// #define NODE_CUSTOM_NAME 1024 /* deprecated! */
-/* group node types: use const outputs by default */
-#define NODE_CONST_OUTPUT (1 << 11)
+// #define NODE_CONST_OUTPUT (1 << 11) /* deprecated */
/* node is always behind others */
#define NODE_BACKGROUND (1 << 12)
/* automatic flag for nodes included in transforms */
@@ -1209,6 +1204,16 @@ typedef struct NodeDenoise {
char prefilter;
} NodeDenoise;
+typedef struct NodeMapRange {
+ /* CustomDataType */
+ uint8_t data_type;
+
+ /* NodeMapRangeType. */
+ uint8_t interpolation_type;
+ uint8_t clamp;
+ char _pad[5];
+} NodeMapRange;
+
typedef struct NodeAttributeClamp {
/* CustomDataType. */
uint8_t data_type;
@@ -1606,6 +1611,16 @@ typedef struct NodeGeometryViewer {
int8_t data_type;
} NodeGeometryViewer;
+typedef struct NodeFunctionCompare {
+ /* NodeCompareOperation */
+ int8_t operation;
+ /* eNodeSocketDatatype */
+ int8_t data_type;
+ /* NodeCompareMode */
+ int8_t mode;
+ char _pad[1];
+} NodeFunctionCompare;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1886,14 +1901,25 @@ enum {
};
/* Float compare node operations. */
-typedef enum FloatCompareOperation {
- NODE_FLOAT_COMPARE_LESS_THAN = 0,
- NODE_FLOAT_COMPARE_LESS_EQUAL = 1,
- NODE_FLOAT_COMPARE_GREATER_THAN = 2,
- NODE_FLOAT_COMPARE_GREATER_EQUAL = 3,
- NODE_FLOAT_COMPARE_EQUAL = 4,
- NODE_FLOAT_COMPARE_NOT_EQUAL = 5,
-} FloatCompareOperation;
+typedef enum NodeCompareMode {
+ NODE_COMPARE_MODE_ELEMENT = 0,
+ NODE_COMPARE_MODE_LENGTH = 1,
+ NODE_COMPARE_MODE_AVERAGE = 2,
+ NODE_COMPARE_MODE_DOT_PRODUCT = 3,
+ NODE_COMPARE_MODE_DIRECTION = 4
+} NodeCompareMode;
+
+typedef enum NodeCompareOperation {
+ NODE_COMPARE_LESS_THAN = 0,
+ NODE_COMPARE_LESS_EQUAL = 1,
+ NODE_COMPARE_GREATER_THAN = 2,
+ NODE_COMPARE_GREATER_EQUAL = 3,
+ NODE_COMPARE_EQUAL = 4,
+ NODE_COMPARE_NOT_EQUAL = 5,
+ NODE_COMPARE_COLOR_BRIGHTER = 6,
+ NODE_COMPARE_COLOR_DARKER = 7,
+
+} NodeCompareOperation;
/* Float to Int node operations. */
typedef enum FloatToIntRoundingMode {
@@ -2272,6 +2298,10 @@ typedef enum GeometryNodeDeleteGeometryMode {
GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE = 2,
} GeometryNodeDeleteGeometryMode;
+typedef enum GeometryNodeRealizeInstancesFlag {
+ GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR = (1 << 0),
+} GeometryNodeRealizeInstancesFlag;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index ebf3d4a248c..a50d0524998 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -41,13 +41,13 @@ typedef struct TreeStoreElem {
/** Used only to store data in blend files. */
typedef struct TreeStore {
- /** Was previously used for memory preallocation. */
+ /** Was previously used for memory pre-allocation. */
int totelem DNA_DEPRECATED;
/** Number of elements in data array. */
int usedelem;
/**
- * Elements to be packed from mempool in writefile.c
- * or extracted to mempool in readfile.c
+ * Elements to be packed from mempool in `writefile.c`
+ * or extracted to mempool in `readfile.c`.
*/
TreeStoreElem *data;
} TreeStore;
diff --git a/source/blender/makesdna/DNA_pointcache_types.h b/source/blender/makesdna/DNA_pointcache_types.h
index 7de0bb29c46..2b6e1c4f7de 100644
--- a/source/blender/makesdna/DNA_pointcache_types.h
+++ b/source/blender/makesdna/DNA_pointcache_types.h
@@ -131,8 +131,8 @@ typedef struct PointCache {
void (*free_edit)(struct PTCacheEdit *edit);
} PointCache;
+/** #PointCache.flag */
enum {
- /* pointcache->flag */
PTCACHE_BAKED = 1 << 0,
PTCACHE_OUTDATED = 1 << 1,
PTCACHE_SIMULATION_VALID = 1 << 2,
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index 9ecf94ebd6e..d2c4f22bc23 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -375,3 +375,5 @@
}
/* clang-format off */
+
+/** \} */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 634e97f782f..c66ac3a6211 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -720,6 +720,7 @@ typedef struct RenderData {
/* path to render output */
/** 1024 = FILE_MAX. */
+ /* NOTE: Excluded from `BKE_bpath_foreach_path_` / `scene_foreach_path` code. */
char pic[1024];
/* stamps flags. */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 03110f6e1be..a4c254d6e5a 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -154,6 +154,9 @@ typedef struct Panel_Runtime {
/* Pointer to the panel's block. Useful when changes to panel #uiBlocks
* need some context from traversal of the panel "tree". */
struct uiBlock *block;
+
+ /* Non-owning pointer. The context is stored in the block. */
+ struct bContextStore *context;
} Panel_Runtime;
/** The part from uiBlock that needs saved in file. */
@@ -458,6 +461,9 @@ typedef struct ARegion_Runtime {
/* The offset needed to not overlap with window scrollbars. Only used by HUD regions for now. */
int offset_x, offset_y;
+
+ /* Maps uiBlock->name to uiBlock for faster lookups. */
+ struct GHash *block_name_map;
} ARegion_Runtime;
typedef struct ARegion {
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 9e6cf907444..e1bba60396a 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -180,8 +180,7 @@ typedef struct Sequence {
int startdisp, enddisp;
float sat;
float mul;
- char tmp_tag;
- char _pad[3];
+ float _pad;
short anim_preseek; /* UNUSED. */
/** Streamindex for movie or sound files with several streams. */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 7fb15fc8508..a7a19be5b3e 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -281,7 +281,7 @@ typedef struct SpaceOutliner {
* Note that treestore may contain duplicate elements if element
* is used multiple times in outliner tree (e. g. linked objects)
* Also note that BLI_mempool can not be read/written in DNA directly,
- * therefore readfile.c/writefile.c linearize treestore into TreeStore structure
+ * therefore `readfile.c/writefile.c` linearize treestore into TreeStore structure
*/
struct BLI_mempool *treestore;
@@ -1514,12 +1514,15 @@ typedef struct bNodeTreePath {
} bNodeTreePath;
typedef struct SpaceNodeOverlay {
+ /* eSpaceNodeOverlay_Flag */
int flag;
} SpaceNodeOverlay;
typedef enum eSpaceNodeOverlay_Flag {
SN_OVERLAY_SHOW_OVERLAYS = (1 << 1),
SN_OVERLAY_SHOW_WIRE_COLORS = (1 << 2),
+ SN_OVERLAY_SHOW_TIMINGS = (1 << 3),
+ SN_OVERLAY_SHOW_PATH = (1 << 4),
} eSpaceNodeOverlay_Flag;
typedef struct SpaceNode {
@@ -2003,6 +2006,7 @@ typedef enum eSpaceSpreadsheet_ContextType {
} eSpaceSpreadsheet_ContextType;
typedef enum eSpreadsheetColumnValueType {
+ SPREADSHEET_VALUE_TYPE_UNKNOWN = -1,
SPREADSHEET_VALUE_TYPE_BOOL = 0,
SPREADSHEET_VALUE_TYPE_INT32 = 1,
SPREADSHEET_VALUE_TYPE_FLOAT = 2,
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index 2dbbb35c3ca..1d4257328a4 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -324,6 +324,7 @@ SDNA_DEFAULT_DECL_STRUCT(LineartGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(LengthGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierSegment);
+SDNA_DEFAULT_DECL_STRUCT(ShrinkwrapGpencilModifierData);
#undef SDNA_DEFAULT_DECL_STRUCT
@@ -555,13 +556,16 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(LengthGpencilModifierData),
SDNA_DEFAULT_DECL(DashGpencilModifierData),
SDNA_DEFAULT_DECL(DashGpencilModifierSegment),
+ SDNA_DEFAULT_DECL(ShrinkwrapGpencilModifierData),
};
#undef SDNA_DEFAULT_DECL
#undef SDNA_DEFAULT_DECL_EX
-char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str)
+uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
+ size_t size,
+ const char *alloc_str)
{
- char *data_dst = MEM_mallocN(size, alloc_str);
+ uint8_t *data_dst = MEM_mallocN(size, alloc_str);
memcpy(data_dst, data_src, size);
return data_dst;
}
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 8aa2a07d071..bdf29b22787 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -177,13 +177,6 @@ static bool ispointer(const char *name)
return (name[0] == '*' || (name[0] == '(' && name[1] == '*'));
}
-/**
- * Returns the size of struct fields of the specified type and name.
- *
- * \param type: Index into sdna->types/types_size
- * \param name: Index into sdna->names,
- * needed to extract possible pointer/array information.
- */
int DNA_elem_size_nr(const SDNA *sdna, short type, short name)
{
const char *cp = sdna->names[name];
@@ -265,9 +258,6 @@ static int dna_struct_find_nr_ex_impl(
return -1;
}
-/**
- * Returns the index of the struct info for the struct with the specified name.
- */
int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
return dna_struct_find_nr_ex_impl(
@@ -284,7 +274,6 @@ int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index
index_last);
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
int DNA_struct_alias_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
#ifdef WITH_DNA_GHASH
@@ -310,7 +299,6 @@ int DNA_struct_find_nr(const SDNA *sdna, const char *str)
return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy);
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
int DNA_struct_alias_find_nr(const SDNA *sdna, const char *str)
{
unsigned int index_last_dummy = UINT_MAX;
@@ -544,9 +532,6 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error
return true;
}
-/**
- * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
- */
SDNA *DNA_sdna_from_data(const void *data,
const int data_len,
bool do_endian_swap,
@@ -691,10 +676,6 @@ static void set_compare_flags_for_struct(const SDNA *oldsdna,
compare_flags[old_struct_index] = SDNA_CMP_EQUAL;
}
-/**
- * Constructs and returns an array of byte flags with one element for each struct in oldsdna,
- * indicating how it compares to newsdna.
- */
const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna)
{
if (oldsdna->structs_len == 0) {
@@ -1018,13 +999,6 @@ static int get_member_size_in_bytes(const SDNA *sdna, const SDNA_StructMember *m
return type_size * array_length;
}
-/**
- * Does endian swapping on the fields of a struct value.
- *
- * \param sdna: SDNA of the struct_nr belongs to
- * \param struct_nr: Index of struct info within sdna
- * \param data: Struct data that is to be converted
- */
void DNA_struct_switch_endian(const SDNA *sdna, int struct_nr, char *data)
{
if (struct_nr == -1) {
@@ -1230,13 +1204,6 @@ static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info,
}
}
-/**
- * \param reconstruct_info: Information preprocessed by #DNA_reconstruct_info_create.
- * \param old_struct_nr: Index of struct info within oldsdna.
- * \param blocks: The number of array elements.
- * \param old_blocks: Array of struct data.
- * \return An allocated reconstructed struct.
- */
void *DNA_struct_reconstruct(const DNA_ReconstructInfo *reconstruct_info,
int old_struct_nr,
int blocks,
@@ -1534,10 +1501,6 @@ static int compress_reconstruct_steps(ReconstructStep *steps, const int old_step
return new_step_count;
}
-/**
- * Pre-process information about how structs in \a newsdna can be reconstructed from structs in
- * \a oldsdna. This information is then used to speedup #DNA_struct_reconstruct.
- */
DNA_ReconstructInfo *DNA_reconstruct_info_create(const SDNA *oldsdna,
const SDNA *newsdna,
const char *compare_flags)
@@ -1597,10 +1560,6 @@ void DNA_reconstruct_info_free(DNA_ReconstructInfo *reconstruct_info)
MEM_freeN(reconstruct_info);
}
-/**
- * Returns the offset of the field with the specified name and type within the specified
- * struct type in #SDNA, -1 on failure.
- */
int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
@@ -1632,7 +1591,6 @@ bool DNA_struct_elem_find(const SDNA *sdna,
return false;
}
-/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */
bool DNA_struct_alias_elem_find(const SDNA *sdna,
const char *stype,
const char *vartype,
@@ -1651,9 +1609,6 @@ bool DNA_struct_alias_elem_find(const SDNA *sdna,
return false;
}
-/**
- * Returns the size in bytes of a primitive type.
- */
int DNA_elem_type_size(const eSDNA_Type elem_nr)
{
/* should contain all enum types */
@@ -1696,9 +1651,6 @@ static bool DNA_sdna_patch_struct_nr(SDNA *sdna,
sdna->types[struct_info->type] = struct_name_new;
return true;
}
-/**
- * Rename a struct
- */
bool DNA_sdna_patch_struct(SDNA *sdna, const char *struct_name_old, const char *struct_name_new)
{
const int struct_name_old_nr = DNA_struct_find_nr(sdna, struct_name_old);
@@ -1756,11 +1708,6 @@ static bool DNA_sdna_patch_struct_member_nr(SDNA *sdna,
}
return false;
}
-/**
- * Replace \a elem_old with \a elem_new for struct \a struct_name
- * handles search & replace, maintaining surrounding non-identifier characters
- * such as pointer & array size.
- */
bool DNA_sdna_patch_struct_member(SDNA *sdna,
const char *struct_name,
const char *elem_old,
@@ -1909,10 +1856,6 @@ void DNA_sdna_alias_data_ensure(SDNA *sdna)
BLI_ghash_free(elem_map_alias_from_static, MEM_freeN, NULL);
}
-/**
- * Separated from #DNA_sdna_alias_data_ensure because it's not needed
- * unless we want to lookup aliased struct names (#DNA_struct_alias_find_nr and friends).
- */
void DNA_sdna_alias_data_ensure_structs_map(SDNA *sdna)
{
DNA_sdna_alias_data_ensure(sdna);
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 9b8bfb5af15..c5769d7eee4 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -50,7 +50,9 @@
/* No include guard (intentional). */
-/* Match RNA names where possible, keep sorted. */
+/* Match RNA names where possible. */
+
+/* NOTE: Keep sorted! */
DNA_STRUCT_RENAME(Lamp, Light)
DNA_STRUCT_RENAME(SpaceButs, SpaceProperties)
@@ -63,20 +65,24 @@ DNA_STRUCT_RENAME_ELEM(Bone, curveInY, curve_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, curveOutX, curve_out_x)
DNA_STRUCT_RENAME_ELEM(Bone, curveOutY, curve_out_z)
DNA_STRUCT_RENAME_ELEM(Bone, scaleIn, scale_in_x)
-DNA_STRUCT_RENAME_ELEM(Bone, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, scaleOut, scale_out_x)
+DNA_STRUCT_RENAME_ELEM(Bone, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(Bone, scale_out_y, scale_out_z)
DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_f, hardeness)
DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_s, aspect_ratio)
DNA_STRUCT_RENAME_ELEM(Camera, YF_dofdist, dof_distance)
-DNA_STRUCT_RENAME_ELEM(Curve, len_wchar, len_char32)
DNA_STRUCT_RENAME_ELEM(Camera, clipend, clip_end)
DNA_STRUCT_RENAME_ELEM(Camera, clipsta, clip_start)
DNA_STRUCT_RENAME_ELEM(Collection, dupli_ofs, instance_offset)
+DNA_STRUCT_RENAME_ELEM(Curve, ext1, extrude)
+DNA_STRUCT_RENAME_ELEM(Curve, ext2, bevel_radius)
+DNA_STRUCT_RENAME_ELEM(Curve, len_wchar, len_char32)
+DNA_STRUCT_RENAME_ELEM(Curve, width, offset)
DNA_STRUCT_RENAME_ELEM(Editing, over_border, overlay_frame_rect)
DNA_STRUCT_RENAME_ELEM(Editing, over_cfra, overlay_frame_abs)
DNA_STRUCT_RENAME_ELEM(Editing, over_flag, overlay_frame_flag)
DNA_STRUCT_RENAME_ELEM(Editing, over_ofs, overlay_frame_ofs)
+DNA_STRUCT_RENAME_ELEM(FileGlobal, filename, filepath)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, cache_frame_pause_guiding, cache_frame_pause_guide)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_alpha, guide_alpha)
DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_beta, guide_beta)
@@ -86,17 +92,23 @@ DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_vel_factor, guide_vel_factor
DNA_STRUCT_RENAME_ELEM(FluidEffectorSettings, guiding_mode, guide_mode)
DNA_STRUCT_RENAME_ELEM(Image, name, filepath)
DNA_STRUCT_RENAME_ELEM(Library, name, filepath)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches)
+DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits)
DNA_STRUCT_RENAME_ELEM(MaskLayer, restrictflag, visibility_flag)
+DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits)
DNA_STRUCT_RENAME_ELEM(MovieClip, name, filepath)
DNA_STRUCT_RENAME_ELEM(Object, col, color)
DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection)
DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale)
-DNA_STRUCT_RENAME_ELEM(Object, size, scale)
DNA_STRUCT_RENAME_ELEM(Object, restrictflag, visibility_flag)
+DNA_STRUCT_RENAME_ELEM(Object, size, scale)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_group, instance_collection)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_ob, instance_object)
DNA_STRUCT_RENAME_ELEM(ParticleSettings, dupliweights, instance_weights)
+DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame)
DNA_STRUCT_RENAME_ELEM(SpaceSeq, overlay_type, overlay_frame_type)
+DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts)
DNA_STRUCT_RENAME_ELEM(Text, name, filepath)
DNA_STRUCT_RENAME_ELEM(ThemeSpace, scrubbing_background, time_scrub_background)
DNA_STRUCT_RENAME_ELEM(ThemeSpace, show_back_grad, background_type)
@@ -114,8 +126,8 @@ DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveInY, curve_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutX, curve_out_x)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutY, curve_out_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleIn, scale_in_x)
-DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleOut, scale_out_x)
+DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_in_y, scale_in_z)
DNA_STRUCT_RENAME_ELEM(bPoseChannel, scale_out_y, scale_out_z)
DNA_STRUCT_RENAME_ELEM(bSameVolumeConstraint, flag, free_axis)
DNA_STRUCT_RENAME_ELEM(bSound, name, filepath)
@@ -136,12 +148,8 @@ DNA_STRUCT_RENAME_ELEM(bTheme, tstatusbar, space_statusbar)
DNA_STRUCT_RENAME_ELEM(bTheme, ttopbar, space_topbar)
DNA_STRUCT_RENAME_ELEM(bTheme, tuserpref, space_preferences)
DNA_STRUCT_RENAME_ELEM(bTheme, tv3d, space_view3d)
-DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame)
/* Write with a different name, old Blender versions crash loading files with non-NULL
* global_areas. See D9442. */
DNA_STRUCT_RENAME_ELEM(wmWindow, global_area_map, global_areas)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, line_types, edge_types)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_flags, mask_switches)
-DNA_STRUCT_RENAME_ELEM(LineartGpencilModifierData, transparency_mask, material_mask_bits)
-DNA_STRUCT_RENAME_ELEM(SurfaceDeformModifierData, numverts, num_bind_verts)
-DNA_STRUCT_RENAME_ELEM(MaterialLineArt, transparency_mask, material_mask_bits)
+
+/* NOTE: Keep sorted! */
diff --git a/source/blender/makesdna/intern/dna_utils.c b/source/blender/makesdna/intern/dna_utils.c
index f050934b5b3..b2e2e263ea3 100644
--- a/source/blender/makesdna/intern/dna_utils.c
+++ b/source/blender/makesdna/intern/dna_utils.c
@@ -39,10 +39,6 @@
/** \name Struct Member Evaluation
* \{ */
-/**
- * Parses the `[n1][n2]...` on the end of an array name
- * and returns the number of array elements `n1 * n2 ...`.
- */
int DNA_elem_array_size(const char *str)
{
int result = 1;
@@ -106,9 +102,6 @@ uint DNA_elem_id_offset_end(const char *elem_full)
return elem_full_offset;
}
-/**
- * \a elem_dst must be at least the size of \a elem_src.
- */
uint DNA_elem_id_strip_copy(char *elem_dst, const char *elem_src)
{
const uint elem_src_offset = DNA_elem_id_offset_start(elem_src);
@@ -129,10 +122,6 @@ uint DNA_elem_id_strip(char *elem)
return elem_trim_len;
}
-/**
- * Check if 'var' matches '*var[3]' for eg,
- * return true if it does, with start/end offsets.
- */
bool DNA_elem_id_match(const char *elem_search,
const int elem_search_len,
const char *elem_full,
@@ -151,9 +140,6 @@ bool DNA_elem_id_match(const char *elem_search,
return false;
}
-/**
- * Return a renamed dna name, allocated from \a mem_arena.
- */
char *DNA_elem_id_rename(struct MemArena *mem_arena,
const char *elem_src,
const int elem_src_len,
@@ -297,19 +283,15 @@ void DNA_alias_maps(enum eDNA_RenameDir version_dir, GHash **r_struct_map, GHash
/** \name Struct Name Legacy Hack
* \{ */
-/**
- * DNA Compatibility Hack
- * ======================
- *
- * Only keep this for compatibility: **NEVER ADD NEW STRINGS HERE**.
- *
- * The renaming here isn't complete, references to the old struct names
- * are still included in DNA, now fixing these struct names properly
- * breaks forward compatibility. Leave these as-is, but don't add to them!
- * See D4342#98780
- */
const char *DNA_struct_rename_legacy_hack_static_from_alias(const char *name)
{
+ /* Only keep this for compatibility: *NEVER ADD NEW STRINGS HERE*.
+ *
+ * The renaming here isn't complete, references to the old struct names
+ * are still included in DNA, now fixing these struct names properly
+ * breaks forward compatibility. Leave these as-is, but don't add to them!
+ * See D4342#98780. */
+
/* 'bScreen' replaces the old IrisGL 'Screen' struct */
if (STREQ("bScreen", name)) {
return "Screen";
diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h
index f711056c575..b89c45a7a43 100644
--- a/source/blender/makesdna/intern/dna_utils.h
+++ b/source/blender/makesdna/intern/dna_utils.h
@@ -27,16 +27,30 @@ extern "C" {
struct GHash;
struct MemArena;
+/**
+ * Parses the `[n1][n2]...` on the end of an array name
+ * and returns the number of array elements `n1 * n2 ...`.
+ */
int DNA_elem_array_size(const char *str);
uint DNA_elem_id_offset_start(const char *elem_full);
uint DNA_elem_id_offset_end(const char *elem_full);
+/**
+ * \a elem_dst must be at least the size of \a elem_src.
+ */
uint DNA_elem_id_strip_copy(char *elem_dst, const char *elem_src);
uint DNA_elem_id_strip(char *elem);
+/**
+ * Check if 'var' matches '*var[3]' for eg,
+ * return true if it does, with start/end offsets.
+ */
bool DNA_elem_id_match(const char *elem_search,
const int elem_search_len,
const char *elem_full,
uint *r_elem_full_offset);
+/**
+ * Return a renamed dna name, allocated from \a mem_arena.
+ */
char *DNA_elem_id_rename(struct MemArena *mem_arena,
const char *elem_src,
const int elem_src_len,
@@ -56,6 +70,9 @@ void DNA_alias_maps(enum eDNA_RenameDir version_dir,
struct GHash **r_elem_map);
const char *DNA_struct_rename_legacy_hack_alias_from_static(const char *name);
+/**
+ * DNA Compatibility Hack.
+ */
const char *DNA_struct_rename_legacy_hack_static_from_alias(const char *name);
#ifdef __cplusplus
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 188f933dba5..7fa7405add1 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -801,6 +801,11 @@ PropertyRNA *RNA_struct_name_property(const StructRNA *type);
const EnumPropertyItem *RNA_struct_property_tag_defines(const StructRNA *type);
PropertyRNA *RNA_struct_iterator_property(StructRNA *type);
StructRNA *RNA_struct_base(StructRNA *type);
+/**
+ * Use to find the sub-type directly below a base-type.
+ *
+ * So if type were `RNA_SpotLight`, `RNA_struct_base_of(type, &RNA_ID)` would return `&RNA_Light`.
+ */
const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type);
bool RNA_struct_is_ID(const StructRNA *type);
@@ -823,16 +828,32 @@ struct IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create);
bool RNA_struct_idprops_check(StructRNA *srna);
bool RNA_struct_idprops_register_check(const StructRNA *type);
bool RNA_struct_idprops_datablock_allowed(const StructRNA *type);
+/**
+ * Whether given type implies datablock usage by IDProperties.
+ * This is used to prevent classes allowed to have IDProperties,
+ * but not datablock ones, to indirectly use some
+ * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
+ */
bool RNA_struct_idprops_contains_datablock(const StructRNA *type);
+/**
+ * Remove an id-property.
+ */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier);
PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier);
bool RNA_struct_contains_property(PointerRNA *ptr, PropertyRNA *prop_test);
unsigned int RNA_struct_count_properties(StructRNA *srna);
-/* lower level functions for access to type properties */
+/**
+ * Low level direct access to type->properties,
+ * note this ignores parent classes so should be used with care.
+ */
const struct ListBase *RNA_struct_type_properties(StructRNA *srna);
PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *identifier);
+/**
+ * \note #RNA_struct_find_property is a higher level alternative to this function
+ * which takes a #PointerRNA instead of a #StructRNA.
+ */
PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier);
FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier);
@@ -840,6 +861,9 @@ const struct ListBase *RNA_struct_type_functions(StructRNA *srna);
char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len);
+/**
+ * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag.
+ */
bool RNA_struct_available_or_report(struct ReportList *reports, const char *identifier);
bool RNA_struct_bl_idname_ok_or_report(struct ReportList *reports,
const char *identifier,
@@ -861,17 +885,32 @@ PropertyUnit RNA_property_unit(PropertyRNA *prop);
PropertyScaleType RNA_property_ui_scale(PropertyRNA *prop);
int RNA_property_flag(PropertyRNA *prop);
int RNA_property_override_flag(PropertyRNA *prop);
+/**
+ * Get the tags set for \a prop as int bitfield.
+ * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
+ * in debug builds (to avoid performance issues in non-debug builds), which should be
+ * the only way to set tags. Hence, at this point we assume the tag bitfield to be valid.
+ */
int RNA_property_tags(PropertyRNA *prop);
bool RNA_property_builtin(PropertyRNA *prop);
void *RNA_property_py_data_get(PropertyRNA *prop);
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_array_check(PropertyRNA *prop);
+/**
+ * Return the size of Nth dimension.
+ */
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dimension);
+/**
+ * Used by BPY to make an array from the python object.
+ */
int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[]);
char RNA_property_array_item_char(PropertyRNA *prop, int index);
int RNA_property_array_item_index(PropertyRNA *prop, char name);
+/**
+ * \return the maximum length including the \0 terminator. '0' is used when there is no maximum.
+ */
int RNA_property_string_maxlength(PropertyRNA *prop);
const char *RNA_property_ui_name(const PropertyRNA *prop);
@@ -906,6 +945,10 @@ bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r
bool RNA_enum_description(const EnumPropertyItem *item, const int value, const char **description);
int RNA_enum_from_value(const EnumPropertyItem *item, const int value);
int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifier);
+/**
+ * Take care using this with translated enums,
+ * prefer #RNA_enum_from_identifier where possible.
+ */
int RNA_enum_from_name(const EnumPropertyItem *item, const char *name);
unsigned int RNA_enum_items_count(const EnumPropertyItem *item);
@@ -967,27 +1010,54 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value);
bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * Version of #RNA_property_editable that tries to return additional info in \a r_info
+ * that can be exposed in UI.
+ */
bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info);
+/**
+ * Same as RNA_property_editable(), except this checks individual items in an array.
+ */
bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index);
-/* without lib check, only checks the flag */
+/**
+ * Without lib check, only checks the flag.
+ */
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \note Does not take into account editable status, this has to be checked separately
+ * (using #RNA_property_editable_flag() usually).
+ */
bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * Should only be used for custom properties.
+ */
bool RNA_property_overridable_library_set(PointerRNA *ptr,
PropertyRNA *prop,
const bool is_overridable);
bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_comparable(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * This function is to check if its possible to create a valid path from the ID
+ * its slow so don't call in a loop.
+ */
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop); /* slow, use with care */
void RNA_property_update(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \param scene: may be NULL.
+ */
void RNA_property_update_main(struct Main *bmain,
struct Scene *scene,
PointerRNA *ptr,
PropertyRNA *prop);
+/**
+ * \note its possible this returns a false positive in the case of #PROP_CONTEXT_UPDATE
+ * but this isn't likely to be a performance problem.
+ */
bool RNA_property_update_check(struct PropertyRNA *prop);
/* Property Data */
@@ -1031,15 +1101,28 @@ char *RNA_property_string_get_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value);
void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len);
+/**
+ * \return the length without `\0` terminator.
+ */
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_string_get_default(PropertyRNA *prop, char *value, int max_len);
char *RNA_property_string_get_default_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len);
+/**
+ * \return the length without `\0` terminator.
+ */
int RNA_property_string_default_length(PointerRNA *ptr, PropertyRNA *prop);
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * Get the value of the item that is \a step items away from \a from_value.
+ *
+ * \param from_value: Item value to start stepping from.
+ * \param step: Absolute value defines step size, sign defines direction.
+ * E.g to get the next item, pass 1, for the previous -1.
+ */
int RNA_property_enum_step(
const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step);
@@ -1068,6 +1151,9 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr,
PointerRNA *r_ptr);
int RNA_property_collection_lookup_string_index(
PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr, int *r_index);
+/**
+ * Zero return is an assignment error.
+ */
int RNA_property_collection_assign_int(PointerRNA *ptr,
PropertyRNA *prop,
const int key,
@@ -1125,31 +1211,99 @@ char *RNA_path_append(
char *RNA_path_back(const char *path);
#endif
-/* path_resolve() variants only ensure that a valid pointer (and optionally property) exist */
+/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */
+
+/**
+ * Resolve the given RNA Path to find the pointer and/or property
+ * indicated by fully resolving the path.
+ *
+ * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers,
+ * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr,
+ * and a NULL \a r_prop...
+ *
+ * \note Assumes all pointers provided are valid
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop);
+/**
+ * Resolve the given RNA Path to find the pointer and/or property + array index
+ * indicated by fully resolving the path.
+ *
+ * \note Assumes all pointers provided are valid.
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
bool RNA_path_resolve_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+/**
+ * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
+ *
+ * \note While it's correct to ignore the value of #PointerRNA.data
+ * most callers need to know if the resulting pointer was found and not null.
+ */
bool RNA_path_resolve_full_maybe_null(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
-/* path_resolve_property() variants ensure that pointer + property both exist */
+/* RNA_path_resolve_property() variants ensure that pointer + property both exist. */
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop);
+/**
+ * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
-/* path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
+/* RNA_path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
* and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property
+ * indicated by fully resolving the path, and get the value of the Pointer property
+ * (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax,
+ * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_ptr: The final Pointer or Collection item value.
+ * You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
PropertyRNA **r_prop,
PointerRNA *r_item_ptr);
+/**
+ * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path,
+ * and get the value of the Pointer property (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax,
+ * it combines both \a RNA_path_resolve_full and
+ * \a RNA_path_resolve_property_full in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_ptr: The final Pointer or Collection item value.
+ * You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -1164,10 +1318,36 @@ struct PropertyElemRNA {
PropertyRNA *prop;
int index;
};
+/**
+ * Resolve the given RNA Path into a linked list of #PropertyElemRNA's.
+ *
+ * To be used when complex operations over path are needed, like e.g. get relative paths,
+ * to avoid too much string operations.
+ *
+ * \return True if there was no error while resolving the path
+ * \note Assumes all pointers provided are valid
+ */
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
+/**
+ * Find the path from the structure referenced by the pointer to the runtime RNA-defined
+ * #IDProperty object.
+ *
+ * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties).
+ *
+ * \param ptr: Reference to the object owning the custom property storage.
+ * \param needle: Custom property object to find.
+ * \return Relative path or NULL.
+ */
char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle);
+/**
+ * Find the actual ID pointer and path from it to the given ID.
+ *
+ * \param id: ID reference to search the global owner for.
+ * \param[out] r_path: Path from the real ID to the initial ID.
+ * \return The ID pointer, or NULL in case of failure.
+ */
struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path);
char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
@@ -1175,6 +1355,11 @@ char *RNA_path_from_ID_to_struct(const PointerRNA *ptr);
char *RNA_path_from_real_ID_to_struct(struct Main *bmain, PointerRNA *ptr, struct ID **r_real);
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+/**
+ * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
+ * \param index: The *flattened* index to use when \a `index_dim > 0`,
+ * this is expanded when used with multi-dimensional arrays.
+ */
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
@@ -1187,19 +1372,43 @@ char *RNA_path_from_real_ID_to_property_index(struct Main *bmain,
int index,
struct ID **r_real_id);
+/**
+ * \return the path to given ptr/prop from the closest ancestor of given type,
+ * if any (else return NULL).
+ */
char *RNA_path_resolve_from_type_to_property(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const struct StructRNA *type);
+/**
+ * Get the ID as a python representation, eg:
+ * bpy.data.foo["bar"]
+ */
char *RNA_path_full_ID_py(struct Main *bmain, struct ID *id);
+/**
+ * Get the ID.struct as a python representation, eg:
+ * bpy.data.foo["bar"].some_struct
+ */
char *RNA_path_full_struct_py(struct Main *bmain, struct PointerRNA *ptr);
+/**
+ * Get the ID.struct.property as a python representation, eg:
+ * bpy.data.foo["bar"].some_struct.some_prop[10]
+ */
char *RNA_path_full_property_py_ex(
struct Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
char *RNA_path_full_property_py(struct Main *bmain,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Get the struct.property as a python representation, eg:
+ * some_struct.some_prop[10]
+ */
char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+/**
+ * Get the struct.property as a python representation, eg:
+ * some_prop[10]
+ */
char *RNA_path_property_py(const struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
/* Quick name based property access
@@ -1314,24 +1523,38 @@ void RNA_collection_clear(PointerRNA *ptr, const char *name);
} \
((void)0)
-/* check if the idproperty exists, for operators */
+/**
+ * Check if the #IDproperty exists, for operators.
+ */
bool RNA_property_is_set_ex(PointerRNA *ptr, PropertyRNA *prop, bool use_ghost);
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost);
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier);
bool RNA_property_is_idprop(const PropertyRNA *prop);
+/**
+ * \note Mainly for the UI.
+ */
bool RNA_property_is_unlink(PropertyRNA *prop);
void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier);
-/* python compatible string representation of this property, (must be freed!) */
+/**
+ * Python compatible string representation of this property, (must be freed!).
+ */
char *RNA_property_as_string(
struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index, int max_prop_length);
+/**
+ * String representation of a property, Python compatible but can be used for display too.
+ * \param C: can be NULL.
+ */
char *RNA_pointer_as_string_id(struct bContext *C, PointerRNA *ptr);
char *RNA_pointer_as_string(struct bContext *C,
PointerRNA *ptr,
PropertyRNA *prop_ptr,
PointerRNA *ptr_prop);
+/**
+ * \param C: can be NULL.
+ */
char *RNA_pointer_as_string_keywords_ex(struct bContext *C,
PointerRNA *ptr,
const bool as_function,
@@ -1383,7 +1606,9 @@ void RNA_parameter_get(ParameterList *parms, PropertyRNA *parm, void **value);
void RNA_parameter_get_lookup(ParameterList *parms, const char *identifier, void **value);
void RNA_parameter_set(ParameterList *parms, PropertyRNA *parm, const void *value);
void RNA_parameter_set_lookup(ParameterList *parms, const char *identifier, const void *value);
+
/* Only for PROP_DYNAMIC properties! */
+
int RNA_parameter_dynamic_length_get(ParameterList *parms, PropertyRNA *parm);
int RNA_parameter_dynamic_length_get_data(ParameterList *parms, PropertyRNA *parm, void *data);
void RNA_parameter_dynamic_length_set(ParameterList *parms, PropertyRNA *parm, int length);
@@ -1454,6 +1679,7 @@ StructRNA *ID_code_to_RNA_type(short idcode);
# define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, __VA_ARGS__)
#endif
+/** Use to implement the #RNA_warning macro which includes `__func__` suffix. */
void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2);
/* Equals test. */
@@ -1520,6 +1746,16 @@ typedef enum eRNAOverrideStatus {
RNA_OVERRIDE_STATUS_LOCKED = 1 << 3,
} eRNAOverrideStatus;
+/**
+ * Check whether reference and local overridden data match (are the same),
+ * with respect to given restrictive sets of properties.
+ * If requested, will generate needed new property overrides, and/or restore values from reference.
+ *
+ * \param r_report_flags: If given,
+ * will be set with flags matching actions taken by the function on \a ptr_local.
+ *
+ * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
+ */
bool RNA_struct_override_matches(struct Main *bmain,
struct PointerRNA *ptr_local,
struct PointerRNA *ptr_reference,
@@ -1529,6 +1765,10 @@ bool RNA_struct_override_matches(struct Main *bmain,
const eRNAOverrideMatch flags,
eRNAOverrideMatchResult *r_report_flags);
+/**
+ * Store needed second operands into \a storage data-block
+ * for differential override operations.
+ */
bool RNA_struct_override_store(struct Main *bmain,
struct PointerRNA *ptr_local,
struct PointerRNA *ptr_reference,
@@ -1544,6 +1784,10 @@ typedef enum eRNAOverrideApplyFlag {
RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS = 1 << 0,
} eRNAOverrideApplyFlag;
+/**
+ * Apply given \a override operations on \a ptr_dst, using \a ptr_src
+ * (and \a ptr_storage for differential ops) as source.
+ */
void RNA_struct_override_apply(struct Main *bmain,
struct PointerRNA *ptr_dst,
struct PointerRNA *ptr_src,
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 01e26cbb41c..3596a5f2234 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -49,6 +49,10 @@ void RNA_free(BlenderRNA *brna);
void RNA_define_verify_sdna(bool verify);
void RNA_define_animate_sdna(bool animate);
void RNA_define_fallback_property_update(int noteflag, const char *updatefunc);
+/**
+ * Properties defined when this is enabled are lib-overridable by default
+ * (except for Pointer ones).
+ */
void RNA_define_lib_overridable(const bool make_overridable);
void RNA_init(void);
@@ -56,6 +60,9 @@ void RNA_exit(void);
/* Struct */
+/**
+ * Struct Definition.
+ */
StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRNA *srnafrom);
StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *from);
void RNA_def_struct_sdna(StructRNA *srna, const char *structname);
@@ -72,6 +79,9 @@ void RNA_def_struct_register_funcs(StructRNA *srna,
const char *unreg,
const char *instance);
void RNA_def_struct_path_func(StructRNA *srna, const char *path);
+/**
+ * Only used in one case when we name the struct for the purpose of useful error messages.
+ */
void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier);
void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier);
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description);
@@ -176,6 +186,9 @@ PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont,
int default_value,
const char *ui_name,
const char *ui_description);
+/**
+ * Same as above but sets #PROP_ENUM_FLAG before setting the default value.
+ */
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont,
const char *identifier,
const EnumPropertyItem *items,
@@ -362,6 +375,13 @@ void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
+/**
+ * Add the property-tags passed as \a tags to \a prop (if valid).
+ *
+ * \note Multiple tags can be set by passing them within \a tags (using bit-flags).
+ * \note Doesn't do any type-checking with the tags defined in the parent #StructRNA
+ * of \a prop. This should be done before (e.g. see #WM_operatortype_prop_tag).
+ */
void RNA_def_property_tags(PropertyRNA *prop, int tags);
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype);
void RNA_def_property_array(PropertyRNA *prop, int length);
@@ -381,11 +401,25 @@ void RNA_def_property_boolean_array_default(PropertyRNA *prop, const bool *array
void RNA_def_property_int_default(PropertyRNA *prop, int value);
void RNA_def_property_int_array_default(PropertyRNA *prop, const int *array);
void RNA_def_property_float_default(PropertyRNA *prop, float value);
+/**
+ * Array must remain valid after this function finishes.
+ */
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array);
void RNA_def_property_enum_default(PropertyRNA *prop, int value);
void RNA_def_property_string_default(PropertyRNA *prop, const char *value);
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description);
+/**
+ * The values hare are a little confusing:
+ *
+ * \param step: Used as the value to increase/decrease when clicking on number buttons,
+ * as well as scaling mouse input for click-dragging number buttons.
+ * For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows.
+ * For ints, whole values are used.
+ *
+ * \param precision: The number of zeros to show
+ * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX
+ */
void RNA_def_property_ui_range(
PropertyRNA *prop, double min, double max, double step, int precision);
void RNA_def_property_ui_scale_type(PropertyRNA *prop, PropertyScaleType scale_type);
@@ -395,6 +429,11 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
+/**
+ * Set custom callbacks for override operations handling.
+ *
+ * \note \a diff callback will also be used by RNA comparison/equality functions.
+ */
void RNA_def_property_override_funcs(PropertyRNA *prop,
const char *diff,
const char *store,
@@ -472,6 +511,9 @@ void RNA_def_property_translation_context(PropertyRNA *prop, const char *context
FunctionRNA *RNA_def_function(StructRNA *srna, const char *identifier, const char *call);
FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, CallFunc call);
+/**
+ * C return value only! multiple RNA returns can be done with #RNA_def_function_output.
+ */
void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret);
void RNA_def_function_output(FunctionRNA *func, PropertyRNA *ret);
void RNA_def_function_flag(FunctionRNA *func, int flag);
@@ -514,7 +556,8 @@ void RNA_def_property_free_identifier_deferred_finish(StructOrFunctionRNA *cont_
void RNA_def_property_free_pointers_set_py_data_callback(
void (*py_data_clear_fn)(PropertyRNA *prop));
-/* utilities */
+/* Utilities. */
+
const char *RNA_property_typename(PropertyType type);
#define IS_DNATYPE_FLOAT_COMPAT(_str) (strcmp(_str, "float") == 0 || strcmp(_str, "double") == 0)
#define IS_DNATYPE_INT_COMPAT(_str) \
@@ -525,16 +568,19 @@ const char *RNA_property_typename(PropertyType type);
void RNA_identifier_sanitize(char *identifier, int property);
+/* Common arguments for length. */
+
extern const int rna_matrix_dimsize_3x3[];
extern const int rna_matrix_dimsize_4x4[];
extern const int rna_matrix_dimsize_4x2[];
+/* Common arguments for defaults. */
+
extern const float rna_default_axis_angle[4];
extern const float rna_default_quaternion[4];
extern const float rna_default_scale_3d[3];
-/* max size for dynamic defined type descriptors,
- * this value is arbitrary */
+/** Maximum size for dynamic defined type descriptors, this value is arbitrary. */
#define RNA_DYN_DESCR_MAX 240
#ifdef __cplusplus
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index fb18802483d..531af92c544 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -61,6 +61,8 @@ DEF_ENUM(rna_enum_object_shaderfx_type_items)
DEF_ENUM(rna_enum_modifier_triangulate_quad_method_items)
DEF_ENUM(rna_enum_modifier_triangulate_ngon_method_items)
DEF_ENUM(rna_enum_modifier_shrinkwrap_mode_items)
+DEF_ENUM(rna_enum_shrinkwrap_type_items)
+DEF_ENUM(rna_enum_shrinkwrap_face_cull_items)
DEF_ENUM(rna_enum_image_type_items)
DEF_ENUM(rna_enum_image_color_mode_items)
@@ -172,6 +174,7 @@ DEF_ENUM(rna_enum_mapping_type_items)
DEF_ENUM(rna_enum_node_vec_math_items)
DEF_ENUM(rna_enum_node_boolean_math_items)
DEF_ENUM(rna_enum_node_float_compare_items)
+DEF_ENUM(rna_enum_node_compare_operation_items)
DEF_ENUM(rna_enum_node_filter_items)
DEF_ENUM(rna_enum_node_float_to_int_items)
DEF_ENUM(rna_enum_node_map_range_items)
@@ -210,6 +213,7 @@ DEF_ENUM(rna_enum_attribute_type_with_auto_items)
DEF_ENUM(rna_enum_attribute_domain_items)
DEF_ENUM(rna_enum_attribute_domain_without_corner_items)
DEF_ENUM(rna_enum_attribute_domain_with_auto_items)
+DEF_ENUM(rna_enum_geometry_component_type_items)
DEF_ENUM(rna_enum_volume_grid_data_type_items)
@@ -221,7 +225,7 @@ DEF_ENUM(rna_enum_subdivision_boundary_smooth_items)
DEF_ENUM(rna_enum_transform_orientation_items)
-/* Not available to RNA pre-processing (`makrsrna`).
+/* Not available to RNA pre-processing (`makesrna`).
* Defined in editors for example. */
#ifndef RNA_MAKESRNA
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index d7520834287..da07f1043a7 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -83,8 +83,10 @@ const EnumPropertyItem *rna_TransformOrientation_itemf(struct bContext *C,
struct PropertyRNA *prop,
bool *r_free);
-/* Generic functions, return an enum from library data, index is the position
- * in the linked list can add more for different types as needed */
+/**
+ * Generic functions, return an enum from library data, index is the position
+ * in the linked list can add more for different types as needed.
+ */
const EnumPropertyItem *RNA_action_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 40b5f3ed1da..b64fa58cf6b 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -438,12 +438,6 @@ static PropertyRNA *arraytypemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_double_array,
};
-/* This function initializes a PropertyRNAOrID with all required info, from a given PropertyRNA
- * and PointerRNA data. It deals properly with the three cases (static RNA, runtime RNA, and
- * IDProperty).
- * WARNING: given `ptr` PointerRNA is assumed to be a valid data one here, calling code is
- * responsible to ensure that.
- */
void rna_property_rna_or_id_get(PropertyRNA *prop,
PointerRNA *ptr,
PropertyRNAOrID *r_prop_rna_or_id)
@@ -515,8 +509,6 @@ void rna_property_rna_or_id_get(PropertyRNA *prop,
}
}
-/* This function only returns an IDProperty,
- * or NULL (in case IDProp could not be found, or prop is a real RNA property). */
IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
{
PropertyRNAOrID prop_rna_or_id;
@@ -527,8 +519,6 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
return prop_rna_or_id.idprop;
}
-/* This function always return the valid, real data pointer, be it a regular RNA property one,
- * or an IDProperty one. */
PropertyRNA *rna_ensure_property_realdata(PropertyRNA **prop, PointerRNA *ptr)
{
PropertyRNAOrID prop_rna_or_id;
@@ -661,11 +651,6 @@ StructRNA *RNA_struct_base(StructRNA *type)
return type->base;
}
-/**
- * Use to find the subtype directly below a base-type.
- *
- * So if type were `RNA_SpotLIght`, `RNA_struct_base_of(type, &RNA_ID)` would return `&RNA_Light`.
- */
const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type)
{
while (type) {
@@ -697,18 +682,11 @@ bool RNA_struct_idprops_datablock_allowed(const StructRNA *type)
return (type->flag & (STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_IDPROPERTIES)) == 0;
}
-/**
- * Whether given type implies datablock usage by IDProperties.
- * This is used to prevent classes allowed to have IDProperties,
- * but not datablock ones, to indirectly use some
- * (e.g. by assigning an IDP_GROUP containing some IDP_ID pointers...).
- */
bool RNA_struct_idprops_contains_datablock(const StructRNA *type)
{
return (type->flag & (STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES | STRUCT_ID)) != 0;
}
-/* remove an id-property */
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier)
{
IDProperty *group = RNA_struct_idprops(ptr, 0);
@@ -825,8 +803,6 @@ unsigned int RNA_struct_count_properties(StructRNA *srna)
return counter;
}
-/* Low level direct access to type->properties,
- * note this ignores parent classes so should be used with care. */
const struct ListBase *RNA_struct_type_properties(StructRNA *srna)
{
return &srna->cont.properties;
@@ -837,10 +813,6 @@ PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *
return BLI_findstring_ptr(&srna->cont.properties, identifier, offsetof(PropertyRNA, identifier));
}
-/**
- * \note #RNA_struct_find_property is a higher level alternative to this function
- * which takes a #PointerRNA instead of a #StructRNA.
- */
PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
{
for (; srna; srna = srna->base) {
@@ -953,9 +925,6 @@ char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, i
return NULL;
}
-/**
- * Use when registering structs with the #STRUCT_PUBLIC_NAMESPACE flag.
- */
bool RNA_struct_available_or_report(ReportList *reports, const char *identifier)
{
const StructRNA *srna_exists = RNA_struct_find(identifier);
@@ -1098,12 +1067,6 @@ int RNA_property_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag;
}
-/**
- * Get the tags set for \a prop as int bitfield.
- * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
- * in debug builds (to avoid performance issues in non-debug builds), which should be
- * the only way to set tags. Hence, at this point we assume the tag bitfield to be valid.
- */
int RNA_property_tags(PropertyRNA *prop)
{
return rna_ensure_property(prop)->tags;
@@ -1129,7 +1092,6 @@ bool RNA_property_array_check(PropertyRNA *prop)
return rna_ensure_property_array_check(prop);
}
-/* used by BPY to make an array from the python object */
int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[])
{
PropertyRNA *rprop = rna_ensure_property(prop);
@@ -1141,7 +1103,6 @@ int RNA_property_array_dimension(PointerRNA *ptr, PropertyRNA *prop, int length[
return rprop->arraydimension;
}
-/* Return the size of Nth dimension. */
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dim)
{
int len[RNA_MAX_ARRAY_DIMENSION];
@@ -1445,9 +1406,6 @@ int RNA_property_int_clamp(PointerRNA *ptr, PropertyRNA *prop, int *value)
return 0;
}
-/**
- * \return the maximum length including the \0 terminator. '0' is used when there is no maximum.
- */
int RNA_property_string_maxlength(PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
@@ -1774,10 +1732,6 @@ int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifie
return -1;
}
-/**
- * Take care using this with translated enums,
- * prefer #RNA_enum_from_identifier where possible.
- */
int RNA_enum_from_name(const EnumPropertyItem *item, const char *name)
{
int i = 0;
@@ -1973,10 +1927,6 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig)
(!ID_IS_OVERRIDE_LIBRARY(id) || RNA_property_overridable_get(ptr, prop_orig)))));
}
-/**
- * Version of #RNA_property_editable that tries to return additional info in \a r_info
- * that can be exposed in UI.
- */
bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info)
{
ID *id = ptr->owner_id;
@@ -2027,7 +1977,6 @@ bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop)
return (flag & PROP_EDITABLE) != 0;
}
-/* same as RNA_property_editable(), except this checks individual items in an array */
bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
ID *id;
@@ -2090,8 +2039,6 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
return false;
}
-/* this function is to check if its possible to create a valid path from the ID
- * its slow so don't call in a loop */
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop)
{
char *path = RNA_path_from_ID_to_property(ptr, prop);
@@ -2194,11 +2141,9 @@ static void rna_property_update(
}
}
-/* must keep in sync with 'rna_property_update'
- * NOTE: its possible this returns a false positive in the case of #PROP_CONTEXT_UPDATE
- * but this isn't likely to be a performance problem. */
bool RNA_property_update_check(PropertyRNA *prop)
{
+ /* NOTE: must keep in sync with #rna_property_update. */
return (prop->magic != RNA_MAGIC || prop->update || prop->noteflag);
}
@@ -2207,7 +2152,6 @@ void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
rna_property_update(C, CTX_data_main(C), CTX_data_scene(C), ptr, prop);
}
-/* NOTE: `scene` pointer may be NULL. */
void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
{
rna_property_update(NULL, bmain, scene, ptr, prop);
@@ -3277,7 +3221,6 @@ char *RNA_property_string_get_alloc(
return buf;
}
-/* this is the length without \0 terminator */
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
@@ -3417,7 +3360,6 @@ char *RNA_property_string_get_default_alloc(
return buf;
}
-/* this is the length without \0 terminator */
int RNA_property_string_default_length(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
@@ -3498,13 +3440,6 @@ int RNA_property_enum_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
return eprop->defaultvalue;
}
-/**
- * Get the value of the item that is \a step items away from \a from_value.
- *
- * \param from_value: Item value to start stepping from.
- * \param step: Absolute value defines step size, sign defines direction.
- * E.g to get the next item, pass 1, for the previous -1.
- */
int RNA_property_enum_step(
const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step)
{
@@ -4212,7 +4147,6 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr,
return RNA_property_collection_lookup_string_index(ptr, prop, key, r_ptr, &index);
}
-/* zero return is an assignment error */
int RNA_property_collection_assign_int(PointerRNA *ptr,
PropertyRNA *prop,
const int key,
@@ -4987,6 +4921,10 @@ static char *rna_path_token_in_brackets(const char **path,
return buf;
}
+/**
+ * \return true when when the key in the path is correctly parsed and found in the collection
+ * or when the path is empty.
+ */
static bool rna_path_parse_collection_key(const char **path,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -5002,6 +4940,7 @@ static bool rna_path_parse_collection_key(const char **path,
return true;
}
+ bool found = false;
if (**path == '[') {
bool quoted;
char *token;
@@ -5016,7 +4955,7 @@ static bool rna_path_parse_collection_key(const char **path,
/* check for "" to see if it is a string */
if (quoted) {
if (RNA_property_collection_lookup_string(ptr, prop, token, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
r_nextptr->data = NULL;
@@ -5029,7 +4968,7 @@ static bool rna_path_parse_collection_key(const char **path,
return false; /* we can be sure the fixedbuf was used in this case */
}
if (RNA_property_collection_lookup_int(ptr, prop, intkey, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
r_nextptr->data = NULL;
@@ -5042,7 +4981,7 @@ static bool rna_path_parse_collection_key(const char **path,
}
else {
if (RNA_property_collection_type_get(ptr, prop, r_nextptr)) {
- /* pass */
+ found = true;
}
else {
/* ensure we quit on invalid values */
@@ -5050,7 +4989,7 @@ static bool rna_path_parse_collection_key(const char **path,
}
}
- return true;
+ return found;
}
static bool rna_path_parse_array_index(const char **path,
@@ -5326,17 +5265,6 @@ static bool rna_path_parse(PointerRNA *ptr,
return true;
}
-/**
- * Resolve the given RNA Path to find the pointer and/or property
- * indicated by fully resolving the path.
- *
- * \warning Unlike \a RNA_path_resolve_property(), that one *will* try to follow RNAPointers,
- * e.g. the path 'parent' applied to a RNAObject \a ptr will return the object.parent in \a r_ptr,
- * and a NULL \a r_prop...
- *
- * \note Assumes all pointers provided are valid
- * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
{
if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true)) {
@@ -5346,13 +5274,6 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
return r_ptr->data != NULL;
}
-/**
- * Resolve the given RNA Path to find the pointer and/or property + array index
- * indicated by fully resolving the path.
- *
- * \note Assumes all pointers provided are valid.
- * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
bool RNA_path_resolve_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
@@ -5363,26 +5284,12 @@ bool RNA_path_resolve_full(
return r_ptr->data != NULL;
}
-/**
- * A version of #RNA_path_resolve_full doesn't check the value of #PointerRNA.data.
- *
- * \note While it's correct to ignore the value of #PointerRNA.data
- * most callers need to know if the resulting pointer was found and not null.
- */
bool RNA_path_resolve_full_maybe_null(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
return rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true);
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property
- * indicated by fully resolving the path.
- *
- * This is a convenience method to avoid logic errors and ugly syntax.
- * \note Assumes all pointers provided are valid
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5395,14 +5302,6 @@ bool RNA_path_resolve_property(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
- * indicated by fully resolving the path.
- *
- * This is a convenience method to avoid logic errors and ugly syntax.
- * \note Assumes all pointers provided are valid
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_full(
PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
@@ -5413,18 +5312,6 @@ bool RNA_path_resolve_property_full(
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property
- * indicated by fully resolving the path, and get the value of the Pointer property
- * (or item of the collection).
- *
- * This is a convenience method to avoid logic errors and ugly syntax,
- * it combines both \a RNA_path_resolve and #RNA_path_resolve_property in a single call.
- * \note Assumes all pointers provided are valid.
- * \param r_item_ptr: The final Pointer or Collection item value.
- * You must check for its validity before use!
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5438,19 +5325,6 @@ bool RNA_path_resolve_property_and_item_pointer(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
- * indicated by fully resolving the path,
- * and get the value of the Pointer property (or item of the collection).
- *
- * This is a convenience method to avoid logic errors and ugly syntax,
- * it combines both \a RNA_path_resolve_full and
- * \a RNA_path_resolve_property_full in a single call.
- * \note Assumes all pointers provided are valid.
- * \param r_item_ptr: The final Pointer or Collection item value.
- * You must check for its validity before use!
- * \return True only if both a valid pointer and property are found after resolving the path
- */
bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
const char *path,
PointerRNA *r_ptr,
@@ -5464,15 +5338,6 @@ bool RNA_path_resolve_property_and_item_pointer_full(PointerRNA *ptr,
return r_ptr->data != NULL && *r_prop != NULL;
}
-/**
- * Resolve the given RNA Path into a linked list of PropertyElemRNA's.
- *
- * To be used when complex operations over path are needed, like e.g. get relative paths,
- * to avoid too much string operations.
- *
- * \return True if there was no error while resolving the path
- * \note Assumes all pointers provided are valid
- */
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
{
return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false);
@@ -5723,16 +5588,6 @@ static char *rna_idp_path(PointerRNA *ptr,
return path;
}
-/**
- * Find the path from the structure referenced by the pointer to the runtime RNA-defined
- * #IDProperty object.
- *
- * \note Does *not* handle pure user-defined IDProperties (a.k.a. custom properties).
- *
- * \param ptr: Reference to the object owning the custom property storage.
- * \param needle: Custom property object to find.
- * \return Relative path or NULL.
- */
char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle)
{
IDProperty *haystack = RNA_struct_idprops(ptr, false);
@@ -5759,13 +5614,6 @@ static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr)
return RNA_path_from_struct_to_idproperty(&id_ptr, ptr->data);
}
-/**
- * Find the actual ID pointer and path from it to the given ID.
- *
- * \param id: ID reference to search the global owner for.
- * \param[out] r_path: Path from the real ID to the initial ID.
- * \return The ID pointer, or NULL in case of failure.
- */
ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path)
{
if (r_path) {
@@ -5918,11 +5766,6 @@ static void rna_path_array_multi_string_from_flat_index(PointerRNA *ptr,
}
}
-/**
- * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
- * \param index: The *flattened* index to use when \a `index_dim > 0`,
- * this is expanded when used with multi-dimensional arrays.
- */
char *RNA_path_from_ID_to_property_index(PointerRNA *ptr,
PropertyRNA *prop,
int index_dim,
@@ -5994,10 +5837,6 @@ char *RNA_path_from_real_ID_to_property_index(
return path != NULL ? rna_prepend_real_ID_path(bmain, ptr->owner_id, path, r_real_id) : NULL;
}
-/**
- * \return the path to given ptr/prop from the closest ancestor of given type,
- * if any (else return NULL).
- */
char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
PropertyRNA *prop,
const StructRNA *type)
@@ -6036,10 +5875,6 @@ char *RNA_path_resolve_from_type_to_property(PointerRNA *ptr,
return path;
}
-/**
- * Get the ID as a python representation, eg:
- * bpy.data.foo["bar"]
- */
char *RNA_path_full_ID_py(Main *bmain, ID *id)
{
const char *path;
@@ -6075,10 +5910,6 @@ char *RNA_path_full_ID_py(Main *bmain, ID *id)
path);
}
-/**
- * Get the ID.struct as a python representation, eg:
- * bpy.data.foo["bar"].some_struct
- */
char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
{
char *id_path;
@@ -6107,10 +5938,6 @@ char *RNA_path_full_struct_py(Main *bmain, struct PointerRNA *ptr)
return ret;
}
-/**
- * Get the ID.struct.property as a python representation, eg:
- * bpy.data.foo["bar"].some_struct.some_prop[10]
- */
char *RNA_path_full_property_py_ex(
Main *bmain, PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
{
@@ -6164,10 +5991,6 @@ char *RNA_path_full_property_py(Main *bmain, PointerRNA *ptr, PropertyRNA *prop,
return RNA_path_full_property_py_ex(bmain, ptr, prop, index, false);
}
-/**
- * Get the struct.property as a python representation, eg:
- * some_struct.some_prop[10]
- */
char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
{
char *data_path;
@@ -6205,10 +6028,6 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
return ret;
}
-/**
- * Get the struct.property as a python representation, eg:
- * some_prop[10]
- */
char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index)
{
char *ret;
@@ -6678,7 +6497,6 @@ bool RNA_property_is_idprop(const PropertyRNA *prop)
return (prop->magic != RNA_MAGIC);
}
-/* mainly for the UI */
bool RNA_property_is_unlink(PropertyRNA *prop)
{
const int flag = RNA_property_flag(prop);
@@ -6688,9 +6506,6 @@ bool RNA_property_is_unlink(PropertyRNA *prop)
return (flag & (PROP_NEVER_UNLINK | PROP_NEVER_NULL)) == 0;
}
-/* string representation of a property, python
- * compatible but can be used for display too,
- * context may be NULL */
char *RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr)
{
DynStr *dynstr = BLI_dynstr_new();
@@ -6752,7 +6567,6 @@ char *RNA_pointer_as_string(bContext *C,
return rna_pointer_as_string__bldata(CTX_data_main(C), ptr_prop);
}
-/* context can be NULL */
char *RNA_pointer_as_string_keywords_ex(bContext *C,
PointerRNA *ptr,
const bool as_function,
@@ -8115,7 +7929,6 @@ bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop)
}
}
-/* use RNA_warning macro which includes __func__ suffix */
void _RNA_warning(const char *format, ...)
{
va_list args;
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index be8972dbff3..35af92592e9 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -126,8 +126,6 @@ int RNA_property_override_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag_override;
}
-/** \note Does not take into account editable status, this has to be checked separately
- * (using #RNA_property_editable_flag() usually). */
bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
@@ -170,7 +168,6 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0;
}
-/* Should only be used for custom properties */
bool RNA_property_overridable_library_set(PointerRNA *UNUSED(ptr),
PropertyRNA *prop,
const bool is_overridable)
@@ -614,37 +611,27 @@ static bool rna_property_override_operation_apply(Main *bmain,
}
/* get and set the default values as appropriate for the various types */
- const bool sucess = override_apply(bmain,
- ptr_dst,
- ptr_src,
- ptr_storage,
- prop_dst,
- prop_src,
- prop_storage,
- len_dst,
- len_src,
- len_storage,
- ptr_item_dst,
- ptr_item_src,
- ptr_item_storage,
- opop);
- if (sucess) {
+ const bool success = override_apply(bmain,
+ ptr_dst,
+ ptr_src,
+ ptr_storage,
+ prop_dst,
+ prop_src,
+ prop_storage,
+ len_dst,
+ len_src,
+ len_storage,
+ ptr_item_dst,
+ ptr_item_src,
+ ptr_item_storage,
+ opop);
+ if (success) {
RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst);
}
- return sucess;
+ return success;
}
-/**
- * Check whether reference and local overridden data match (are the same),
- * with respect to given restrictive sets of properties.
- * If requested, will generate needed new property overrides, and/or restore values from reference.
- *
- * \param r_report_flags: If given,
- * will be set with flags matching actions taken by the function on \a ptr_local.
- *
- * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
- */
bool RNA_struct_override_matches(Main *bmain,
PointerRNA *ptr_local,
PointerRNA *ptr_reference,
@@ -928,10 +915,6 @@ bool RNA_struct_override_matches(Main *bmain,
return matching;
}
-/**
- * Store needed second operands into \a storage data-block
- * for differential override operations.
- */
bool RNA_struct_override_store(Main *bmain,
PointerRNA *ptr_local,
PointerRNA *ptr_reference,
@@ -1076,7 +1059,12 @@ static void rna_porperty_override_collection_subitem_lookup(
*r_ptr_item_storage = private_ptr_item_storage;
}
- if ((*r_ptr_item_dst)->type == NULL) {
+ /* Note that there is no reason to report in case no item is expected, i.e. in case subitem name
+ * and index are invalid. This can often happen when inserting new items (constraint,
+ * modifier...) in a collection that supports it. */
+ if ((*r_ptr_item_dst)->type == NULL &&
+ ((opop->subitem_reference_name != NULL && opop->subitem_reference_name[0] != '\0') ||
+ opop->subitem_reference_index != -1)) {
CLOG_INFO(&LOG,
2,
"Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'",
@@ -1085,7 +1073,9 @@ static void rna_porperty_override_collection_subitem_lookup(
op->rna_path,
ptr_dst->owner_id->name);
}
- if ((*r_ptr_item_src)->type == NULL) {
+ if ((*r_ptr_item_src)->type == NULL &&
+ ((opop->subitem_local_name != NULL && opop->subitem_local_name[0] != '\0') ||
+ opop->subitem_local_index != -1)) {
CLOG_INFO(&LOG,
2,
"Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'",
@@ -1195,10 +1185,6 @@ static void rna_property_override_apply_ex(Main *bmain,
}
}
-/**
- * Apply given \a override operations on \a ptr_dst, using \a ptr_src
- * (and \a ptr_storage for differential ops) as source.
- */
void RNA_struct_override_apply(Main *bmain,
PointerRNA *ptr_dst,
PointerRNA *ptr_src,
diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h
index 73407123863..9f1be5bbd67 100644
--- a/source/blender/makesrna/intern/rna_access_internal.h
+++ b/source/blender/makesrna/intern/rna_access_internal.h
@@ -27,6 +27,13 @@
struct IDProperty;
struct PropertyRNAOrID;
+/**
+ * This function initializes a #PropertyRNAOrID with all required info, from a given #PropertyRNA
+ * and #PointerRNA data. It deals properly with the three cases
+ * (static RNA, runtime RNA, and #IDProperty).
+ * \warning given `ptr` #PointerRNA is assumed to be a valid data one here, calling code is
+ * responsible to ensure that.
+ */
void rna_property_rna_or_id_get(PropertyRNA *prop,
PointerRNA *ptr,
PropertyRNAOrID *r_prop_rna_or_id);
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 2aa09a30c75..96e37dfebbb 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -246,12 +246,60 @@ static void rna_Action_active_pose_marker_index_range(
*max = max_ii(0, BLI_listbase_count(&act->markers) - 1);
}
-static void rna_Action_frame_range_get(PointerRNA *ptr, float *values)
+static void rna_Action_frame_range_get(PointerRNA *ptr, float *r_values)
+{
+ BKE_action_get_frame_range((bAction *)ptr->owner_id, &r_values[0], &r_values[1]);
+}
+
+static void rna_Action_frame_range_set(PointerRNA *ptr, const float *values)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->flag |= ACT_FRAME_RANGE;
+ data->frame_start = values[0];
+ data->frame_end = values[1];
+ CLAMP_MIN(data->frame_end, data->frame_start);
+}
+
+static void rna_Action_curve_frame_range_get(PointerRNA *ptr, float *values)
{ /* don't include modifiers because they too easily can have very large
* ranges: MINAFRAMEF to MAXFRAMEF. */
calc_action_range((bAction *)ptr->owner_id, values, values + 1, false);
}
+static void rna_Action_use_frame_range_set(PointerRNA *ptr, bool value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ if (value) {
+ /* If the frame range is blank, initialize it by scanning F-Curves. */
+ if ((data->frame_start == data->frame_end) && (data->frame_start == 0)) {
+ calc_action_range(data, &data->frame_start, &data->frame_end, false);
+ }
+
+ data->flag |= ACT_FRAME_RANGE;
+ }
+ else {
+ data->flag &= ~ACT_FRAME_RANGE;
+ }
+}
+
+static void rna_Action_start_frame_set(PointerRNA *ptr, float value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->frame_start = value;
+ CLAMP_MIN(data->frame_end, data->frame_start);
+}
+
+static void rna_Action_end_frame_set(PointerRNA *ptr, float value)
+{
+ bAction *data = (bAction *)ptr->owner_id;
+
+ data->frame_end = value;
+ CLAMP_MAX(data->frame_start, data->frame_end);
+}
+
/* Used to check if an action (value pointer)
* is suitable to be assigned to the ID-block that is ptr. */
bool rna_Action_id_poll(PointerRNA *ptr, PointerRNA value)
@@ -834,17 +882,73 @@ static void rna_def_action(BlenderRNA *brna)
rna_def_action_pose_markers(brna, prop);
/* properties */
+ prop = RNA_def_property(srna, "use_frame_range", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_FRAME_RANGE);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_Action_use_frame_range_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Manual Frame Range",
+ "Manually specify the intended playback frame range for the action "
+ "(this range is used by some tools, but does not affect animation evaluation)");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "use_cyclic", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CYCLIC);
+ RNA_def_property_ui_text(
+ prop,
+ "Cyclic Animation",
+ "The action is intended to be used as a cycle looping over its manually set "
+ "playback frame range (enabling this doesn't automatically make it loop)");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_float_sdna(prop, NULL, "frame_start");
+ RNA_def_property_float_funcs(prop, NULL, "rna_Action_start_frame_set", NULL);
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 0);
+ RNA_def_property_ui_text(
+ prop, "Start Frame", "The start frame of the manually set intended playback range");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_float_sdna(prop, NULL, "frame_end");
+ RNA_def_property_float_funcs(prop, NULL, "rna_Action_end_frame_set", NULL);
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 100, 0);
+ RNA_def_property_ui_text(
+ prop, "End Frame", "The end frame of the manually set intended playback range");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_float_vector(
+ srna,
+ "frame_range",
+ 2,
+ NULL,
+ 0,
+ 0,
+ "Frame Range",
+ "The intended playback frame range of this action, using the manually set range "
+ "if available, or the combined frame range of all F-Curves within this action "
+ "if not (assigning sets the manual frame range)",
+ 0,
+ 0);
+ RNA_def_property_float_funcs(
+ prop, "rna_Action_frame_range_get", "rna_Action_frame_range_set", NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
prop = RNA_def_float_vector(srna,
- "frame_range",
+ "curve_frame_range",
2,
NULL,
0,
0,
- "Frame Range",
- "The final frame range of all F-Curves within this action",
+ "Curve Frame Range",
+ "The combined frame range of all F-Curves within this action",
0,
0);
- RNA_def_property_float_funcs(prop, "rna_Action_frame_range_get", NULL, NULL);
+ RNA_def_property_float_funcs(prop, "rna_Action_curve_frame_range_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* special "type" limiter - should not really be edited in general,
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 690506fa517..7a934443907 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -669,10 +669,10 @@ static void rna_Armature_transform(bArmature *arm, float mat[16])
#else
-/* Settings for curved bbone settings -
- * The posemode values get applied over the top of the editmode ones. */
void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone, bool is_editbone)
{
+ /* NOTE: The pose-mode values get applied over the top of the edit-mode ones. */
+
# define RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone, is_editbone) \
{ \
if (is_posebone) { \
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index 5d83da170b5..e79cbc838d4 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -307,7 +307,7 @@ const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf();
+ const EnumPropertyItem *items = ED_asset_library_reference_to_rna_enum_itemf(true);
if (!items) {
*r_free = false;
}
@@ -493,9 +493,6 @@ static void rna_def_asset_library_reference(BlenderRNA *brna)
srna, "Asset Library Reference", "Identifier to refer to the asset library");
}
-/**
- * \note the UI text and updating has to be set by the caller.
- */
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set)
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index bde348c1848..0c993660f39 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -3446,7 +3446,8 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
-/* base struct for constraints */
+/* Define the base struct for constraints. */
+
void RNA_def_constraint(BlenderRNA *brna)
{
StructRNA *srna;
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 8c89162f571..6cca0c51988 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -141,8 +141,6 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
static const EnumPropertyItem curve_type_items[] = {
{CU_POLY, "POLY", 0, "Poly", ""},
{CU_BEZIER, "BEZIER", 0, "Bezier", ""},
- {CU_BSPLINE, "BSPLINE", 0, "BSpline", ""},
- {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
{CU_NURBS, "NURBS", 0, "Ease", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -569,13 +567,13 @@ static void rna_Curve_resolution_v_update_data(Main *bmain, Scene *scene, Pointe
static float rna_Curve_offset_get(PointerRNA *ptr)
{
Curve *cu = (Curve *)ptr->owner_id;
- return cu->width - 1.0f;
+ return cu->offset - 1.0f;
}
static void rna_Curve_offset_set(PointerRNA *ptr, float value)
{
Curve *cu = (Curve *)ptr->owner_id;
- cu->width = 1.0f + value;
+ cu->offset = 1.0f + value;
}
static int rna_Curve_body_length(PointerRNA *ptr);
@@ -1656,14 +1654,14 @@ static void rna_def_curve(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Curve_bevel_resolution_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "width");
+ RNA_def_property_float_sdna(prop, NULL, "offset");
RNA_def_property_ui_range(prop, -1.0, 1.0, 0.1, 3);
RNA_def_property_float_funcs(prop, "rna_Curve_offset_get", "rna_Curve_offset_set", NULL);
RNA_def_property_ui_text(prop, "Offset", "Distance to move the curve parallel to its normals");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "extrude", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "ext1");
+ RNA_def_property_float_sdna(prop, NULL, "extrude");
RNA_def_property_ui_range(prop, 0, 100.0, 0.1, 3);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_text(prop,
@@ -1673,7 +1671,7 @@ static void rna_def_curve(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "bevel_depth", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "ext2");
+ RNA_def_property_float_sdna(prop, NULL, "bevel_radius");
RNA_def_property_ui_range(prop, 0, 100.0, 0.1, 3);
RNA_def_property_ui_text(
prop, "Bevel Depth", "Radius of the bevel geometry, not including extrusion");
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index bd5ade36eaa..b17ca7d8d59 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -753,10 +753,6 @@ void RNA_define_verify_sdna(bool verify)
DefRNA.verify = verify;
}
-/**
- * Properties defined when this is enabled are lib-overridable by default (except for Pointer
- * ones).
- */
void RNA_define_lib_overridable(const bool make_overridable)
{
DefRNA.make_overridable = make_overridable;
@@ -915,7 +911,6 @@ static StructDefRNA *rna_find_def_struct(StructRNA *srna)
return NULL;
}
-/* Struct Definition */
StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRNA *srnafrom)
{
StructRNA *srna;
@@ -1243,9 +1238,6 @@ void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *id
srna->identifier = identifier;
}
-/**
- * Only used in one case when we name the struct for the purpose of useful error messages.
- */
void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier)
{
if (DefRNA.preprocess) {
@@ -1532,13 +1524,6 @@ void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFla
prop->flag_override &= ~flag;
}
-/**
- * Add the property-tags passed as \a tags to \a prop (if valid).
- *
- * \note Multiple tags can be set by passing them within \a tags (using bitflags).
- * \note Doesn't do any type-checking with the tags defined in the parent StructRNA
- * of \a prop. This should be done before (e.g. see #WM_operatortype_prop_tag).
- */
void RNA_def_property_tags(PropertyRNA *prop, int tags)
{
prop->tags |= tags;
@@ -1616,12 +1601,10 @@ void RNA_def_property_array(PropertyRNA *prop, int length)
}
}
-/* common args for defaults. */
const float rna_default_quaternion[4] = {1, 0, 0, 0};
const float rna_default_axis_angle[4] = {0, 0, 1, 0};
const float rna_default_scale_3d[3] = {1, 1, 1};
-/* common args for length */
const int rna_matrix_dimsize_3x3[] = {3, 3};
const int rna_matrix_dimsize_4x4[] = {4, 4};
const int rna_matrix_dimsize_4x2[] = {4, 2};
@@ -1692,17 +1675,6 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, int consecutive)
}
}
-/**
- * The values hare are a little confusing:
- *
- * \param step: Used as the value to increase/decrease when clicking on number buttons,
- * as well as scaling mouse input for click-dragging number buttons.
- * For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows.
- * For ints, whole values are used.
- *
- * \param precision: The number of zeros to show
- * (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX
- */
void RNA_def_property_ui_range(
PropertyRNA *prop, double min, double max, double step, int precision)
{
@@ -2082,7 +2054,6 @@ void RNA_def_property_float_default(PropertyRNA *prop, float value)
break;
}
}
-/* array must remain valid after this function finishes */
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
{
StructRNA *srna = DefRNA.laststruct;
@@ -2920,11 +2891,6 @@ void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editabl
}
}
-/**
- * Set custom callbacks for override operations handling.
- *
- * \note \a diff callback will also be used by RNA comparison/equality functions.
- */
void RNA_def_property_override_funcs(PropertyRNA *prop,
const char *diff,
const char *store,
@@ -3813,7 +3779,6 @@ PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont_,
return prop;
}
-/* same as above but sets 'PROP_ENUM_FLAG' before setting the default value */
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_,
const char *identifier,
const EnumPropertyItem *items,
@@ -4320,7 +4285,6 @@ FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, C
return func;
}
-/* C return value only!, multiple RNA returns can be done with RNA_def_function_output */
void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret)
{
if (ret->flag & PROP_DYNAMIC) {
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 82f3279146a..e06aac31124 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -28,6 +28,7 @@
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -144,6 +145,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_OFFSET,
"Offset",
"Change stroke location, rotation or scale"},
+ {eGpencilModifierType_Shrinkwrap,
+ "SHRINKWRAP",
+ ICON_MOD_SHRINKWRAP,
+ "Shrinkwrap",
+ "Project the shape onto another object"},
{eGpencilModifierType_Smooth, "GP_SMOOTH", ICON_MOD_SMOOTH, "Smooth", "Smooth stroke"},
{eGpencilModifierType_Thick,
"GP_THICK",
@@ -269,6 +275,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_LengthGpencilModifier;
case eGpencilModifierType_Mirror:
return &RNA_MirrorGpencilModifier;
+ case eGpencilModifierType_Shrinkwrap:
+ return &RNA_ShrinkwrapGpencilModifier;
case eGpencilModifierType_Smooth:
return &RNA_SmoothGpencilModifier;
case eGpencilModifierType_Hook:
@@ -360,6 +368,7 @@ RNA_GP_MOD_VGROUP_NAME_SET(WeightProx, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(WeightAngle, target_vgname);
RNA_GP_MOD_VGROUP_NAME_SET(WeightAngle, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Lineart, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Shrinkwrap, vgname);
# undef RNA_GP_MOD_VGROUP_NAME_SET
@@ -392,6 +401,8 @@ RNA_GP_MOD_OBJECT_SET(Armature, object, OB_ARMATURE);
RNA_GP_MOD_OBJECT_SET(Lattice, object, OB_LATTICE);
RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY);
RNA_GP_MOD_OBJECT_SET(WeightProx, object, OB_EMPTY);
+RNA_GP_MOD_OBJECT_SET(Shrinkwrap, target, OB_MESH);
+RNA_GP_MOD_OBJECT_SET(Shrinkwrap, aux_target, OB_MESH);
# undef RNA_GP_MOD_OBJECT_SET
@@ -685,6 +696,16 @@ static void rna_TextureGpencilModifier_material_set(PointerRNA *ptr,
rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
}
+static void rna_ShrinkwrapGpencilModifier_material_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ ShrinkwrapGpencilModifierData *tmd = (ShrinkwrapGpencilModifierData *)ptr->data;
+ Material **ma_target = &tmd->material;
+
+ rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
+}
+
static void rna_Lineart_start_level_set(PointerRNA *ptr, int value)
{
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)ptr->data;
@@ -756,6 +777,18 @@ static void rna_DashGpencilModifierSegment_name_set(PointerRNA *ptr, const char
BKE_animdata_fix_paths_rename_all(NULL, prefix, oldname, ds->name);
}
+static int rna_ShrinkwrapGpencilModifier_face_cull_get(PointerRNA *ptr)
+{
+ ShrinkwrapGpencilModifierData *swm = (ShrinkwrapGpencilModifierData *)ptr->data;
+ return swm->shrink_opts & MOD_SHRINKWRAP_CULL_TARGET_MASK;
+}
+
+static void rna_ShrinkwrapGpencilModifier_face_cull_set(struct PointerRNA *ptr, int value)
+{
+ ShrinkwrapGpencilModifierData *swm = (ShrinkwrapGpencilModifierData *)ptr->data;
+ swm->shrink_opts = (swm->shrink_opts & ~MOD_SHRINKWRAP_CULL_TARGET_MASK) | value;
+}
+
#else
static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
@@ -3455,6 +3488,43 @@ static void rna_def_modifier_gpencillength(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "End Factor", "Absolute added length to the end of each stroke");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "random_start_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_start_fac");
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.1, 1);
+ RNA_def_property_ui_text(
+ prop, "Random Start Factor", "Size of random length added to the start of each stroke");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random_end_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_end_fac");
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.1, 1);
+ RNA_def_property_ui_text(
+ prop, "Random End Factor", "Size of random length added to the end of each stroke");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rand_offset");
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1, 3);
+ RNA_def_property_ui_text(
+ prop, "Random Noise Offset", "Smoothly offset each stroke's random value");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_random", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LENGTH_USE_RANDOM);
+ RNA_def_property_ui_text(prop, "Random", "Use random values over time");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_ui_text(prop, "Seed", "Random seed");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(
+ prop, "Step", "Number of frames before recalculate random values again");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "overshoot_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "overshoot_fac");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -3683,6 +3753,194 @@ static void rna_def_modifier_gpencildash(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
+static void rna_def_modifier_gpencilshrinkwrap(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShrinkwrapGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna,
+ "Shrinkwrap Modifier",
+ "Shrink wrapping modifier to shrink wrap and object to a target");
+ RNA_def_struct_sdna(srna, "ShrinkwrapGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SHRINKWRAP);
+
+ RNA_define_lib_overridable(true);
+
+ prop = RNA_def_property(srna, "wrap_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_type");
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_type_items);
+ RNA_def_property_ui_text(prop, "Wrap Method", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "wrap_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_mode");
+ RNA_def_property_enum_items(prop, rna_enum_modifier_shrinkwrap_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Snap Mode", "Select how vertices are constrained to the target surface");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrink_opts");
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_face_cull_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_ShrinkwrapGpencilModifier_face_cull_get",
+ "rna_ShrinkwrapGpencilModifier_face_cull_set",
+ NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Face Cull",
+ "Stop vertices from projecting to a face on the target when facing towards/away");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Target", "Mesh target to shrink to");
+ RNA_def_property_pointer_funcs(
+ prop, NULL, "rna_ShrinkwrapGpencilModifier_target_set", NULL, "rna_Mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "auxiliary_target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "aux_target");
+ RNA_def_property_ui_text(prop, "Auxiliary Target", "Additional mesh target to shrink to");
+ RNA_def_property_pointer_funcs(
+ prop, NULL, "rna_ShrinkwrapGpencilModifier_aux_target_set", NULL, "rna_Mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "keep_dist");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -100, 100, 1, 2);
+ RNA_def_property_ui_text(prop, "Offset", "Distance to keep from the target");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "project_limit", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "proj_limit");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 100, 1, 2);
+ RNA_def_property_ui_text(
+ prop, "Project Limit", "Limit the distance used for projection (zero disables)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS);
+ RNA_def_property_ui_text(prop, "X", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS);
+ RNA_def_property_ui_text(prop, "Y", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_project_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proj_axis", MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS);
+ RNA_def_property_ui_text(prop, "Z", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "subsurf_levels", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "subsurf_levels");
+ RNA_def_property_range(prop, 0, 6);
+ RNA_def_property_ui_range(prop, 0, 6, 1, -1);
+ RNA_def_property_ui_text(
+ prop,
+ "Subdivision Levels",
+ "Number of subdivisions that must be performed before extracting vertices' "
+ "positions and normals");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_negative_direction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR);
+ RNA_def_property_ui_text(
+ prop, "Negative", "Allow vertices to move in the negative direction of axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_positive_direction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR);
+ RNA_def_property_ui_text(
+ prop, "Positive", "Allow vertices to move in the positive direction of axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_invert_cull", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrink_opts", MOD_SHRINKWRAP_INVERT_CULL_TARGET);
+ RNA_def_property_ui_text(
+ prop, "Invert Cull", "When projecting in the negative direction invert the face cull mode");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop,
+ NULL,
+ "rna_ShrinkwrapGpencilModifier_material_set",
+ NULL,
+ "rna_GpencilModifier_material_poll");
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ShrinkwrapGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_MATERIAL);
+ RNA_def_property_ui_text(prop, "Inverse Materials", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SHRINKWRAP_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SHRINKWRAP_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "smooth_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "smooth_factor");
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_text(prop, "Smooth Factor", "Amount of smoothing to apply");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "smooth_step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "smooth_step");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(
+ prop, "Step", "Number of times to apply smooth (high numbers can reduce FPS)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ RNA_define_lib_overridable(false);
+}
+
void RNA_def_greasepencil_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3772,6 +4030,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencillineart(brna);
rna_def_modifier_gpencillength(brna);
rna_def_modifier_gpencildash(brna);
+ rna_def_modifier_gpencilshrinkwrap(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 4b52ceb6241..7d2697c8770 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -213,11 +213,17 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
}
}
-static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
+static int rna_Image_gl_load(
+ Image *image, ReportList *reports, int frame, int layer_index, int pass_index)
{
ImageUser iuser;
BKE_imageuser_default(&iuser);
iuser.framenr = frame;
+ iuser.layer = layer_index;
+ iuser.pass = pass_index;
+ if (image->rr != NULL) {
+ BKE_image_multilayer_index(image->rr, &iuser);
+ }
GPUTexture *tex = BKE_image_get_gpu_texture(image, &iuser, NULL);
@@ -230,14 +236,15 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame)
return 0; /* GL_NO_ERROR */
}
-static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame)
+static int rna_Image_gl_touch(
+ Image *image, ReportList *reports, int frame, int layer_index, int pass_index)
{
int error = 0; /* GL_NO_ERROR */
BKE_image_tag_time(image);
if (image->gputexture[TEXTARGET_2D][0] == NULL) {
- error = rna_Image_gl_load(image, reports, frame);
+ error = rna_Image_gl_load(image, reports, frame, layer_index, pass_index);
}
return error;
@@ -332,6 +339,24 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
+ RNA_def_int(func,
+ "layer_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Layer",
+ "Index of layer that should be loaded",
+ 0,
+ INT_MAX);
+ RNA_def_int(func,
+ "pass_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Pass",
+ "Index of pass that should be loaded",
+ 0,
+ INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
@@ -346,6 +371,24 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(
func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX);
+ RNA_def_int(func,
+ "layer_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Layer",
+ "Index of layer that should be loaded",
+ 0,
+ INT_MAX);
+ RNA_def_int(func,
+ "pass_index",
+ 0,
+ 0,
+ INT_MAX,
+ "Pass",
+ "Index of pass that should be loaded",
+ 0,
+ INT_MAX);
/* return value */
parm = RNA_def_int(
func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index fd6664ff0de..c1989a5b10d 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -251,6 +251,9 @@ bool rna_AnimaData_override_apply(struct Main *bmain,
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
+/**
+ * Settings for curved bbone settings.
+ */
void rna_def_bone_curved_common(struct StructRNA *srna, bool is_posebone, bool is_editbone);
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
@@ -268,6 +271,9 @@ void rna_def_texpaint_slots(struct BlenderRNA *brna, struct StructRNA *srna);
void rna_def_view_layer_common(struct BlenderRNA *brna, struct StructRNA *srna, const bool scene);
int rna_AssetMetaData_editable(struct PointerRNA *ptr, const char **r_info);
+/**
+ * \note the UI text and updating has to be set by the caller.
+ */
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set);
@@ -276,6 +282,9 @@ const EnumPropertyItem *rna_asset_library_reference_itemf(struct bContext *C,
struct PropertyRNA *prop,
bool *r_free);
+/**
+ * Common properties for Action/Bone Groups - related to color.
+ */
void rna_def_actionbone_group_common(struct StructRNA *srna,
int update_flag,
const char *update_cb);
@@ -509,8 +518,16 @@ extern StructRNA RNA_PropertyGroupItem;
extern StructRNA RNA_PropertyGroup;
#endif
+/**
+ * This function only returns an #IDProperty,
+ * or NULL (in case IDProp could not be found, or prop is a real RNA property).
+ */
struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop,
struct PointerRNA *ptr) ATTR_WARN_UNUSED_RESULT;
+/**
+ * This function always return the valid, real data pointer, be it a regular RNA property one,
+ * or an #IDProperty one.
+ */
struct PropertyRNA *rna_ensure_property_realdata(struct PropertyRNA **prop,
struct PointerRNA *ptr) ATTR_WARN_UNUSED_RESULT;
struct PropertyRNA *rna_ensure_property(struct PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index 8cd1ac0d963..93e8e4bc31e 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -949,8 +949,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1051,8 +1052,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1191,8 +1193,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Period", "Period of the noise");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Seed", "Seed for the noise generation");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -1306,8 +1309,9 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
srna, "Sinus Displacement", "Add sinus displacement to stroke backbone geometry");
rna_def_geometry_modifier(srna);
- prop = RNA_def_property(srna, "wavelength", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "wavelength", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "wavelength");
+ RNA_def_property_range(prop, 0.0001f, FLT_MAX);
RNA_def_property_ui_text(prop, "Wavelength", "Wavelength of the sinus displacement");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 464abc6b543..a162aa26b78 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -56,9 +56,10 @@ static void rna_Main_use_autopack_set(PointerRNA *UNUSED(ptr), bool value)
}
}
-static bool rna_Main_is_saved_get(PointerRNA *UNUSED(ptr))
+static bool rna_Main_is_saved_get(PointerRNA *ptr)
{
- return G.relbase_valid;
+ const Main *bmain = (Main *)ptr->data;
+ return (bmain->filepath[0] != '\0');
}
static bool rna_Main_is_dirty_get(PointerRNA *ptr)
@@ -76,20 +77,20 @@ static bool rna_Main_is_dirty_get(PointerRNA *ptr)
static void rna_Main_filepath_get(PointerRNA *ptr, char *value)
{
Main *bmain = (Main *)ptr->data;
- BLI_strncpy(value, bmain->name, sizeof(bmain->name));
+ BLI_strncpy(value, bmain->filepath, sizeof(bmain->filepath));
}
static int rna_Main_filepath_length(PointerRNA *ptr)
{
Main *bmain = (Main *)ptr->data;
- return strlen(bmain->name);
+ return strlen(bmain->filepath);
}
# if 0
static void rna_Main_filepath_set(PointerRNA *ptr, const char *value)
{
Main *bmain = (Main *)ptr->data;
- BLI_strncpy(bmain->name, value, sizeof(bmain->name));
+ STRNCPY(bmain->filepath, value);
}
# endif
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 9ad6771cda3..d46ae13b482 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -381,6 +381,42 @@ const EnumPropertyItem rna_enum_modifier_shrinkwrap_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_shrinkwrap_type_items[] = {
+ {MOD_SHRINKWRAP_NEAREST_SURFACE,
+ "NEAREST_SURFACEPOINT",
+ 0,
+ "Nearest Surface Point",
+ "Shrink the mesh to the nearest target surface"},
+ {MOD_SHRINKWRAP_PROJECT,
+ "PROJECT",
+ 0,
+ "Project",
+ "Shrink the mesh to the nearest target surface along a given axis"},
+ {MOD_SHRINKWRAP_NEAREST_VERTEX,
+ "NEAREST_VERTEX",
+ 0,
+ "Nearest Vertex",
+ "Shrink the mesh to the nearest target vertex"},
+ {MOD_SHRINKWRAP_TARGET_PROJECT,
+ "TARGET_PROJECT",
+ 0,
+ "Target Normal Project",
+ "Shrink the mesh to the nearest target surface "
+ "along the interpolated vertex normals of the target"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_shrinkwrap_face_cull_items[] = {
+ {0, "OFF", 0, "Off", "No culling"},
+ {MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE,
+ "FRONT",
+ 0,
+ "Front",
+ "No projection when in front of the face"},
+ {MOD_SHRINKWRAP_CULL_TARGET_BACKFACE, "BACK", 0, "Back", "No projection when behind the face"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
/* use eWarp_Falloff_*** & eHook_Falloff_***, they're in sync */
static const EnumPropertyItem modifier_warp_falloff_items[] = {
@@ -4184,46 +4220,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem shrink_type_items[] = {
- {MOD_SHRINKWRAP_NEAREST_SURFACE,
- "NEAREST_SURFACEPOINT",
- 0,
- "Nearest Surface Point",
- "Shrink the mesh to the nearest target surface"},
- {MOD_SHRINKWRAP_PROJECT,
- "PROJECT",
- 0,
- "Project",
- "Shrink the mesh to the nearest target surface along a given axis"},
- {MOD_SHRINKWRAP_NEAREST_VERTEX,
- "NEAREST_VERTEX",
- 0,
- "Nearest Vertex",
- "Shrink the mesh to the nearest target vertex"},
- {MOD_SHRINKWRAP_TARGET_PROJECT,
- "TARGET_PROJECT",
- 0,
- "Target Normal Project",
- "Shrink the mesh to the nearest target surface "
- "along the interpolated vertex normals of the target"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem shrink_face_cull_items[] = {
- {0, "OFF", 0, "Off", "No culling"},
- {MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE,
- "FRONT",
- 0,
- "Front",
- "No projection when in front of the face"},
- {MOD_SHRINKWRAP_CULL_TARGET_BACKFACE,
- "BACK",
- 0,
- "Back",
- "No projection when behind the face"},
- {0, NULL, 0, NULL, NULL},
- };
-
srna = RNA_def_struct(brna, "ShrinkwrapModifier", "Modifier");
RNA_def_struct_ui_text(srna,
"Shrinkwrap Modifier",
@@ -4235,7 +4231,7 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
prop = RNA_def_property(srna, "wrap_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkType");
- RNA_def_property_enum_items(prop, shrink_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_type_items);
RNA_def_property_ui_text(prop, "Wrap Method", "");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
@@ -4248,7 +4244,7 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkOpts");
- RNA_def_property_enum_items(prop, shrink_face_cull_items);
+ RNA_def_property_enum_items(prop, rna_enum_shrinkwrap_face_cull_items);
RNA_def_property_enum_funcs(
prop, "rna_ShrinkwrapModifier_face_cull_get", "rna_ShrinkwrapModifier_face_cull_set", NULL);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index b19836a7f12..230133a8f9d 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -885,6 +885,8 @@ static void rna_def_nlatrack(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track");
+ rna_api_nlatrack_strips(brna, prop);
+
prop = RNA_def_boolean(srna,
"is_override_data",
false,
@@ -894,8 +896,6 @@ static void rna_def_nlatrack(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", NLATRACK_OVERRIDELIBRARY_LOCAL);
- rna_api_nlatrack_strips(brna, prop);
-
RNA_define_lib_overridable(true);
/* name property */
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index aef3823338b..df0271d81d5 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -39,6 +39,7 @@
#include "BKE_animsys.h"
#include "BKE_attribute.h"
#include "BKE_cryptomatte.h"
+#include "BKE_geometry_set.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_texture.h"
@@ -304,36 +305,68 @@ const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
};
const EnumPropertyItem rna_enum_node_float_compare_items[] = {
- {NODE_FLOAT_COMPARE_LESS_THAN,
+ {NODE_COMPARE_LESS_THAN,
"LESS_THAN",
0,
"Less Than",
"True when the first input is smaller than second input"},
- {NODE_FLOAT_COMPARE_LESS_EQUAL,
+ {NODE_COMPARE_LESS_EQUAL,
"LESS_EQUAL",
0,
"Less Than or Equal",
"True when the first input is smaller than the second input or equal"},
- {NODE_FLOAT_COMPARE_GREATER_THAN,
+ {NODE_COMPARE_GREATER_THAN,
"GREATER_THAN",
0,
"Greater Than",
"True when the first input is greater than the second input"},
- {NODE_FLOAT_COMPARE_GREATER_EQUAL,
+ {NODE_COMPARE_GREATER_EQUAL,
"GREATER_EQUAL",
0,
"Greater Than or Equal",
"True when the first input is greater than the second input or equal"},
- {NODE_FLOAT_COMPARE_EQUAL,
- "EQUAL",
+ {NODE_COMPARE_EQUAL, "EQUAL", 0, "Equal", "True when both inputs are approximately equal"},
+ {NODE_COMPARE_NOT_EQUAL,
+ "NOT_EQUAL",
+ 0,
+ "Not Equal",
+ "True when both inputs are not approximately equal"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_node_compare_operation_items[] = {
+ {NODE_COMPARE_LESS_THAN,
+ "LESS_THAN",
+ 0,
+ "Less Than",
+ "True when the first input is smaller than second input"},
+ {NODE_COMPARE_LESS_EQUAL,
+ "LESS_EQUAL",
+ 0,
+ "Less Than or Equal",
+ "True when the first input is smaller than the second input or equal"},
+ {NODE_COMPARE_GREATER_THAN,
+ "GREATER_THAN",
0,
- "Equal",
- "True when both inputs are approximately equal"},
- {NODE_FLOAT_COMPARE_NOT_EQUAL,
+ "Greater Than",
+ "True when the first input is greater than the second input"},
+ {NODE_COMPARE_GREATER_EQUAL,
+ "GREATER_EQUAL",
+ 0,
+ "Greater Than or Equal",
+ "True when the first input is greater than the second input or equal"},
+ {NODE_COMPARE_EQUAL, "EQUAL", 0, "Equal", "True when both inputs are approximately equal"},
+ {NODE_COMPARE_NOT_EQUAL,
"NOT_EQUAL",
0,
"Not Equal",
"True when both inputs are not approximately equal"},
+ {NODE_COMPARE_COLOR_BRIGHTER,
+ "BRIGHTER",
+ 0,
+ "Brighter",
+ "True when the first input is brighter"},
+ {NODE_COMPARE_COLOR_DARKER, "DARKER", 0, "Darker", "True when the first input is darker"},
{0, NULL, 0, NULL, NULL},
};
@@ -1235,10 +1268,15 @@ static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
ntreeTexCheckCyclics(ntree);
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ Main *bmain = CTX_data_main(C);
+ ntreeUpdateTree(bmain, ntree);
nodeUpdate(ntree, node);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
+ if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ DEG_relations_tag_update(bmain);
+ }
+
return node;
}
@@ -1853,7 +1891,7 @@ static void rna_Node_draw_buttons_ext(struct uiLayout *layout, bContext *C, Poin
RNA_parameter_list_free(&list);
}
-static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int maxlen)
+static void rna_Node_draw_label(const bNodeTree *ntree, const bNode *node, char *label, int maxlen)
{
extern FunctionRNA rna_Node_draw_label_func;
@@ -1865,7 +1903,7 @@ static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int
func = &rna_Node_draw_label_func; /* RNA_struct_find_function(&ptr, "draw_label"); */
- RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
+ RNA_pointer_create((ID *)&ntree->id, &RNA_Node, (bNode *)node, &ptr);
RNA_parameter_list_create(&list, &ptr, func);
node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
@@ -2069,10 +2107,76 @@ static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSE
return itemf_function_check(node_socket_data_type_items, switch_type_supported);
}
+static bool compare_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR, SOCK_STRING, SOCK_RGBA);
+}
+
+static bool compare_main_operation_supported(const EnumPropertyItem *item)
+{
+ return !ELEM(item->value, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER);
+}
+
+static bool compare_rgba_operation_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value,
+ NODE_COMPARE_EQUAL,
+ NODE_COMPARE_NOT_EQUAL,
+ NODE_COMPARE_COLOR_BRIGHTER,
+ NODE_COMPARE_COLOR_DARKER);
+}
+
+static bool compare_string_operation_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL);
+}
+
+static bool compare_other_operation_supported(const EnumPropertyItem *UNUSED(item))
+{
+ return false;
+}
+
+static const EnumPropertyItem *rna_FunctionNodeCompare_type_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(node_socket_data_type_items, compare_type_supported);
+}
+
+static const EnumPropertyItem *rna_FunctionNodeCompare_operation_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ bNode *node = ptr->data;
+ NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+
+ if (ELEM(data->data_type, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR)) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_main_operation_supported);
+ }
+ else if (data->data_type == SOCK_STRING) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_string_operation_supported);
+ }
+ else if (data->data_type == SOCK_RGBA) {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_rgba_operation_supported);
+ }
+ else {
+ return itemf_function_check(rna_enum_node_compare_operation_items,
+ compare_other_operation_supported);
+ }
+}
+
static bool attribute_clamp_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR);
}
+
static const EnumPropertyItem *rna_GeometryNodeAttributeClamp_type_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -2149,6 +2253,30 @@ static void rna_GeometryNodeAttributeRandomize_data_type_update(Main *bmain,
rna_Node_socket_update(bmain, scene, ptr);
}
+static void rna_GeometryNodeCompare_data_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+ NodeFunctionCompare *node_storage = (NodeFunctionCompare *)node->storage;
+
+ if (node_storage->data_type == SOCK_RGBA && !ELEM(node_storage->operation,
+ NODE_COMPARE_EQUAL,
+ NODE_COMPARE_NOT_EQUAL,
+ NODE_COMPARE_COLOR_BRIGHTER,
+ NODE_COMPARE_COLOR_DARKER)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+ else if (node_storage->data_type == SOCK_STRING &&
+ !ELEM(node_storage->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+ else if (node_storage->data_type != SOCK_RGBA &&
+ ELEM(node_storage->operation, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) {
+ node_storage->operation = NODE_COMPARE_EQUAL;
+ }
+
+ rna_Node_socket_update(bmain, scene, ptr);
+}
+
static bool attribute_convert_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value,
@@ -3036,8 +3164,11 @@ static void rna_NodeSocketInterface_register_properties(bNodeTree *ntree,
RNA_parameter_list_free(&list);
}
-static void rna_NodeSocketInterface_init_socket(
- bNodeTree *ntree, bNodeSocket *stemp, bNode *node, bNodeSocket *sock, const char *data_path)
+static void rna_NodeSocketInterface_init_socket(bNodeTree *ntree,
+ const bNodeSocket *interface_socket,
+ bNode *node,
+ bNodeSocket *sock,
+ const char *data_path)
{
extern FunctionRNA rna_NodeSocketInterface_init_socket_func;
@@ -3045,11 +3176,11 @@ static void rna_NodeSocketInterface_init_socket(
ParameterList list;
FunctionRNA *func;
- if (!stemp->typeinfo) {
+ if (!interface_socket->typeinfo) {
return;
}
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, (bNodeSocket *)interface_socket, &ptr);
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr);
// RNA_struct_find_function(&ptr, "init_socket");
@@ -3059,13 +3190,13 @@ static void rna_NodeSocketInterface_init_socket(
RNA_parameter_set_lookup(&list, "node", &node_ptr);
RNA_parameter_set_lookup(&list, "socket", &sock_ptr);
RNA_parameter_set_lookup(&list, "data_path", &data_path);
- stemp->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
+ interface_socket->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
- bNodeSocket *stemp,
+ bNodeSocket *interface_socket,
bNode *node,
bNodeSocket *sock)
{
@@ -3075,11 +3206,11 @@ static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
ParameterList list;
FunctionRNA *func;
- if (!stemp->typeinfo) {
+ if (!interface_socket->typeinfo) {
return;
}
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, stemp, &ptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocketInterface, interface_socket, &ptr);
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sock_ptr);
// RNA_struct_find_function(&ptr, "from_socket");
@@ -3088,7 +3219,7 @@ static void rna_NodeSocketInterface_from_socket(bNodeTree *ntree,
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "node", &node_ptr);
RNA_parameter_set_lookup(&list, "socket", &sock_ptr);
- stemp->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
+ interface_socket->typeinfo->ext_interface.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -4823,18 +4954,32 @@ static void def_clamp(StructRNA *srna)
static void def_map_range(StructRNA *srna)
{
+ static const EnumPropertyItem rna_enum_data_type_items[] = {
+ {CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"},
+ {CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeMapRange", "storage");
+
PropertyRNA *prop;
prop = RNA_def_property(srna, "clamp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
+ RNA_def_property_boolean_sdna(prop, NULL, "clamp", 1);
RNA_def_property_ui_text(prop, "Clamp", "Clamp the result to the target range [To Min, To Max]");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "interpolation_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_sdna(prop, NULL, "interpolation_type");
RNA_def_property_enum_items(prop, rna_enum_node_map_range_items);
RNA_def_property_ui_text(prop, "Interpolation Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_type");
+ RNA_def_property_enum_items(prop, rna_enum_data_type_items);
+ RNA_def_property_ui_text(prop, "Data Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_math(StructRNA *srna)
@@ -4864,15 +5009,57 @@ static void def_boolean_math(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_float_compare(StructRNA *srna)
+static void def_compare(StructRNA *srna)
{
+
+ static const EnumPropertyItem mode_items[] = {
+ {NODE_COMPARE_MODE_ELEMENT,
+ "ELEMENT",
+ 0,
+ "Element-Wise",
+ "Compare each element of the input vectors"},
+ {NODE_COMPARE_MODE_LENGTH, "LENGTH", 0, "Length", "Compare the length of the input vectors"},
+ {NODE_COMPARE_MODE_AVERAGE,
+ "AVERAGE",
+ 0,
+ "Average",
+ "Compare the average of the input vectors elements"},
+ {NODE_COMPARE_MODE_DOT_PRODUCT,
+ "DOT_PRODUCT",
+ 0,
+ "Dot Product",
+ "Compare the dot products of the input vectors"},
+ {NODE_COMPARE_MODE_DIRECTION,
+ "DIRECTION",
+ 0,
+ "Direction",
+ "Compare the direction of the input vectors"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
+ RNA_def_struct_sdna_from(srna, "NodeFunctionCompare", "storage");
+
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeCompare_operation_itemf");
+ RNA_def_property_enum_items(prop, rna_enum_node_compare_operation_items);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_EQUAL);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_FunctionNodeCompare_type_itemf");
+ RNA_def_property_enum_items(prop, node_socket_data_type_items);
+ RNA_def_property_enum_default(prop, SOCK_FLOAT);
+ RNA_def_property_ui_text(prop, "Input Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNodeCompare_data_type_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_MODE_ELEMENT);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_float_to_int(StructRNA *srna)
@@ -9166,6 +9353,16 @@ static void def_geo_boolean(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_attribute_domain_size(StructRNA *srna)
+{
+ PropertyRNA *prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_geometry_component_type_items);
+ RNA_def_property_enum_default(prop, GEO_COMPONENT_TYPE_MESH);
+ RNA_def_property_ui_text(prop, "Component", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_primitive_bezier_segment(StructRNA *srna)
{
static const EnumPropertyItem mode_items[] = {
@@ -9578,7 +9775,7 @@ static void def_geo_attribute_attribute_compare(StructRNA *srna)
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
- RNA_def_property_enum_default(prop, NODE_FLOAT_COMPARE_GREATER_THAN);
+ RNA_def_property_enum_default(prop, NODE_COMPARE_GREATER_THAN);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
@@ -11092,6 +11289,17 @@ static void def_geo_viewer(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
}
+static void def_geo_realize_instances(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "legacy_behavior", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR);
+ RNA_def_property_ui_text(
+ prop, "Legacy Behavior", "Behave like before instance attributes existed");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 87173adc38f..76bfea00a79 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -869,7 +869,6 @@ static void rna_PoseChannel_custom_shape_transform_set(PointerRNA *ptr,
#else
-/* common properties for Action/Bone Groups - related to color */
void rna_def_actionbone_group_common(StructRNA *srna, int update_flag, const char *update_cb)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index e5009305fe5..285f6365ea1 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -1941,6 +1941,8 @@ int rna_property_override_diff_default(Main *bmain,
idx_a - 1);
# endif
op = NULL;
+
+ equals = false;
}
else if (is_id || is_valid_for_diffing) {
if (equals || do_create) {
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index c69a69290f9..5f1d9c5a5ce 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3425,7 +3425,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop,
"Cycle-Aware Keying",
"For channels with cyclic extrapolation, keyframe insertion is automatically "
- "remapped inside the cycle time range, and keeps ends in sync");
+ "remapped inside the cycle time range, and keeps ends in sync. Curves newly added to "
+ "actions with a Manual Frame Range and Cyclic Animation are automatically made cyclic");
/* Keyframing */
prop = RNA_def_property(srna, "keyframe_type", PROP_ENUM, PROP_NONE);
@@ -5582,7 +5583,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_MPEG2, "MPEG2", 0, "MPEG-2", ""},
{FFMPEG_MPEG4, "MPEG4", 0, "MPEG-4", ""},
{FFMPEG_AVI, "AVI", 0, "AVI", ""},
- {FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""},
+ {FFMPEG_MOV, "QUICKTIME", 0, "QuickTime", ""},
{FFMPEG_DV, "DV", 0, "DV", ""},
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index f92043995dd..9be66a6553b 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2272,7 +2272,8 @@ static void rna_def_filter_video(StructRNA *srna)
prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_REVERSE_FRAMES);
RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse frame order");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
+ RNA_def_property_update(
+ prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "color_multiply", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "mul");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index e7bcd387eaf..16e9a6208fb 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -73,6 +73,30 @@
#include "RNA_enum_types.h"
+const EnumPropertyItem rna_enum_geometry_component_type_items[] = {
+ {GEO_COMPONENT_TYPE_MESH,
+ "MESH",
+ ICON_MESH_DATA,
+ "Mesh",
+ "Mesh component containing point, corner, edge and face data"},
+ {GEO_COMPONENT_TYPE_POINT_CLOUD,
+ "POINTCLOUD",
+ ICON_POINTCLOUD_DATA,
+ "Point Cloud",
+ "Point cloud component containing only point data"},
+ {GEO_COMPONENT_TYPE_CURVE,
+ "CURVE",
+ ICON_CURVE_DATA,
+ "Curve",
+ "Curve component containing spline and control point data"},
+ {GEO_COMPONENT_TYPE_INSTANCES,
+ "INSTANCES",
+ ICON_EMPTY_AXIS,
+ "Instances",
+ "Instances of objects or collections"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_space_type_items[] = {
/* empty must be here for python, is skipped for UI */
{SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""},
@@ -7110,6 +7134,18 @@ static void rna_def_space_node_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Show Wire Colors", "Color node links based on their connected sockets");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
+ prop = RNA_def_property(srna, "show_timing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_TIMINGS);
+ RNA_def_property_boolean_default(prop, false);
+ RNA_def_property_ui_text(prop, "Show Timing", "Display each node's last execution time");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
+ prop = RNA_def_property(srna, "show_context_path", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_PATH);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Show Tree Path", "Display breadcrumbs for the editor's context");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
}
static void rna_def_space_node(BlenderRNA *brna)
@@ -7826,30 +7862,6 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
PropertyRNA *prop;
StructRNA *srna;
- static const EnumPropertyItem geometry_component_type_items[] = {
- {GEO_COMPONENT_TYPE_MESH,
- "MESH",
- ICON_MESH_DATA,
- "Mesh",
- "Mesh component containing point, corner, edge and face data"},
- {GEO_COMPONENT_TYPE_POINT_CLOUD,
- "POINTCLOUD",
- ICON_POINTCLOUD_DATA,
- "Point Cloud",
- "Point cloud component containing only point data"},
- {GEO_COMPONENT_TYPE_CURVE,
- "CURVE",
- ICON_CURVE_DATA,
- "Curve",
- "Curve component containing spline and control point data"},
- {GEO_COMPONENT_TYPE_INSTANCES,
- "INSTANCES",
- ICON_EMPTY_AXIS,
- "Instances",
- "Instances of objects or collections"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem object_eval_state_items[] = {
{SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED,
"EVALUATED",
@@ -7908,7 +7920,7 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
prop = RNA_def_property(srna, "geometry_component_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, geometry_component_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_geometry_component_type_items);
RNA_def_property_ui_text(
prop, "Geometry Component", "Part of the geometry to display data from");
RNA_def_property_update(prop,
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index 83c1efd55bc..0920fe6679a 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -84,8 +84,8 @@ void RNA_api_texture(StructRNA *srna)
NULL,
-FLT_MAX,
FLT_MAX,
- "The result of the texture where (x,y,z,w) are (red, green, blue, intensity). For greyscale "
- "textures, often intensity only will be used",
+ "The result of the texture where (x,y,z,w) are (red, green, blue, intensity). "
+ "For grayscale textures, often intensity only will be used",
NULL,
-1e4,
1e4);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 1cb1397a0ed..8c128292fd7 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -142,9 +142,10 @@ static const EnumPropertyItem event_ndof_type_items[] = {
};
#endif /* RNA_RUNTIME */
-/* not returned: CAPSLOCKKEY, UNKNOWNKEY */
const EnumPropertyItem rna_enum_event_type_items[] = {
- /* Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names. */
+ /* - Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names.
+ * - Intentionally excluded: #CAPSLOCKKEY, #UNKNOWNKEY.
+ */
{0, "NONE", 0, "", ""},
{LEFTMOUSE, "LEFTMOUSE", 0, "Left Mouse", "LMB"},
{MIDDLEMOUSE, "MIDDLEMOUSE", 0, "Middle Mouse", "MMB"},
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index d9b9fa96d04..c30beaf001a 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../depsgraph
../editors/include
../functions
+ ../geometry
../makesdna
../makesrna
../nodes
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index f36cb7ded9c..2a0a7a02472 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -91,6 +91,10 @@ extern ModifierTypeInfo modifierType_VolumeDisplace;
extern ModifierTypeInfo modifierType_VolumeToMesh;
/* MOD_util.c */
+
+/**
+ * Only called by `BKE_modifier.h/modifier.c`
+ */
void modifier_type_init(ModifierTypeInfo *types[]);
#ifdef __cplusplus
diff --git a/source/blender/modifiers/MOD_nodes.h b/source/blender/modifiers/MOD_nodes.h
index 907dbe9c5f4..1105925162c 100644
--- a/source/blender/modifiers/MOD_nodes.h
+++ b/source/blender/modifiers/MOD_nodes.h
@@ -24,6 +24,11 @@ struct Object;
extern "C" {
#endif
+/**
+ * Rebuild the list of properties based on the sockets exposed as the modifier's node group
+ * inputs. If any properties correspond to the old properties by name and type, carry over
+ * the values.
+ */
void MOD_nodes_update_interface(struct Object *object, struct NodesModifierData *nmd);
void MOD_nodes_init(struct Main *bmain, struct NodesModifierData *nmd);
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index aae6d257766..20dbb299767 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -167,7 +167,7 @@ static void deformVertsEM(ModifierData *md,
int defgrp_index = -1;
if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') {
- defgrp_index = BKE_id_defgroup_name_index(&mesh->id, cmd->name);
+ defgrp_index = BKE_object_defgroup_name_index(ctx->object, cmd->name);
if (defgrp_index != -1) {
use_dverts = true;
}
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 7fd90c71c9f..bbac6589577 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -84,14 +84,17 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, Object *ob, Mesh *mesh)
{
Mesh *result = mesh;
+ const bool use_correct_order_on_merge = mmd->use_correct_order_on_merge;
/* check which axes have been toggled and mirror accordingly */
if (mmd->flag & MOD_MIR_AXIS_X) {
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 0);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 0, use_correct_order_on_merge);
}
if (mmd->flag & MOD_MIR_AXIS_Y) {
Mesh *tmp = result;
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 1);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 1, use_correct_order_on_merge);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
@@ -99,7 +102,8 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, Object *ob, Mesh
}
if (mmd->flag & MOD_MIR_AXIS_Z) {
Mesh *tmp = result;
- result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(mmd, ob, result, 2);
+ result = BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(
+ mmd, ob, result, 2, use_correct_order_on_merge);
if (tmp != mesh) {
/* free intermediate results */
BKE_id_free(NULL, tmp);
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index c1cdfa43920..ec6cbeb43bf 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -98,6 +98,7 @@
#include "NOD_node_declaration.hh"
#include "FN_field.hh"
+#include "FN_field_cpp_type.hh"
#include "FN_multi_function.hh"
using blender::Array;
@@ -113,9 +114,11 @@ using blender::StringRef;
using blender::StringRefNull;
using blender::Vector;
using blender::bke::OutputAttribute;
+using blender::fn::Field;
using blender::fn::GField;
using blender::fn::GMutablePointer;
using blender::fn::GPointer;
+using blender::fn::ValueOrField;
using blender::nodes::FieldInferencingInterface;
using blender::nodes::GeoNodeExecParams;
using blender::nodes::InputSocketFieldType;
@@ -265,6 +268,39 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
+static bool check_tree_for_time_node(const bNodeTree &tree,
+ Set<const bNodeTree *> &r_checked_trees)
+{
+ if (!r_checked_trees.add(&tree)) {
+ return false;
+ }
+ LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
+ if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ return true;
+ }
+ if (node->type == NODE_GROUP) {
+ const bNodeTree *sub_tree = reinterpret_cast<const bNodeTree *>(node->id);
+ if (sub_tree && check_tree_for_time_node(*sub_tree, r_checked_trees)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool dependsOnTime(struct Scene *UNUSED(scene),
+ ModifierData *md,
+ const int UNUSED(dag_eval_mode))
+{
+ const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ const bNodeTree *tree = nmd->node_group;
+ if (tree == nullptr) {
+ return false;
+ }
+ Set<const bNodeTree *> checked_trees;
+ return check_tree_for_time_node(*tree, checked_trees);
+}
+
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
@@ -491,35 +527,34 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
else if (property.type == IDP_DOUBLE) {
value = (float)IDP_Double(&property);
}
- new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float>(value);
break;
}
case SOCK_INT: {
int value = IDP_Int(&property);
- new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<int>(value);
break;
}
case SOCK_VECTOR: {
float3 value;
copy_v3_v3(value, (const float *)IDP_Array(&property));
- new (r_value) blender::fn::Field<float3>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float3>(value);
break;
}
case SOCK_RGBA: {
blender::ColorGeometry4f value;
copy_v4_v4((float *)value, (const float *)IDP_Array(&property));
- new (r_value) blender::fn::Field<ColorGeometry4f>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<ColorGeometry4f>(value);
break;
}
case SOCK_BOOLEAN: {
bool value = IDP_Int(&property) != 0;
- new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<bool>(value);
break;
}
case SOCK_STRING: {
std::string value = IDP_String(&property);
- new (r_value)
- blender::fn::Field<std::string>(blender::fn::make_constant_field(std::move(value)));
+ new (r_value) ValueOrField<std::string>(std::move(value));
break;
}
case SOCK_OBJECT: {
@@ -559,11 +594,6 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
}
}
-/**
- * Rebuild the list of properties based on the sockets exposed as the modifier's node group
- * inputs. If any properties correspond to the old properties by name and type, carry over
- * the values.
- */
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
{
if (nmd->node_group == nullptr) {
@@ -739,8 +769,13 @@ static void initialize_group_input(NodesModifierData &nmd,
if (use_attribute) {
const StringRef attribute_name{IDP_String(property_attribute_name)};
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
- attribute_name, *socket_type.get_base_cpp_type());
- new (r_value) blender::fn::GField(std::move(attribute_input), 0);
+ attribute_name, *socket_type.base_cpp_type);
+ GField attribute_field{std::move(attribute_input), 0};
+ const blender::fn::ValueOrFieldCPPType *cpp_type =
+ dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(
+ socket_type.geometry_nodes_cpp_type);
+ BLI_assert(cpp_type != nullptr);
+ cpp_type->construct_from_field(r_value, std::move(attribute_field));
}
else {
init_socket_cpp_value_from_property(
@@ -904,7 +939,11 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set,
if (attribute_name.is_empty()) {
return;
}
- const GField &field = *(const GField *)value.get();
+ const blender::fn::ValueOrFieldCPPType *cpp_type =
+ dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(value.type());
+ BLI_assert(cpp_type != nullptr);
+
+ const GField field = cpp_type->as_field(value.get());
const bNodeSocket *interface_socket = (bNodeSocket *)BLI_findlink(&nmd->node_group->outputs,
socket.index());
const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain;
@@ -963,7 +1002,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
/* Initialize remaining group inputs. */
for (const OutputSocketRef *socket : remaining_input_sockets) {
- const CPPType &cpp_type = *socket->typeinfo()->get_geometry_nodes_cpp_type();
+ const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type;
void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
initialize_group_input(*nmd, *socket, value_in);
group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
@@ -1584,7 +1623,7 @@ ModifierTypeInfo modifierType_Nodes = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ nullptr,
+ /* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ nullptr,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ foreachTexLink,
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index badd633f648..4e808120f4a 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -16,9 +16,10 @@
#include "MOD_nodes_evaluator.hh"
+#include "BKE_type_conversions.hh"
+
#include "NOD_geometry_exec.hh"
#include "NOD_socket_declarations.hh"
-#include "NOD_type_conversions.hh"
#include "DEG_depsgraph_query.h"
@@ -35,13 +36,17 @@
#include "BLI_task.hh"
#include "BLI_vector_set.hh"
+#include <chrono>
+
namespace blender::modifiers::geometry_nodes {
using fn::CPPType;
using fn::Field;
-using fn::FieldCPPType;
using fn::GField;
using fn::GValueMap;
+using fn::GVArray;
+using fn::ValueOrField;
+using fn::ValueOrFieldCPPType;
using nodes::GeoNodeExecParams;
using namespace fn::multi_function_types;
@@ -309,10 +314,10 @@ class LockedNode : NonCopyable, NonMovable {
static const CPPType *get_socket_cpp_type(const SocketRef &socket)
{
const bNodeSocketType *typeinfo = socket.typeinfo();
- if (typeinfo->get_geometry_nodes_cpp_type == nullptr) {
+ if (typeinfo->geometry_nodes_cpp_type == nullptr) {
return nullptr;
}
- const CPPType *type = typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType *type = typeinfo->geometry_nodes_cpp_type;
if (type == nullptr) {
return nullptr;
}
@@ -348,18 +353,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value)
GEO_NODE_CURVE_HANDLE_LEFT ?
"handle_left" :
"handle_right";
- new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>(side));
+ new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side));
return true;
}
- new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>("position"));
+ new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position"));
return true;
}
if (socket.typeinfo()->type == SOCK_INT) {
if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) {
- new (r_value) Field<int>(std::make_shared<bke::IDAttributeFieldInput>());
+ new (r_value)
+ ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>()));
return true;
}
- new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>());
+ new (r_value) ValueOrField<int>(Field<int>(std::make_shared<fn::IndexFieldInput>()));
return true;
}
}
@@ -381,14 +387,23 @@ static bool node_supports_laziness(const DNode node)
return node->typeinfo()->geometry_node_execute_supports_laziness;
}
+struct NodeTaskRunState {
+ /** The node that should be run on the same thread after the current node finished. */
+ DNode next_node_to_run;
+};
+
/** Implements the callbacks that might be called when a node is executed. */
class NodeParamsProvider : public nodes::GeoNodeExecParamsProvider {
private:
GeometryNodesEvaluator &evaluator_;
NodeState &node_state_;
+ NodeTaskRunState *run_state_;
public:
- NodeParamsProvider(GeometryNodesEvaluator &evaluator, DNode dnode, NodeState &node_state);
+ NodeParamsProvider(GeometryNodesEvaluator &evaluator,
+ DNode dnode,
+ NodeState &node_state,
+ NodeTaskRunState *run_state);
bool can_get_input(StringRef identifier) const override;
bool can_set_output(StringRef identifier) const override;
@@ -402,6 +417,8 @@ class NodeParamsProvider : public nodes::GeoNodeExecParamsProvider {
bool lazy_require_input(StringRef identifier) override;
bool lazy_output_is_required(StringRef identifier) const override;
+
+ void set_default_remaining_outputs() override;
};
class GeometryNodesEvaluator {
@@ -433,7 +450,7 @@ class GeometryNodesEvaluator {
TaskPool *task_pool_ = nullptr;
GeometryNodesEvaluationParams &params_;
- const blender::nodes::DataTypeConversions &conversions_;
+ const blender::bke::DataTypeConversions &conversions_;
friend NodeParamsProvider;
@@ -441,7 +458,7 @@ class GeometryNodesEvaluator {
GeometryNodesEvaluator(GeometryNodesEvaluationParams &params)
: outer_allocator_(params.allocator),
params_(params),
- conversions_(blender::nodes::get_implicit_type_conversions())
+ conversions_(blender::bke::get_implicit_type_conversions())
{
}
@@ -640,7 +657,7 @@ class GeometryNodesEvaluator {
value.destruct();
continue;
}
- this->forward_output(socket, value);
+ this->forward_output(socket, value, nullptr);
}
}
@@ -649,7 +666,7 @@ class GeometryNodesEvaluator {
for (const DInputSocket &socket : params_.output_sockets) {
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, nullptr, [&](LockedNode &locked_node) {
/* Setting an input as required will schedule any linked node. */
this->set_input_required(locked_node, socket);
});
@@ -657,7 +674,7 @@ class GeometryNodesEvaluator {
for (const DSocket socket : params_.force_compute_sockets) {
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, nullptr, [&](LockedNode &locked_node) {
if (socket->is_input()) {
this->set_input_required(locked_node, DInputSocket(socket));
}
@@ -702,12 +719,24 @@ class GeometryNodesEvaluator {
{
void *user_data = BLI_task_pool_user_data(task_pool);
GeometryNodesEvaluator &evaluator = *(GeometryNodesEvaluator *)user_data;
- const NodeWithState *node_with_state = (const NodeWithState *)task_data;
-
- evaluator.node_task_run(node_with_state->node, *node_with_state->state);
+ const NodeWithState *root_node_with_state = (const NodeWithState *)task_data;
+
+ /* First, the node provided by the task pool is executed. During the execution other nodes
+ * might be scheduled. One of those nodes is not added to the task pool but is executed in the
+ * loop below directly. This has two main benefits:
+ * - Fewer round trips through the task pool which add threading overhead.
+ * - Helps with cpu cache efficiency, because a thread is more likely to process data that it
+ * has processed shortly before.
+ */
+ DNode next_node_to_run = root_node_with_state->node;
+ while (next_node_to_run) {
+ NodeTaskRunState run_state;
+ evaluator.node_task_run(next_node_to_run, &run_state);
+ next_node_to_run = run_state.next_node_to_run;
+ }
}
- void node_task_run(const DNode node, NodeState &node_state)
+ void node_task_run(const DNode node, NodeTaskRunState *run_state)
{
/* These nodes are sometimes scheduled. We could also check for them in other places, but
* it's the easiest to do it here. */
@@ -715,21 +744,25 @@ class GeometryNodesEvaluator {
return;
}
- const bool do_execute_node = this->node_task_preprocessing(node, node_state);
+ NodeState &node_state = *node_states_.lookup_key_as(node).state;
+
+ const bool do_execute_node = this->node_task_preprocessing(node, node_state, run_state);
/* Only execute the node if all prerequisites are met. There has to be an output that is
* required and all required inputs have to be provided already. */
if (do_execute_node) {
- this->execute_node(node, node_state);
+ this->execute_node(node, node_state, run_state);
}
- this->node_task_postprocessing(node, node_state, do_execute_node);
+ this->node_task_postprocessing(node, node_state, do_execute_node, run_state);
}
- bool node_task_preprocessing(const DNode node, NodeState &node_state)
+ bool node_task_preprocessing(const DNode node,
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
{
bool do_execute_node = false;
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
BLI_assert(node_state.schedule_state == NodeScheduleState::Scheduled);
node_state.schedule_state = NodeScheduleState::Running;
@@ -888,7 +921,7 @@ class GeometryNodesEvaluator {
* Actually execute the node. All the required inputs are available and at least one output is
* required.
*/
- void execute_node(const DNode node, NodeState &node_state)
+ void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
const bNode &bnode = *node->bnode();
@@ -902,40 +935,49 @@ class GeometryNodesEvaluator {
/* Use the geometry node execute callback if it exists. */
if (bnode.typeinfo->geometry_node_execute != nullptr) {
- this->execute_geometry_node(node, node_state);
+ this->execute_geometry_node(node, node_state, run_state);
return;
}
/* Use the multi-function implementation if it exists. */
const nodes::NodeMultiFunctions::Item &fn_item = params_.mf_by_node->try_get(node);
if (fn_item.fn != nullptr) {
- this->execute_multi_function_node(node, fn_item, node_state);
+ this->execute_multi_function_node(node, fn_item, node_state, run_state);
return;
}
- this->execute_unknown_node(node, node_state);
+ this->execute_unknown_node(node, node_state, run_state);
}
- void execute_geometry_node(const DNode node, NodeState &node_state)
+ void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
const bNode &bnode = *node->bnode();
- NodeParamsProvider params_provider{*this, node, node_state};
+ NodeParamsProvider params_provider{*this, node, node_state, run_state};
GeoNodeExecParams params{params_provider};
if (node->idname().find("Legacy") != StringRef::not_found) {
params.error_message_add(geo_log::NodeWarningType::Legacy,
TIP_("Legacy node will be removed before Blender 4.0"));
}
+ using Clock = std::chrono::steady_clock;
+ Clock::time_point begin = Clock::now();
bnode.typeinfo->geometry_node_execute(params);
+ Clock::time_point end = Clock::now();
+ const std::chrono::microseconds duration =
+ std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
+ if (params_.geo_logger != nullptr) {
+ params_.geo_logger->local().log_execution_time(node, duration);
+ }
}
void execute_multi_function_node(const DNode node,
const nodes::NodeMultiFunctions::Item &fn_item,
- NodeState &node_state)
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
{
if (node->idname().find("Legacy") != StringRef::not_found) {
/* Create geometry nodes params just for creating an error message. */
- NodeParamsProvider params_provider{*this, node, node_state};
+ NodeParamsProvider params_provider{*this, node, node_state, run_state};
GeoNodeExecParams params{params_provider};
params.error_message_add(geo_log::NodeWarningType::Legacy,
TIP_("Legacy node will be removed before Blender 4.0"));
@@ -943,8 +985,9 @@ class GeometryNodesEvaluator {
LinearAllocator<> &allocator = local_allocators_.local();
- /* Prepare the inputs for the multi function. */
- Vector<GField> input_fields;
+ bool any_input_is_field = false;
+ Vector<const void *, 16> input_values;
+ Vector<const ValueOrFieldCPPType *, 16> input_types;
for (const int i : node->inputs().index_range()) {
const InputSocketRef &socket_ref = node->input(i);
if (!socket_ref.is_available()) {
@@ -955,7 +998,38 @@ class GeometryNodesEvaluator {
BLI_assert(input_state.was_ready_for_execution);
SingleInputValue &single_value = *input_state.value.single;
BLI_assert(single_value.value != nullptr);
- input_fields.append(std::move(*(GField *)single_value.value));
+ const ValueOrFieldCPPType &field_cpp_type = static_cast<const ValueOrFieldCPPType &>(
+ *input_state.type);
+ input_values.append(single_value.value);
+ input_types.append(&field_cpp_type);
+ if (field_cpp_type.is_field(single_value.value)) {
+ any_input_is_field = true;
+ }
+ }
+
+ if (any_input_is_field) {
+ this->execute_multi_function_node__field(
+ node, fn_item, node_state, allocator, input_values, input_types, run_state);
+ }
+ else {
+ this->execute_multi_function_node__value(
+ node, *fn_item.fn, node_state, allocator, input_values, input_types, run_state);
+ }
+ }
+
+ void execute_multi_function_node__field(const DNode node,
+ const nodes::NodeMultiFunctions::Item &fn_item,
+ NodeState &node_state,
+ LinearAllocator<> &allocator,
+ Span<const void *> input_values,
+ Span<const ValueOrFieldCPPType *> input_types,
+ NodeTaskRunState *run_state)
+ {
+ Vector<GField> input_fields;
+ for (const int i : input_values.index_range()) {
+ const void *input_value_or_field = input_values[i];
+ const ValueOrFieldCPPType &field_cpp_type = *input_types[i];
+ input_fields.append(field_cpp_type.as_field(input_value_or_field));
}
std::shared_ptr<fn::FieldOperation> operation;
@@ -966,7 +1040,6 @@ class GeometryNodesEvaluator {
operation = std::make_shared<fn::FieldOperation>(*fn_item.fn, std::move(input_fields));
}
- /* Forward outputs. */
int output_index = 0;
for (const int i : node->outputs().index_range()) {
const OutputSocketRef &socket_ref = node->output(i);
@@ -975,17 +1048,70 @@ class GeometryNodesEvaluator {
}
OutputState &output_state = node_state.outputs[i];
const DOutputSocket socket{node.context(), &socket_ref};
- const CPPType *cpp_type = get_socket_cpp_type(socket_ref);
+ const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>(
+ get_socket_cpp_type(socket_ref));
GField new_field{operation, output_index};
- new_field = fn::make_field_constant_if_possible(std::move(new_field));
- GField &field_to_forward = *allocator.construct<GField>(std::move(new_field)).release();
- this->forward_output(socket, {cpp_type, &field_to_forward});
+ void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment());
+ cpp_type->construct_from_field(buffer, std::move(new_field));
+ this->forward_output(socket, {cpp_type, buffer}, run_state);
output_state.has_been_computed = true;
output_index++;
}
}
- void execute_unknown_node(const DNode node, NodeState &node_state)
+ void execute_multi_function_node__value(const DNode node,
+ const MultiFunction &fn,
+ NodeState &node_state,
+ LinearAllocator<> &allocator,
+ Span<const void *> input_values,
+ Span<const ValueOrFieldCPPType *> input_types,
+ NodeTaskRunState *run_state)
+ {
+ MFParamsBuilder params{fn, 1};
+ for (const int i : input_values.index_range()) {
+ const void *input_value_or_field = input_values[i];
+ const ValueOrFieldCPPType &field_cpp_type = *input_types[i];
+ const CPPType &base_type = field_cpp_type.base_type();
+ const void *input_value = field_cpp_type.get_value_ptr(input_value_or_field);
+ params.add_readonly_single_input(GVArray::ForSingleRef(base_type, 1, input_value));
+ }
+
+ Vector<GMutablePointer, 16> output_buffers;
+ for (const int i : node->outputs().index_range()) {
+ const DOutputSocket socket = node.output(i);
+ if (!socket->is_available()) {
+ output_buffers.append({});
+ continue;
+ }
+ const ValueOrFieldCPPType *value_or_field_type = static_cast<const ValueOrFieldCPPType *>(
+ get_socket_cpp_type(socket));
+ const CPPType &base_type = value_or_field_type->base_type();
+ void *value_or_field_buffer = allocator.allocate(value_or_field_type->size(),
+ value_or_field_type->alignment());
+ value_or_field_type->default_construct(value_or_field_buffer);
+ void *value_buffer = value_or_field_type->get_value_ptr(value_or_field_buffer);
+ base_type.destruct(value_buffer);
+ params.add_uninitialized_single_output(GMutableSpan{base_type, value_buffer, 1});
+ output_buffers.append({value_or_field_type, value_or_field_buffer});
+ }
+
+ MFContextBuilder context;
+ fn.call(IndexRange(1), params, context);
+
+ for (const int i : output_buffers.index_range()) {
+ GMutablePointer buffer = output_buffers[i];
+ if (buffer.get() == nullptr) {
+ continue;
+ }
+ const DOutputSocket socket = node.output(i);
+ this->forward_output(socket, buffer, run_state);
+
+ OutputState &output_state = node_state.outputs[i];
+ output_state.has_been_computed = true;
+ }
+ }
+
+ void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
LinearAllocator<> &allocator = local_allocators_.local();
for (const OutputSocketRef *socket : node->outputs()) {
@@ -1002,13 +1128,16 @@ class GeometryNodesEvaluator {
output_state.has_been_computed = true;
void *buffer = allocator.allocate(type->size(), type->alignment());
this->construct_default_value(*type, buffer);
- this->forward_output({node.context(), socket}, {*type, buffer});
+ this->forward_output({node.context(), socket}, {*type, buffer}, run_state);
}
}
- void node_task_postprocessing(const DNode node, NodeState &node_state, bool was_executed)
+ void node_task_postprocessing(const DNode node,
+ NodeState &node_state,
+ bool was_executed,
+ NodeTaskRunState *run_state)
{
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
const bool node_has_finished = this->finish_node_if_possible(locked_node);
const bool reschedule_requested = node_state.schedule_state ==
NodeScheduleState::RunningAndRescheduled;
@@ -1089,10 +1218,9 @@ class GeometryNodesEvaluator {
/**
* Load the required input from the socket or trigger nodes to the left to compute the value.
- * When this function is called, the node will always be executed again eventually (either
- * immediately, or when all required inputs have been computed by other nodes).
+ * \return True when the node will be triggered by another node again when the value is computed.
*/
- void set_input_required(LockedNode &locked_node, const DInputSocket input_socket)
+ bool set_input_required(LockedNode &locked_node, const DInputSocket input_socket)
{
BLI_assert(locked_node.node == input_socket.node());
InputState &input_state = locked_node.node_state.inputs[input_socket->index()];
@@ -1100,19 +1228,16 @@ class GeometryNodesEvaluator {
/* Value set as unused cannot become used again. */
BLI_assert(input_state.usage != ValueUsage::Unused);
- if (input_state.usage == ValueUsage::Required) {
- /* The value is already required, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- /* Returning here also ensure that the code below is executed at most once per input. */
- return;
+ if (input_state.was_ready_for_execution) {
+ return false;
}
- input_state.usage = ValueUsage::Required;
- if (input_state.was_ready_for_execution) {
- /* The value was already ready, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- return;
+ if (input_state.usage == ValueUsage::Required) {
+ /* If the input was not ready for execution but is required, the node will be triggered again
+ * once the input has been computed. */
+ return true;
}
+ input_state.usage = ValueUsage::Required;
/* Count how many values still have to be added to this input until it is "complete". */
int missing_values = 0;
@@ -1127,9 +1252,7 @@ class GeometryNodesEvaluator {
}
}
if (missing_values == 0) {
- /* The input is fully available already, but the node might expect to be evaluated again. */
- this->schedule_node(locked_node);
- return;
+ return false;
}
/* Increase the total number of missing required inputs. This ensures that the node will be
* scheduled correctly when all inputs have been provided. */
@@ -1144,30 +1267,28 @@ class GeometryNodesEvaluator {
/* If there are no origin sockets, just load the value from the socket directly. */
this->load_unlinked_input_value(locked_node, input_socket, input_state, input_socket);
locked_node.node_state.missing_required_inputs -= 1;
- this->schedule_node(locked_node);
- return;
+ return false;
}
- bool will_be_triggered_by_other_node = false;
+ bool requested_from_other_node = false;
for (const DSocket &origin_socket : origin_sockets) {
if (origin_socket->is_input()) {
/* Load the value directly from the origin socket. In most cases this is an unlinked
* group input. */
this->load_unlinked_input_value(locked_node, input_socket, input_state, origin_socket);
locked_node.node_state.missing_required_inputs -= 1;
- this->schedule_node(locked_node);
}
else {
/* The value has not been computed yet, so when it will be forwarded by another node, this
* node will be triggered. */
- will_be_triggered_by_other_node = true;
-
+ requested_from_other_node = true;
locked_node.delayed_required_outputs.append(DOutputSocket(origin_socket));
}
}
/* If this node will be triggered by another node, we don't have to schedule it now. */
- if (!will_be_triggered_by_other_node) {
- this->schedule_node(locked_node);
+ if (requested_from_other_node) {
+ return true;
}
+ return false;
}
void set_input_unused(LockedNode &locked_node, const DInputSocket socket)
@@ -1203,13 +1324,13 @@ class GeometryNodesEvaluator {
});
}
- void send_output_required_notification(const DOutputSocket socket)
+ void send_output_required_notification(const DOutputSocket socket, NodeTaskRunState *run_state)
{
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
OutputState &output_state = node_state.outputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
if (output_state.output_usage == ValueUsage::Required) {
/* Output is marked as required already. So the node is scheduled already. */
return;
@@ -1221,13 +1342,13 @@ class GeometryNodesEvaluator {
});
}
- void send_output_unused_notification(const DOutputSocket socket)
+ void send_output_unused_notification(const DOutputSocket socket, NodeTaskRunState *run_state)
{
const DNode node = socket.node();
NodeState &node_state = this->get_node_state(node);
OutputState &output_state = node_state.outputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
output_state.potential_users -= 1;
if (output_state.potential_users == 0) {
/* The socket might be required even though the output is not used by other sockets. That
@@ -1253,8 +1374,11 @@ class GeometryNodesEvaluator {
/**
* Moves a newly computed value from an output socket to all the inputs that might need it.
+ * Takes ownership of the value and destructs if it is unused.
*/
- void forward_output(const DOutputSocket from_socket, GMutablePointer value_to_forward)
+ void forward_output(const DOutputSocket from_socket,
+ GMutablePointer value_to_forward,
+ NodeTaskRunState *run_state)
{
BLI_assert(value_to_forward.get() != nullptr);
@@ -1307,12 +1431,12 @@ class GeometryNodesEvaluator {
}
else {
/* The value has been converted. */
- this->add_value_to_input_socket(to_socket, from_socket, current_value);
+ this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state);
}
});
this->log_socket_value(log_original_value_sockets, value_to_forward);
this->forward_to_sockets_with_same_type(
- allocator, forward_original_value_sockets, value_to_forward, from_socket);
+ allocator, forward_original_value_sockets, value_to_forward, from_socket, run_state);
}
bool should_forward_to_socket(const DInputSocket socket)
@@ -1334,7 +1458,8 @@ class GeometryNodesEvaluator {
void forward_to_sockets_with_same_type(LinearAllocator<> &allocator,
Span<DInputSocket> to_sockets,
GMutablePointer value_to_forward,
- const DOutputSocket from_socket)
+ const DOutputSocket from_socket,
+ NodeTaskRunState *run_state)
{
if (to_sockets.is_empty()) {
/* Value is not used anymore, so it can be destructed. */
@@ -1343,7 +1468,7 @@ class GeometryNodesEvaluator {
else if (to_sockets.size() == 1) {
/* Value is only used by one input socket, no need to copy it. */
const DInputSocket to_socket = to_sockets[0];
- this->add_value_to_input_socket(to_socket, from_socket, value_to_forward);
+ this->add_value_to_input_socket(to_socket, from_socket, value_to_forward, run_state);
}
else {
/* Multiple inputs use the value, make a copy for every input except for one. */
@@ -1353,17 +1478,18 @@ class GeometryNodesEvaluator {
for (const DInputSocket &to_socket : to_sockets.drop_front(1)) {
void *buffer = allocator.allocate(type.size(), type.alignment());
type.copy_construct(value_to_forward.get(), buffer);
- this->add_value_to_input_socket(to_socket, from_socket, {type, buffer});
+ this->add_value_to_input_socket(to_socket, from_socket, {type, buffer}, run_state);
}
/* Forward the original value to one of the targets. */
const DInputSocket to_socket = to_sockets[0];
- this->add_value_to_input_socket(to_socket, from_socket, value_to_forward);
+ this->add_value_to_input_socket(to_socket, from_socket, value_to_forward, run_state);
}
}
void add_value_to_input_socket(const DInputSocket socket,
const DOutputSocket origin,
- GMutablePointer value)
+ GMutablePointer value,
+ NodeTaskRunState *run_state)
{
BLI_assert(socket->is_available());
@@ -1371,7 +1497,7 @@ class GeometryNodesEvaluator {
NodeState &node_state = this->get_node_state(node);
InputState &input_state = node_state.inputs[socket->index()];
- this->with_locked_node(node, node_state, [&](LockedNode &locked_node) {
+ this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) {
if (socket->is_multi_input_socket()) {
/* Add a new value to the multi-input. */
MultiInputValue &multi_value = *input_state.value.multi;
@@ -1398,6 +1524,14 @@ class GeometryNodesEvaluator {
});
}
+ /**
+ * Loads the value of a socket that is not computed by another node. Note that the socket may
+ * still be linked to e.g. a Group Input node, but the socket on the outside is not connected to
+ * anything.
+ *
+ * \param input_socket: The socket of the node that wants to use the value.
+ * \param origin_socket: The socket that we want to load the value from.
+ */
void load_unlinked_input_value(LockedNode &locked_node,
const DInputSocket input_socket,
InputState &input_state,
@@ -1417,7 +1551,15 @@ class GeometryNodesEvaluator {
else {
SingleInputValue &single_value = *input_state.value.single;
single_value.value = value.get();
- this->log_socket_value({input_socket}, value);
+ Vector<DSocket> sockets_to_log_to = {input_socket};
+ if (origin_socket != input_socket) {
+ /* This might log the socket value for the #origin_socket more than once, but this is
+ * handled by the logging system gracefully. */
+ sockets_to_log_to.append(origin_socket);
+ }
+ /* TODO: Log to the intermediate sockets between the group input and where the value is
+ * actually used as well. */
+ this->log_socket_value(sockets_to_log_to, value);
}
}
@@ -1466,19 +1608,28 @@ class GeometryNodesEvaluator {
from_type.copy_construct(from_value, to_value);
return;
}
-
- const FieldCPPType *from_field_type = dynamic_cast<const FieldCPPType *>(&from_type);
- const FieldCPPType *to_field_type = dynamic_cast<const FieldCPPType *>(&to_type);
+ const ValueOrFieldCPPType *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>(
+ &from_type);
+ const ValueOrFieldCPPType *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&to_type);
if (from_field_type != nullptr && to_field_type != nullptr) {
- const CPPType &from_base_type = from_field_type->field_type();
- const CPPType &to_base_type = to_field_type->field_type();
+ const CPPType &from_base_type = from_field_type->base_type();
+ const CPPType &to_base_type = to_field_type->base_type();
if (conversions_.is_convertible(from_base_type, to_base_type)) {
- const MultiFunction &fn = *conversions_.get_conversion_multi_function(
- MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
- const GField &from_field = *(const GField *)from_value;
- auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field});
- new (to_value) GField(std::move(operation), 0);
+ if (from_field_type->is_field(from_value)) {
+ const GField &from_field = *from_field_type->get_field_ptr(from_value);
+ const MultiFunction &fn = *conversions_.get_conversion_multi_function(
+ MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type));
+ auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field});
+ to_field_type->construct_from_field(to_value, GField(std::move(operation), 0));
+ }
+ else {
+ to_field_type->default_construct(to_value);
+ const void *from_value_ptr = from_field_type->get_value_ptr(from_value);
+ void *to_value_ptr = to_field_type->get_value_ptr(to_value);
+ conversions_.get_conversion_functions(from_base_type, to_base_type)
+ ->convert_single_to_initialized(from_value_ptr, to_value_ptr);
+ }
return;
}
}
@@ -1494,14 +1645,6 @@ class GeometryNodesEvaluator {
void construct_default_value(const CPPType &type, void *r_value)
{
- if (const FieldCPPType *field_cpp_type = dynamic_cast<const FieldCPPType *>(&type)) {
- const CPPType &base_type = field_cpp_type->field_type();
- auto constant_fn = std::make_unique<fn::CustomMF_GenericConstant>(
- base_type, base_type.default_value(), false);
- auto operation = std::make_shared<fn::FieldOperation>(std::move(constant_fn));
- new (r_value) GField(std::move(operation), 0);
- return;
- }
type.copy_construct(type.default_value(), r_value);
}
@@ -1533,10 +1676,21 @@ class GeometryNodesEvaluator {
params_.geo_logger->local().log_value_for_sockets(sockets, value);
}
+ void log_debug_message(DNode node, std::string message)
+ {
+ if (params_.geo_logger == nullptr) {
+ return;
+ }
+ params_.geo_logger->local().log_debug_message(node, std::move(message));
+ }
+
/* In most cases when `NodeState` is accessed, the node has to be locked first to avoid race
* conditions. */
template<typename Function>
- void with_locked_node(const DNode node, NodeState &node_state, const Function &function)
+ void with_locked_node(const DNode node,
+ NodeState &node_state,
+ NodeTaskRunState *run_state,
+ const Function &function)
{
LockedNode locked_node{node, node_state};
@@ -1549,21 +1703,32 @@ class GeometryNodesEvaluator {
/* Then send notifications to the other nodes after the node state is unlocked. This avoids
* locking two nodes at the same time on this thread and helps to prevent deadlocks. */
for (const DOutputSocket &socket : locked_node.delayed_required_outputs) {
- this->send_output_required_notification(socket);
+ this->send_output_required_notification(socket, run_state);
}
for (const DOutputSocket &socket : locked_node.delayed_unused_outputs) {
- this->send_output_unused_notification(socket);
- }
- for (const DNode &node : locked_node.delayed_scheduled_nodes) {
- this->add_node_to_task_pool(node);
+ this->send_output_unused_notification(socket, run_state);
+ }
+ for (const DNode &node_to_schedule : locked_node.delayed_scheduled_nodes) {
+ if (run_state != nullptr && !run_state->next_node_to_run) {
+ /* Execute the node on the same thread after the current node finished. */
+ /* Currently, this assumes that it is always best to run the first node that is scheduled
+ * on the same thread. That is usually correct, because the geometry socket which carries
+ * the most data usually comes first in nodes. */
+ run_state->next_node_to_run = node_to_schedule;
+ }
+ else {
+ /* Push the node to the task pool so that another thread can start working on it. */
+ this->add_node_to_task_pool(node_to_schedule);
+ }
}
}
};
NodeParamsProvider::NodeParamsProvider(GeometryNodesEvaluator &evaluator,
DNode dnode,
- NodeState &node_state)
- : evaluator_(evaluator), node_state_(node_state)
+ NodeState &node_state,
+ NodeTaskRunState *run_state)
+ : evaluator_(evaluator), node_state_(node_state), run_state_(run_state)
{
this->dnode = dnode;
this->self_object = evaluator.params_.self_object;
@@ -1671,7 +1836,7 @@ void NodeParamsProvider::set_output(StringRef identifier, GMutablePointer value)
OutputState &output_state = node_state_.outputs[socket->index()];
BLI_assert(!output_state.has_been_computed);
- evaluator_.forward_output(socket, value);
+ evaluator_.forward_output(socket, value, run_state_);
output_state.has_been_computed = true;
}
@@ -1685,8 +1850,12 @@ bool NodeParamsProvider::lazy_require_input(StringRef identifier)
if (input_state.was_ready_for_execution) {
return false;
}
- evaluator_.with_locked_node(this->dnode, node_state_, [&](LockedNode &locked_node) {
- evaluator_.set_input_required(locked_node, socket);
+ evaluator_.with_locked_node(this->dnode, node_state_, run_state_, [&](LockedNode &locked_node) {
+ if (!evaluator_.set_input_required(locked_node, socket)) {
+ /* Schedule the currently executed node again because the value is available now but was not
+ * ready for the current execution. */
+ evaluator_.schedule_node(locked_node);
+ }
});
return true;
}
@@ -1696,7 +1865,7 @@ void NodeParamsProvider::set_input_unused(StringRef identifier)
const DInputSocket socket = this->dnode.input_by_identifier(identifier);
BLI_assert(socket);
- evaluator_.with_locked_node(this->dnode, node_state_, [&](LockedNode &locked_node) {
+ evaluator_.with_locked_node(this->dnode, node_state_, run_state_, [&](LockedNode &locked_node) {
evaluator_.set_input_unused(locked_node, socket);
});
}
@@ -1726,6 +1895,29 @@ bool NodeParamsProvider::lazy_output_is_required(StringRef identifier) const
return output_state.output_usage_for_execution == ValueUsage::Required;
}
+void NodeParamsProvider::set_default_remaining_outputs()
+{
+ LinearAllocator<> &allocator = evaluator_.local_allocators_.local();
+
+ for (const int i : this->dnode->outputs().index_range()) {
+ OutputState &output_state = node_state_.outputs[i];
+ if (output_state.has_been_computed) {
+ continue;
+ }
+ if (output_state.output_usage_for_execution == ValueUsage::Unused) {
+ continue;
+ }
+
+ const DOutputSocket socket = this->dnode.output(i);
+ const CPPType *type = get_socket_cpp_type(socket);
+ BLI_assert(type != nullptr);
+ void *buffer = allocator.allocate(type->size(), type->alignment());
+ type->copy_construct(type->default_value(), buffer);
+ evaluator_.forward_output(socket, {type, buffer}, run_state_);
+ output_state.has_been_computed = true;
+ }
+}
+
void evaluate_geometry_nodes(GeometryNodesEvaluationParams &params)
{
GeometryNodesEvaluator evaluator{params};
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 54a508ff5e2..20d65b9d9f8 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -183,6 +183,7 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
/* -------------------------------------------------------------------- */
/** \name Main Solidify Function
* \{ */
+
/* NOLINTNEXTLINE: readability-function-size */
Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index d4aaefcfe05..997f5943060 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -74,6 +74,7 @@ static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3],
static float clamp_nonzero(const float value, const float epsilon)
{
BLI_assert(!(epsilon < 0.0f));
+ /* Return closest value with `abs(value) >= epsilon`. */
if (value < 0.0f) {
return min_ff(value, -epsilon);
}
@@ -171,15 +172,22 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
float(*poly_nors)[3] = NULL;
+ /* #ofs_front and #ofs_back are the offset from the original
+ * surface along the normal, where #oft_front is along the positive
+ * and #oft_back is along the negative normal. */
const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset;
const float ofs_back = ofs_front - smd->offset * smd->offset_fac;
- const float ofs_front_clamped = clamp_nonzero(smd->offset > 0 ? ofs_front : ofs_back, 1e-5f);
- const float ofs_back_clamped = clamp_nonzero(smd->offset > 0 ? ofs_back : ofs_front, 1e-5f);
+ /* #ofs_front_clamped and #ofs_back_clamped are the same as
+ * #ofs_front and #ofs_back, but never zero. */
+ const float ofs_front_clamped = clamp_nonzero(ofs_front, 1e-5f);
+ const float ofs_back_clamped = clamp_nonzero(ofs_back, 1e-5f);
const float offset_fac_vg = smd->offset_fac_vg;
const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
const float offset = fabsf(smd->offset) * smd->offset_clamp;
const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP;
- const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
+ /* #do_flip, flips the normals of the result. This is inverted if negative thickness
+ * is used, since simple solidify with negative thickness keeps the faces facing outside. */
+ const bool do_flip = ((smd->flag & MOD_SOLIDIFY_FLIP) != 0) == (smd->offset > 0);
const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM;
const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
0;
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
index 9937a2342c3..fc1f6d33b25 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.c
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -100,9 +100,6 @@ static void set_modifier_expand_flag(const bContext *UNUSED(C), Panel *panel, sh
/** \name Modifier Panel Layouts
* \{ */
-/**
- * Draw modifier error message.
- */
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
{
ModifierData *md = ptr->data;
@@ -132,14 +129,11 @@ PointerRNA *modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_
uiBlock *block = uiLayoutGetBlock(panel->layout);
UI_block_lock_set(block, ID_IS_LINKED((Object *)ptr->owner_id), ERROR_LIBDATA_MESSAGE);
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
return ptr;
}
-/**
- * Helper function for modifier layouts to draw vertex group settings.
- */
void modifier_vgroup_ui(uiLayout *layout,
PointerRNA *ptr,
PointerRNA *ob_ptr,
@@ -304,7 +298,7 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
ModifierData *md = (ModifierData *)ptr->data;
Object *ob = (Object *)ptr->owner_id;
- uiLayoutSetContextPointer(panel->layout, "modifier", ptr);
+ UI_panel_context_pointer_set(panel, "modifier", ptr);
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
Scene *scene = CTX_data_scene(C);
@@ -429,9 +423,6 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
/** \name Modifier Registration Helpers
* \{ */
-/**
- * Create a panel in the context's region
- */
PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
{
PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
@@ -458,12 +449,6 @@ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *modifier_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/modifiers/intern/MOD_ui_common.h b/source/blender/modifiers/intern/MOD_ui_common.h
index e7f801049b8..9662b181013 100644
--- a/source/blender/modifiers/intern/MOD_ui_common.h
+++ b/source/blender/modifiers/intern/MOD_ui_common.h
@@ -37,6 +37,9 @@ typedef void (*PanelDrawFn)(const bContext *, struct Panel *);
void modifier_panel_buttons(const struct bContext *C, struct Panel *panel);
+/**
+ * Helper function for modifier layouts to draw vertex group settings.
+ */
void modifier_vgroup_ui(struct uiLayout *layout,
struct PointerRNA *ptr,
struct PointerRNA *ob_ptr,
@@ -44,15 +47,27 @@ void modifier_vgroup_ui(struct uiLayout *layout,
const char *invert_vgroup_prop,
const char *text);
+/**
+ * Draw modifier error message.
+ */
void modifier_panel_end(struct uiLayout *layout, PointerRNA *ptr);
struct PointerRNA *modifier_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
struct PanelType *modifier_panel_register(struct ARegionType *region_type,
ModifierType type,
PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *modifier_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index d57e92b4b35..16ef65f7838 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -72,7 +72,6 @@ void MOD_init_texture(MappingInfoModifierData *dmd, const ModifierEvalContext *c
}
/* TODO: to be renamed to get_texture_coords once we are done with moving modifiers to Mesh. */
-/** \param cos: may be NULL, in which case we use directly mesh vertices' coordinates. */
void MOD_get_texture_coords(MappingInfoModifierData *dmd,
const ModifierEvalContext *UNUSED(ctx),
Object *ob,
@@ -182,7 +181,6 @@ void MOD_previous_vcos_store(ModifierData *md, const float (*vert_coords)[3])
/* lattice/mesh modifier too */
}
-/* returns a mesh if mesh == NULL, for deforming modifiers that need it */
Mesh *MOD_deform_mesh_eval_get(Object *ob,
struct BMEditMesh *em,
Mesh *mesh,
@@ -219,8 +217,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
if (use_orco) {
- CustomData_add_layer(
- &mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
+ BKE_mesh_orco_ensure(ob, mesh);
}
}
else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
@@ -289,7 +286,6 @@ void MOD_depsgraph_update_object_bone_relation(struct DepsNodeHandle *node,
}
}
-/* only called by BKE_modifier.h/modifier.c */
void modifier_type_init(ModifierTypeInfo *types[])
{
#define INIT_TYPE(typeName) (types[eModifierType_##typeName] = &modifierType_##typeName)
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index a3db848874e..a6fc2749e71 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -32,6 +32,9 @@ struct ModifierEvalContext;
struct Object;
void MOD_init_texture(struct MappingInfoModifierData *dmd, const struct ModifierEvalContext *ctx);
+/**
+ * \param cos: may be NULL, in which case we use directly mesh vertices' coordinates.
+ */
void MOD_get_texture_coords(struct MappingInfoModifierData *dmd,
const struct ModifierEvalContext *ctx,
struct Object *ob,
@@ -41,6 +44,9 @@ void MOD_get_texture_coords(struct MappingInfoModifierData *dmd,
void MOD_previous_vcos_store(struct ModifierData *md, const float (*vert_coords)[3]);
+/**
+ * \returns a mesh if mesh == NULL, for deforming modifiers that need it.
+ */
struct Mesh *MOD_deform_mesh_eval_get(struct Object *ob,
struct BMEditMesh *em,
struct Mesh *mesh,
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index e403051d1be..cd9e5162527 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -57,12 +57,6 @@
#include "MOD_weightvg_util.h"
#include "RE_texture.h" /* Texture masking. */
-/* Maps new_w weights in place, using either one of the predefined functions, or a custom curve.
- * Return values are in new_w.
- * If indices is not NULL, it must be a table of same length as org_w and new_w,
- * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
- * cmap might be NULL, in which case curve mapping mode will return unmodified data.
- */
void weightvg_do_map(
int num, float *new_w, short falloff_type, const bool do_invert, CurveMapping *cmap, RNG *rng)
{
@@ -125,13 +119,6 @@ void weightvg_do_map(
}
}
-/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
- * Return values are in org_w.
- * If indices is not NULL, it must be a table of same length as org_w and new_w,
- * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
- * XXX The standard "factor" value is assumed in [0.0, 1.0] range.
- * Else, weird results might appear.
- */
void weightvg_do_mask(const ModifierEvalContext *ctx,
const int num,
const int *indices,
@@ -267,12 +254,6 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
}
}
-/* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
- * If dws is not NULL, it must be an array of MDeformWeight pointers of same length as weights (and
- * defgrp_idx can then have any value).
- * If indices is not NULL, it must be an array of same length as weights, mapping to the real
- * vertex index (in case the weight array does not cover the whole vertices...).
- */
void weightvg_update_vg(MDeformVert *dvert,
int defgrp_idx,
MDeformWeight **dws,
@@ -340,8 +321,6 @@ void weightvg_update_vg(MDeformVert *dvert,
}
}
-/* Common vertex weight mask interface elements for the modifier panels.
- */
void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout)
{
PointerRNA mask_texture_ptr = RNA_pointer_get(ptr, "mask_texture");
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h
index 796603289ca..00aecd7342c 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.h
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.h
@@ -46,13 +46,21 @@ struct uiLayout;
* Util functions. *
**************************************/
-/* We cannot divide by zero (what a surprise...).
- * So if -MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR < weightf < MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR,
+/**
+ * We cannot divide by zero (what a surprise...).
+ * So if `-MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR < weightf < MOD_WEIGHTVGROUP_DIVMODE_ZEROFLOOR`,
* we clamp weightf to this value (or its negative version).
* Also used to avoid null power factor.
*/
#define MOD_WVG_ZEROFLOOR 1.0e-32f
+/**
+ * Maps new_w weights in place, using either one of the predefined functions, or a custom curve.
+ * Return values are in new_w.
+ * If indices is not NULL, it must be a table of same length as org_w and new_w,
+ * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
+ * cmap might be NULL, in which case curve mapping mode will return unmodified data.
+ */
void weightvg_do_map(int num,
float *new_w,
short falloff_type,
@@ -60,6 +68,14 @@ void weightvg_do_map(int num,
struct CurveMapping *cmap,
struct RNG *rng);
+/**
+ * Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
+ * Return values are in org_w.
+ * If indices is not NULL, it must be a table of same length as org_w and new_w,
+ * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
+ * XXX The standard "factor" value is assumed in [0.0, 1.0] range.
+ * Else, weird results might appear.
+ */
void weightvg_do_mask(const ModifierEvalContext *ctx,
const int num,
const int *indices,
@@ -78,6 +94,13 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
const char *tex_uvlayer_name,
const bool invert_vgroup_mask);
+/**
+ * Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
+ * If dws is not NULL, it must be an array of #MDeformWeight pointers of same length as weights
+ * (and defgrp_idx can then have any value).
+ * If indices is not NULL, it must be an array of same length as weights, mapping to the real
+ * vertex index (in case the weight array does not cover the whole vertices...).
+ */
void weightvg_update_vg(struct MDeformVert *dvert,
int defgrp_idx,
struct MDeformWeight **dws,
@@ -90,4 +113,7 @@ void weightvg_update_vg(struct MDeformVert *dvert,
const float rem_thresh,
const bool do_normalize);
+/**
+ * Common vertex weight mask interface elements for the modifier panels.
+ */
void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout);
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
index 503297d5985..f842bef3298 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -363,7 +363,9 @@ static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
uint max_len = wp->loop_end - wp->loop_start + 1;
BLI_assert(len <= max_len);
}
-#endif
+
+#endif /* USE_WELD_DEBUG */
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index e256ebcff56..5f61d13a3af 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -19,6 +19,7 @@
# ***** END GPL LICENSE BLOCK *****
add_subdirectory(geometry)
+add_subdirectory(shader)
set(INC
.
@@ -44,7 +45,6 @@ set(INC
../windowmanager
../../../intern/glew-mx
../../../intern/guardedalloc
- ../../../intern/sky/include
)
@@ -141,7 +141,7 @@ set(SRC
function/nodes/node_fn_align_euler_to_vector.cc
function/nodes/node_fn_boolean_math.cc
- function/nodes/node_fn_float_compare.cc
+ function/nodes/node_fn_compare.cc
function/nodes/node_fn_float_to_int.cc
function/nodes/node_fn_input_bool.cc
function/nodes/node_fn_input_color.cc
@@ -157,99 +157,6 @@ set(SRC
function/nodes/node_fn_value_to_string.cc
function/node_function_util.cc
- shader/nodes/node_shader_add_shader.c
- shader/nodes/node_shader_ambient_occlusion.c
- shader/nodes/node_shader_attribute.c
- shader/nodes/node_shader_background.c
- shader/nodes/node_shader_bevel.c
- shader/nodes/node_shader_blackbody.c
- shader/nodes/node_shader_brightness.c
- shader/nodes/node_shader_bsdf_anisotropic.c
- shader/nodes/node_shader_bsdf_diffuse.c
- shader/nodes/node_shader_bsdf_glass.c
- shader/nodes/node_shader_bsdf_glossy.c
- shader/nodes/node_shader_bsdf_hair.c
- shader/nodes/node_shader_bsdf_hair_principled.c
- shader/nodes/node_shader_bsdf_principled.c
- shader/nodes/node_shader_bsdf_refraction.c
- shader/nodes/node_shader_bsdf_toon.c
- shader/nodes/node_shader_bsdf_translucent.c
- shader/nodes/node_shader_bsdf_transparent.c
- shader/nodes/node_shader_bsdf_velvet.c
- shader/nodes/node_shader_bump.c
- shader/nodes/node_shader_camera.c
- shader/nodes/node_shader_clamp.cc
- shader/nodes/node_shader_common.c
- shader/nodes/node_shader_curves.cc
- shader/nodes/node_shader_displacement.c
- shader/nodes/node_shader_eevee_specular.c
- shader/nodes/node_shader_emission.c
- shader/nodes/node_shader_fresnel.c
- shader/nodes/node_shader_gamma.c
- shader/nodes/node_shader_geometry.c
- shader/nodes/node_shader_hair_info.c
- shader/nodes/node_shader_holdout.c
- shader/nodes/node_shader_hueSatVal.c
- shader/nodes/node_shader_ies_light.c
- shader/nodes/node_shader_invert.c
- shader/nodes/node_shader_layer_weight.c
- shader/nodes/node_shader_light_falloff.c
- shader/nodes/node_shader_light_path.c
- shader/nodes/node_shader_map_range.cc
- shader/nodes/node_shader_mapping.c
- shader/nodes/node_shader_math.cc
- shader/nodes/node_shader_mixRgb.cc
- shader/nodes/node_shader_mix_shader.c
- shader/nodes/node_shader_normal.c
- shader/nodes/node_shader_normal_map.c
- shader/nodes/node_shader_object_info.c
- shader/nodes/node_shader_output_aov.c
- shader/nodes/node_shader_output_light.c
- shader/nodes/node_shader_output_linestyle.c
- shader/nodes/node_shader_output_material.c
- shader/nodes/node_shader_output_world.c
- shader/nodes/node_shader_particle_info.c
- shader/nodes/node_shader_rgb.c
- shader/nodes/node_shader_script.c
- shader/nodes/node_shader_sepcombHSV.c
- shader/nodes/node_shader_sepcombRGB.cc
- shader/nodes/node_shader_sepcombXYZ.cc
- shader/nodes/node_shader_shaderToRgb.c
- shader/nodes/node_shader_squeeze.c
- shader/nodes/node_shader_subsurface_scattering.c
- shader/nodes/node_shader_tangent.c
- shader/nodes/node_shader_tex_brick.cc
- shader/nodes/node_shader_tex_checker.cc
- shader/nodes/node_shader_tex_coord.c
- shader/nodes/node_shader_tex_environment.c
- shader/nodes/node_shader_tex_gradient.cc
- shader/nodes/node_shader_tex_image.cc
- shader/nodes/node_shader_tex_magic.cc
- shader/nodes/node_shader_tex_musgrave.cc
- shader/nodes/node_shader_tex_noise.cc
- shader/nodes/node_shader_tex_pointdensity.c
- shader/nodes/node_shader_tex_sky.c
- shader/nodes/node_shader_tex_voronoi.cc
- shader/nodes/node_shader_tex_wave.cc
- shader/nodes/node_shader_tex_white_noise.cc
- shader/nodes/node_shader_uvAlongStroke.c
- shader/nodes/node_shader_uvmap.c
- shader/nodes/node_shader_valToRgb.cc
- shader/nodes/node_shader_value.cc
- shader/nodes/node_shader_vectTransform.c
- shader/nodes/node_shader_vector_displacement.c
- shader/nodes/node_shader_vector_math.cc
- shader/nodes/node_shader_vector_rotate.cc
- shader/nodes/node_shader_vertex_color.c
- shader/nodes/node_shader_volume_absorption.c
- shader/nodes/node_shader_volume_info.c
- shader/nodes/node_shader_volume_principled.c
- shader/nodes/node_shader_volume_scatter.c
- shader/nodes/node_shader_wavelength.c
- shader/nodes/node_shader_wireframe.c
- shader/node_shader_tree.c
- shader/node_shader_util.c
-
texture/nodes/node_texture_at.c
texture/nodes/node_texture_bricks.c
texture/nodes/node_texture_checker.c
@@ -277,7 +184,6 @@ set(SRC
texture/node_texture_util.c
intern/derived_node_tree.cc
- intern/extern_implementations.cc
intern/geometry_nodes_eval_log.cc
intern/math_functions.cc
intern/node_common.cc
@@ -287,13 +193,12 @@ set(SRC
intern/node_multi_function.cc
intern/node_socket.cc
intern/node_socket_declarations.cc
+ intern/socket_search_link.cc
intern/node_tree_ref.cc
intern/node_util.c
- intern/type_conversions.cc
composite/node_composite_util.hh
function/node_function_util.hh
- shader/node_shader_util.h
texture/node_texture_util.h
NOD_common.h
@@ -310,10 +215,10 @@ set(SRC
NOD_shader.h
NOD_socket.h
NOD_socket_declarations.hh
+ NOD_socket_search_link.hh
NOD_socket_declarations_geometry.hh
NOD_static_types.h
NOD_texture.h
- NOD_type_conversions.hh
intern/node_common.h
intern/node_exec.h
intern/node_util.h
@@ -322,8 +227,8 @@ set(SRC
set(LIB
bf_bmesh
bf_functions
- bf_intern_sky
bf_nodes_geometry
+ bf_nodes_shader
)
if(WITH_BULLET)
diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h
index fa979bb4799..e488352170b 100644
--- a/source/blender/nodes/NOD_common.h
+++ b/source/blender/nodes/NOD_common.h
@@ -35,9 +35,11 @@ void register_node_type_reroute(void);
void register_node_type_group_input(void);
void register_node_type_group_output(void);
-/* internal functions for editor */
+/* Internal functions for editor. */
+
struct bNodeSocket *node_group_find_input_socket(struct bNode *groupnode, const char *identifier);
struct bNodeSocket *node_group_find_output_socket(struct bNode *groupnode, const char *identifier);
+/** Make sure all group node in ntree, which use ngroup, are sync'd. */
void node_group_update(struct bNodeTree *ntree, struct bNode *node);
struct bNodeSocket *node_group_input_find_socket(struct bNode *node, const char *identifier);
diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh
index 895f7ef6d5b..dc619deb5d2 100644
--- a/source/blender/nodes/NOD_derived_node_tree.hh
+++ b/source/blender/nodes/NOD_derived_node_tree.hh
@@ -72,8 +72,10 @@ class DTreeContext {
bool is_root() const;
};
-/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested
- * node group hierarchy. This type is small and can be passed around by value. */
+/**
+ * A (nullable) reference to a node and the context it is in. It is unique within an entire nested
+ * node group hierarchy. This type is small and can be passed around by value.
+ */
class DNode {
private:
const DTreeContext *context_ = nullptr;
@@ -100,11 +102,13 @@ class DNode {
DOutputSocket output_by_identifier(StringRef identifier) const;
};
-/* A (nullable) reference to a socket and the context it is in. It is unique within an entire
+/**
+ * A (nullable) reference to a socket and the context it is in. It is unique within an entire
* nested node group hierarchy. This type is small and can be passed around by value.
*
* A #DSocket can represent an input or an output socket. If the type of a socket is known at
- * compile time is preferable to use #DInputSocket or #DOutputSocket instead. */
+ * compile time is preferable to use #DInputSocket or #DOutputSocket instead.
+ */
class DSocket {
protected:
const DTreeContext *context_ = nullptr;
@@ -129,7 +133,7 @@ class DSocket {
DNode node() const;
};
-/* A (nullable) reference to an input socket and the context it is in. */
+/** A (nullable) reference to an input socket and the context it is in. */
class DInputSocket : public DSocket {
public:
DInputSocket() = default;
@@ -142,10 +146,15 @@ class DInputSocket : public DSocket {
DOutputSocket get_corresponding_group_node_output() const;
Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const;
+ /**
+ * Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Origin sockets are ones where a node gets its
+ * inputs from.
+ */
void foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const;
};
-/* A (nullable) reference to an output socket and the context it is in. */
+/** A (nullable) reference to an output socket and the context it is in. */
class DOutputSocket : public DSocket {
public:
DOutputSocket() = default;
@@ -166,6 +175,11 @@ class DOutputSocket : public DSocket {
using ForeachTargetSocketFn =
FunctionRef<void(DInputSocket, const TargetSocketPathInfo &path_info)>;
+ /**
+ * Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
+ * and node groups are handled by this function. Target sockets are on the nodes that use the
+ * value from this socket.
+ */
void foreach_target_socket(ForeachTargetSocketFn target_fn) const;
private:
@@ -180,16 +194,27 @@ class DerivedNodeTree {
VectorSet<const NodeTreeRef *> used_node_tree_refs_;
public:
+ /**
+ * Construct a new derived node tree for a given root node tree. The generated derived node tree
+ * does not own the used node tree refs (so that those can be used by others as well). The caller
+ * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
+ * derived node tree.
+ */
DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs);
~DerivedNodeTree();
const DTreeContext &root_context() const;
Span<const NodeTreeRef *> used_node_tree_refs() const;
+ /**
+ * \return True when there is a link cycle. Unavailable sockets are ignored.
+ */
bool has_link_cycles() const;
bool has_undefined_nodes_or_sockets() const;
+ /** Calls the given callback on all nodes in the (possibly nested) derived node tree. */
void foreach_node(FunctionRef<void(DNode)> callback) const;
+ /** Generates a graph in dot format. The generated graph has all node groups inlined. */
std::string to_dot() const;
private:
@@ -246,6 +271,7 @@ inline bool DTreeContext::is_root() const
{
return parent_context_ == nullptr;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -312,6 +338,7 @@ inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const
{
return {context_, &node_ref_->output_by_identifier(identifier)};
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -374,6 +401,7 @@ inline DNode DSocket::node() const
BLI_assert(socket_ref_ != nullptr);
return {context_, &socket_ref_->node()};
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -399,6 +427,7 @@ inline const InputSocketRef *DInputSocket::operator->() const
{
return (const InputSocketRef *)socket_ref_;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -424,6 +453,7 @@ inline const OutputSocketRef *DOutputSocket::operator->() const
{
return (const OutputSocketRef *)socket_ref_;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index 81f0667fe1c..be3998a916c 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -24,7 +24,7 @@ void register_node_type_fn_legacy_random_float(void);
void register_node_type_fn_align_euler_to_vector(void);
void register_node_type_fn_boolean_math(void);
-void register_node_type_fn_float_compare(void);
+void register_node_type_fn_compare(void);
void register_node_type_fn_float_to_int(void);
void register_node_type_fn_input_bool(void);
void register_node_type_fn_input_color(void);
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index ea3458af065..a0b8e237f19 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -16,12 +16,12 @@
#pragma once
+#include "BKE_node.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BKE_node.h"
-
extern struct bNodeTreeType *ntreeType_Geometry;
void register_node_tree_type_geo(void);
@@ -57,6 +57,7 @@ void register_node_type_geo_attribute_combine_xyz(void);
void register_node_type_geo_attribute_compare(void);
void register_node_type_geo_attribute_convert(void);
void register_node_type_geo_attribute_curve_map(void);
+void register_node_type_geo_attribute_domain_size(void);
void register_node_type_geo_attribute_fill(void);
void register_node_type_geo_attribute_map_range(void);
void register_node_type_geo_attribute_math(void);
@@ -75,7 +76,6 @@ void register_node_type_geo_curve_fill(void);
void register_node_type_geo_curve_fillet(void);
void register_node_type_geo_curve_handle_type_selection(void);
void register_node_type_geo_curve_length(void);
-void register_node_type_geo_curve_parameter(void);
void register_node_type_geo_curve_primitive_bezier_segment(void);
void register_node_type_geo_curve_primitive_circle(void);
void register_node_type_geo_curve_primitive_line(void);
@@ -88,13 +88,16 @@ void register_node_type_geo_curve_reverse(void);
void register_node_type_geo_curve_sample(void);
void register_node_type_geo_curve_set_handles(void);
void register_node_type_geo_curve_spline_type(void);
+void register_node_type_geo_curve_spline_parameter(void);
void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_curve_to_mesh(void);
void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_trim(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_distribute_points_on_faces(void);
+void register_node_type_geo_dual_mesh(void);
void register_node_type_geo_edge_split(void);
+void register_node_type_geo_geometry_to_instance(void);
void register_node_type_geo_image_texture(void);
void register_node_type_geo_input_curve_handles(void);
void register_node_type_geo_input_curve_tilt(void);
@@ -102,9 +105,16 @@ void register_node_type_geo_input_id(void);
void register_node_type_geo_input_index(void);
void register_node_type_geo_input_material_index(void);
void register_node_type_geo_input_material(void);
+void register_node_type_geo_input_mesh_edge_neighbors(void);
+void register_node_type_geo_input_mesh_edge_vertices(void);
+void register_node_type_geo_input_mesh_face_area(void);
+void register_node_type_geo_input_mesh_face_neighbors(void);
+void register_node_type_geo_input_mesh_island(void);
+void register_node_type_geo_input_mesh_vertex_neighbors(void);
void register_node_type_geo_input_normal(void);
void register_node_type_geo_input_position(void);
void register_node_type_geo_input_radius(void);
+void register_node_type_geo_input_scene_time(void);
void register_node_type_geo_input_shade_smooth(void);
void register_node_type_geo_input_spline_cyclic(void);
void register_node_type_geo_input_spline_length(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 700f32ee414..f225b3b94b2 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -28,6 +28,8 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_nodes_eval_log.hh"
+#include "GEO_realize_instances.hh"
+
struct Depsgraph;
struct ModifierData;
@@ -36,8 +38,8 @@ namespace blender::nodes {
using bke::AnonymousAttributeFieldInput;
using bke::AttributeFieldInput;
using bke::AttributeIDRef;
-using bke::geometry_set_realize_instances;
using bke::GeometryComponentFieldContext;
+using bke::GeometryFieldInput;
using bke::OutputAttribute;
using bke::OutputAttribute_Typed;
using bke::ReadAttributeLookup;
@@ -59,6 +61,7 @@ using fn::GVArray;
using fn::GVArray_GSpan;
using fn::GVMutableArray;
using fn::GVMutableArray_GSpan;
+using fn::ValueOrField;
using geometry_nodes_eval_log::NodeWarningType;
/**
@@ -117,6 +120,8 @@ class GeoNodeExecParamsProvider {
virtual bool output_is_required(StringRef identifier) const = 0;
virtual bool lazy_require_input(StringRef identifier) = 0;
virtual bool lazy_output_is_required(StringRef identifier) const = 0;
+
+ virtual void set_default_remaining_outputs() = 0;
};
class GeoNodeExecParams {
@@ -129,7 +134,7 @@ class GeoNodeExecParams {
}
template<typename T>
- static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> ||
+ static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> ||
std::is_same_v<T, int> ||
std::is_same_v<T, bool> ||
std::is_same_v<T, ColorGeometry4f> ||
@@ -157,9 +162,15 @@ class GeoNodeExecParams {
*/
template<typename T> T extract_input(StringRef identifier)
{
- if constexpr (is_stored_as_field_v<T>) {
- Field<T> field = this->extract_input<Field<T>>(identifier);
- return fn::evaluate_constant_field(field);
+ if constexpr (is_field_base_type_v<T>) {
+ ValueOrField<T> value_or_field = this->extract_input<ValueOrField<T>>(identifier);
+ return value_or_field.as_value();
+ }
+ else if constexpr (fn::is_field_v<T>) {
+ using BaseType = typename T::base_type;
+ ValueOrField<BaseType> value_or_field = this->extract_input<ValueOrField<BaseType>>(
+ identifier);
+ return value_or_field.as_field();
}
else {
#ifdef DEBUG
@@ -186,9 +197,9 @@ class GeoNodeExecParams {
Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier);
Vector<T> values;
for (GMutablePointer gvalue : gvalues) {
- if constexpr (is_stored_as_field_v<T>) {
- const Field<T> field = gvalue.relocate_out<Field<T>>();
- values.append(fn::evaluate_constant_field(field));
+ if constexpr (is_field_base_type_v<T>) {
+ const ValueOrField<T> value_or_field = gvalue.relocate_out<ValueOrField<T>>();
+ values.append(value_or_field.as_value());
}
else {
values.append(gvalue.relocate_out<T>());
@@ -200,11 +211,16 @@ class GeoNodeExecParams {
/**
* Get the input value for the input socket with the given identifier.
*/
- template<typename T> const T get_input(StringRef identifier) const
+ template<typename T> T get_input(StringRef identifier) const
{
- if constexpr (is_stored_as_field_v<T>) {
- const Field<T> &field = this->get_input<Field<T>>(identifier);
- return fn::evaluate_constant_field(field);
+ if constexpr (is_field_base_type_v<T>) {
+ ValueOrField<T> value_or_field = this->get_input<ValueOrField<T>>(identifier);
+ return value_or_field.as_value();
+ }
+ else if constexpr (fn::is_field_v<T>) {
+ using BaseType = typename T::base_type;
+ ValueOrField<BaseType> value_or_field = this->get_input<ValueOrField<BaseType>>(identifier);
+ return value_or_field.as_field();
}
else {
#ifdef DEBUG
@@ -226,9 +242,12 @@ class GeoNodeExecParams {
template<typename T> void set_output(StringRef identifier, T &&value)
{
using StoredT = std::decay_t<T>;
- if constexpr (is_stored_as_field_v<StoredT>) {
- this->set_output<Field<StoredT>>(identifier,
- fn::make_constant_field<StoredT>(std::forward<T>(value)));
+ if constexpr (is_field_base_type_v<StoredT>) {
+ this->set_output(identifier, ValueOrField<StoredT>(std::forward<T>(value)));
+ }
+ else if constexpr (fn::is_field_v<StoredT>) {
+ using BaseType = typename StoredT::base_type;
+ this->set_output(identifier, ValueOrField<BaseType>(std::forward<T>(value)));
}
else {
const CPPType &type = CPPType::get<StoredT>();
@@ -336,12 +355,19 @@ class GeoNodeExecParams {
const GeometryComponent &component,
const CustomDataType default_type) const;
+ /**
+ * If any of the corresponding input sockets are attributes instead of single values,
+ * use the highest priority attribute domain from among them.
+ * Otherwise return the default domain.
+ */
AttributeDomain get_highest_priority_input_domain(Span<std::string> names,
const GeometryComponent &component,
const AttributeDomain default_domain) const;
std::string attribute_producer_name() const;
+ void set_default_remaining_outputs();
+
private:
/* Utilities for detecting common errors at when using this class. */
void check_input_access(StringRef identifier, const CPPType *requested_type = nullptr) const;
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 2a118057a03..ac2c29b4ec2 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -41,6 +41,8 @@
#include "NOD_derived_node_tree.hh"
+#include <chrono>
+
struct SpaceNode;
struct SpaceSpreadsheet;
@@ -169,6 +171,16 @@ struct NodeWithWarning {
NodeWarning warning;
};
+struct NodeWithExecutionTime {
+ DNode node;
+ std::chrono::microseconds exec_time;
+};
+
+struct NodeWithDebugMessage {
+ DNode node;
+ std::string message;
+};
+
/** The same value can be referenced by multiple sockets when they are linked. */
struct ValueOfSockets {
Span<DSocket> sockets;
@@ -189,6 +201,8 @@ class LocalGeoLogger {
std::unique_ptr<LinearAllocator<>> allocator_;
Vector<ValueOfSockets> values_;
Vector<NodeWithWarning> node_warnings_;
+ Vector<NodeWithExecutionTime> node_exec_times_;
+ Vector<NodeWithDebugMessage> node_debug_messages_;
friend ModifierLog;
@@ -201,6 +215,12 @@ class LocalGeoLogger {
void log_value_for_sockets(Span<DSocket> sockets, GPointer value);
void log_multi_value_socket(DSocket socket, Span<GPointer> values);
void log_node_warning(DNode node, NodeWarningType type, std::string message);
+ void log_execution_time(DNode node, std::chrono::microseconds exec_time);
+ /**
+ * Log a message that will be displayed in the node editor next to the node.
+ * This should only be used for debugging purposes and not to display information to users.
+ */
+ void log_debug_message(DNode node, std::string message);
};
/** The root logger class. */
@@ -274,12 +294,15 @@ class NodeLog {
Vector<SocketLog> input_logs_;
Vector<SocketLog> output_logs_;
Vector<NodeWarning, 0> warnings_;
+ Vector<std::string, 0> debug_messages_;
+ std::chrono::microseconds exec_time_;
friend ModifierLog;
public:
const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const;
const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const;
+ void execution_time(std::chrono::microseconds exec_time);
Span<SocketLog> input_logs() const
{
@@ -296,6 +319,16 @@ class NodeLog {
return warnings_;
}
+ Span<std::string> debug_messages() const
+ {
+ return debug_messages_;
+ }
+
+ std::chrono::microseconds execution_time() const
+ {
+ return exec_time_;
+ }
+
Vector<const GeometryAttributeInfo *> lookup_available_attributes() const;
};
diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh
index 86ff8cab3e9..54abc754346 100644
--- a/source/blender/nodes/NOD_math_functions.hh
+++ b/source/blender/nodes/NOD_math_functions.hh
@@ -204,7 +204,7 @@ inline bool try_dispatch_float_math_fl_fl_fl_to_fl(const int operation, Callback
* This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature.
*/
template<typename Callback>
-inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation operation,
+inline bool try_dispatch_float_math_fl_fl_to_bool(const NodeCompareOperation operation,
Callback &&callback)
{
const FloatMathOperationInfo *info = get_float_compare_operation_info(operation);
@@ -219,13 +219,13 @@ inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation op
};
switch (operation) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
+ case NODE_COMPARE_LESS_THAN:
return dispatch([](float a, float b) { return a < b; });
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
+ case NODE_COMPARE_LESS_EQUAL:
return dispatch([](float a, float b) { return a <= b; });
- case NODE_FLOAT_COMPARE_GREATER_THAN:
+ case NODE_COMPARE_GREATER_THAN:
return dispatch([](float a, float b) { return a > b; });
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
+ case NODE_COMPARE_GREATER_EQUAL:
return dispatch([](float a, float b) { return a >= b; });
default:
return false;
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index 9b99026d6a7..af2130ec452 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <type_traits>
#include "BLI_string_ref.hh"
@@ -23,6 +24,8 @@
#include "DNA_node_types.h"
+struct bNode;
+
namespace blender::nodes {
class NodeDeclarationBuilder;
@@ -84,8 +87,12 @@ class SocketDeclaration {
std::string name_;
std::string identifier_;
std::string description_;
+ /** Defined by whether the socket is part of the node's input or
+ * output socket declaration list. Included here for convenience. */
+ eNodeSocketInOut in_out_;
bool hide_label_ = false;
bool hide_value_ = false;
+ bool compact_ = false;
bool is_multi_input_ = false;
bool no_mute_links_ = false;
bool is_attribute_name_ = false;
@@ -94,19 +101,36 @@ class SocketDeclaration {
InputSocketFieldType input_field_type_ = InputSocketFieldType::None;
OutputFieldDependency output_field_dependency_;
+ /** Utility method to make the socket available if there is a straightforward way to do so. */
+ std::function<void(bNode &)> make_available_fn_;
+
friend NodeDeclarationBuilder;
template<typename SocketDecl> friend class SocketDeclarationBuilder;
public:
virtual ~SocketDeclaration() = default;
- virtual bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const = 0;
+ virtual bNodeSocket &build(bNodeTree &ntree, bNode &node) const = 0;
virtual bool matches(const bNodeSocket &socket) const = 0;
virtual bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const;
+ /**
+ * Determine if a new socket described by this declaration could have a valid connection
+ * the other socket.
+ */
+ virtual bool can_connect(const bNodeSocket &socket) const = 0;
+
+ /**
+ * Change the node such that the socket will become visible. The node type's update method
+ * should be called afterwards.
+ * \note Note that this is not necessarily implemented for all node types.
+ */
+ void make_available(bNode &node) const;
+
StringRefNull name() const;
StringRefNull description() const;
StringRefNull identifier() const;
+ eNodeSocketInOut in_out() const;
bool is_attribute_name() const;
bool is_default_link_socket() const;
@@ -215,6 +239,18 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
std::move(input_dependencies));
return *(Self *)this;
}
+
+ /**
+ * Pass a function that sets properties on the node required to make the corresponding socket
+ * available, if it is not available on the default state of the node. The function is allowed to
+ * make other sockets unavailable, since it is meant to be called when the node is first added.
+ * The node type's update function is called afterwards.
+ */
+ Self &make_available(std::function<void(bNode &)> fn)
+ {
+ decl_->make_available_fn_ = std::move(fn);
+ return *(Self *)this;
+ }
};
using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;
@@ -232,6 +268,7 @@ class NodeDeclaration {
Span<SocketDeclarationPtr> inputs() const;
Span<SocketDeclarationPtr> outputs() const;
+ Span<SocketDeclarationPtr> sockets(eNodeSocketInOut in_out) const;
bool is_function_node() const
{
@@ -267,7 +304,7 @@ class NodeDeclarationBuilder {
template<typename DeclType>
typename DeclType::Builder &add_socket(StringRef name,
StringRef identifier,
- Vector<SocketDeclarationPtr> &r_decls);
+ eNodeSocketInOut in_out);
};
/* -------------------------------------------------------------------- */
@@ -360,6 +397,11 @@ inline StringRefNull SocketDeclaration::identifier() const
return identifier_;
}
+inline eNodeSocketInOut SocketDeclaration::in_out() const
+{
+ return in_out_;
+}
+
inline StringRefNull SocketDeclaration::description() const
{
return description_;
@@ -385,6 +427,13 @@ inline const OutputFieldDependency &SocketDeclaration::output_field_dependency()
return output_field_dependency_;
}
+inline void SocketDeclaration::make_available(bNode &node) const
+{
+ if (make_available_fn_) {
+ make_available_fn_(node);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -400,28 +449,34 @@ template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_input(StringRef name,
StringRef identifier)
{
- return this->add_socket<DeclType>(name, identifier, declaration_.inputs_);
+ return this->add_socket<DeclType>(name, identifier, SOCK_IN);
}
template<typename DeclType>
inline typename DeclType::Builder &NodeDeclarationBuilder::add_output(StringRef name,
StringRef identifier)
{
- return this->add_socket<DeclType>(name, identifier, declaration_.outputs_);
+ return this->add_socket<DeclType>(name, identifier, SOCK_OUT);
}
template<typename DeclType>
-inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(
- StringRef name, StringRef identifier, Vector<SocketDeclarationPtr> &r_decls)
+inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef name,
+ StringRef identifier,
+ eNodeSocketInOut in_out)
{
static_assert(std::is_base_of_v<SocketDeclaration, DeclType>);
using Builder = typename DeclType::Builder;
+
+ Vector<SocketDeclarationPtr> &declarations = in_out == SOCK_IN ? declaration_.inputs_ :
+ declaration_.outputs_;
+
std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
std::unique_ptr<Builder> socket_decl_builder = std::make_unique<Builder>();
socket_decl_builder->decl_ = &*socket_decl;
socket_decl->name_ = name;
socket_decl->identifier_ = identifier.is_empty() ? name : identifier;
- r_decls.append(std::move(socket_decl));
+ socket_decl->in_out_ = in_out;
+ declarations.append(std::move(socket_decl));
Builder &socket_decl_builder_ref = *socket_decl_builder;
builders_.append(std::move(socket_decl_builder));
return socket_decl_builder_ref;
@@ -443,6 +498,14 @@ inline Span<SocketDeclarationPtr> NodeDeclaration::outputs() const
return outputs_;
}
+inline Span<SocketDeclarationPtr> NodeDeclaration::sockets(eNodeSocketInOut in_out) const
+{
+ if (in_out == SOCK_IN) {
+ return inputs_;
+ }
+ return outputs_;
+}
+
/** \} */
} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 26a5dc9d60f..65789069231 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -279,6 +279,9 @@ class NodeTreeRef : NonCopyable, NonMovable {
const NodeRef *find_node(const bNode &bnode) const;
+ /**
+ * \return True when there is a link cycle. Unavailable sockets are ignored.
+ */
bool has_link_cycles() const;
bool has_undefined_nodes_or_sockets() const;
@@ -297,6 +300,10 @@ class NodeTreeRef : NonCopyable, NonMovable {
bool has_cycle = false;
};
+ /**
+ * Sort nodes topologically from left to right or right to left.
+ * In the future the result if this could be cached on #NodeTreeRef.
+ */
ToposortResult toposort(ToposortDirection direction) const;
bNodeTree *btree() const;
diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh
index f7aea212f73..3fb21a4263d 100644
--- a/source/blender/nodes/NOD_socket_declarations.hh
+++ b/source/blender/nodes/NOD_socket_declarations.hh
@@ -39,9 +39,10 @@ class Float : public SocketDeclaration {
public:
using Builder = FloatBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class FloatBuilder : public SocketDeclarationBuilder<Float> {
@@ -66,9 +67,10 @@ class Int : public SocketDeclaration {
public:
using Builder = IntBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class IntBuilder : public SocketDeclarationBuilder<Int> {
@@ -93,9 +95,10 @@ class Vector : public SocketDeclaration {
public:
using Builder = VectorBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class VectorBuilder : public SocketDeclarationBuilder<Vector> {
@@ -104,6 +107,7 @@ class VectorBuilder : public SocketDeclarationBuilder<Vector> {
VectorBuilder &subtype(PropertySubType subtype);
VectorBuilder &min(const float min);
VectorBuilder &max(const float max);
+ VectorBuilder &compact();
};
class BoolBuilder;
@@ -116,8 +120,9 @@ class Bool : public SocketDeclaration {
public:
using Builder = BoolBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class BoolBuilder : public SocketDeclarationBuilder<Bool> {
@@ -136,8 +141,9 @@ class Color : public SocketDeclaration {
public:
using Builder = ColorBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class ColorBuilder : public SocketDeclarationBuilder<Color> {
@@ -156,8 +162,9 @@ class String : public SocketDeclaration {
public:
using Builder = StringBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class StringBuilder : public SocketDeclarationBuilder<String> {
@@ -172,9 +179,10 @@ class IDSocketDeclaration : public SocketDeclaration {
public:
IDSocketDeclaration(const char *idname);
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class Object : public IDSocketDeclaration {
@@ -212,6 +220,23 @@ class Image : public IDSocketDeclaration {
Image();
};
+class ShaderBuilder;
+
+class Shader : public SocketDeclaration {
+ private:
+ friend ShaderBuilder;
+
+ public:
+ using Builder = ShaderBuilder;
+
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
+ bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const;
+};
+
+class ShaderBuilder : public SocketDeclarationBuilder<Shader> {
+};
+
/* -------------------------------------------------------------------- */
/** \name #FloatBuilder Inline Methods
* \{ */
@@ -300,6 +325,12 @@ inline VectorBuilder &VectorBuilder::max(const float max)
return *this;
}
+inline VectorBuilder &VectorBuilder::compact()
+{
+ decl_->compact_ = true;
+ return *this;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -369,26 +400,3 @@ inline Image::Image() : IDSocketDeclaration("NodeSocketImage")
/** \} */
} // namespace blender::nodes::decl
-
-/* -------------------------------------------------------------------- */
-/** \name External Template Instantiations
- *
- * Defined in `intern/extern_implementations.cc`.
- * \{ */
-
-namespace blender::nodes {
-#define MAKE_EXTERN_SOCKET_DECLARATION(TYPE) \
- extern template class SocketDeclarationBuilder<TYPE>; \
- extern template TYPE::Builder &NodeDeclarationBuilder::add_input<TYPE>(StringRef, StringRef); \
- extern template TYPE::Builder &NodeDeclarationBuilder::add_output<TYPE>(StringRef, StringRef);
-
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Float)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Int)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Vector)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Bool)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Color)
-MAKE_EXTERN_SOCKET_DECLARATION(decl::String)
-
-} // namespace blender::nodes
-
-/** \} */
diff --git a/source/blender/nodes/NOD_socket_declarations_geometry.hh b/source/blender/nodes/NOD_socket_declarations_geometry.hh
index 1531f82d67d..0ce07da22ff 100644
--- a/source/blender/nodes/NOD_socket_declarations_geometry.hh
+++ b/source/blender/nodes/NOD_socket_declarations_geometry.hh
@@ -35,8 +35,9 @@ class Geometry : public SocketDeclaration {
public:
using Builder = GeometryBuilder;
- bNodeSocket &build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const override;
+ bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
+ bool can_connect(const bNodeSocket &socket) const override;
Span<GeometryComponentType> supported_types() const;
bool only_realized_data() const;
@@ -52,7 +53,3 @@ class GeometryBuilder : public SocketDeclarationBuilder<Geometry> {
};
} // namespace blender::nodes::decl
-
-namespace blender::nodes {
-MAKE_EXTERN_SOCKET_DECLARATION(decl::Geometry)
-}
diff --git a/source/blender/nodes/NOD_socket_search_link.hh b/source/blender/nodes/NOD_socket_search_link.hh
new file mode 100644
index 00000000000..b7594561dc4
--- /dev/null
+++ b/source/blender/nodes/NOD_socket_search_link.hh
@@ -0,0 +1,151 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <functional>
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h" /* Necessary for eNodeSocketInOut. */
+
+#include "NOD_node_declaration.hh"
+
+struct bContext;
+
+namespace blender::nodes {
+
+/**
+ * Parameters for the operation operation of adding a node after the link drag search menu closes.
+ */
+class LinkSearchOpParams {
+ private:
+ /**
+ * Keep track of the nodes added by the callback, so they can be selected or moved afterwards.
+ */
+ Vector<bNode *> &added_nodes_;
+
+ public:
+ const bContext &C;
+ bNodeTree &node_tree;
+ /**
+ * The node that contains the #socket.
+ */
+ bNode &node;
+ /**
+ * The existing socket to connect any added nodes to. Might be an input or output socket.
+ */
+ bNodeSocket &socket;
+
+ LinkSearchOpParams(const bContext &C,
+ bNodeTree &node_tree,
+ bNode &node,
+ bNodeSocket &socket,
+ Vector<bNode *> &added_nodes)
+ : added_nodes_(added_nodes), C(C), node_tree(node_tree), node(node), socket(socket)
+ {
+ }
+
+ bNode &add_node(StringRef idname);
+ bNode &add_node(const bNodeType &type);
+ /**
+ * Find a socket with the given name (correctly checks for inputs and outputs)
+ * and connect it to the socket the link drag started from (#socket).
+ */
+ void connect_available_socket(bNode &new_node, StringRef socket_name);
+ /**
+ * Like #connect_available_socket, but also calls the node's update function.
+ */
+ void update_and_connect_available_socket(bNode &new_node, StringRef socket_name);
+};
+
+struct SocketLinkOperation {
+ using LinkSocketFn = std::function<void(LinkSearchOpParams &link_params)>;
+
+ std::string name;
+ LinkSocketFn fn;
+ int weight = 0;
+};
+
+class GatherLinkSearchOpParams {
+ /** The current node type. */
+ const bNodeType &node_type_;
+
+ const bNodeTree &node_tree_;
+
+ const bNodeSocket &other_socket_;
+
+ /* The operations currently being built. Owned by the caller. */
+ Vector<SocketLinkOperation> &items_;
+
+ public:
+ GatherLinkSearchOpParams(const bNodeType &node_type,
+ const bNodeTree &node_tree,
+ const bNodeSocket &other_socket,
+ Vector<SocketLinkOperation> &items)
+ : node_type_(node_type), node_tree_(node_tree), other_socket_(other_socket), items_(items)
+ {
+ }
+
+ /**
+ * The node on the other side of the dragged link.
+ */
+ const bNodeSocket &other_socket() const;
+
+ /**
+ * The node tree the user is editing when the search menu is created.
+ */
+ const bNodeTree &node_tree() const;
+
+ /**
+ * The type of the node in the current callback.
+ */
+ const bNodeType &node_type() const;
+
+ /**
+ * Whether to list the input or output sockets of the node.
+ */
+ eNodeSocketInOut in_out() const;
+
+ /**
+ * \param weight: Used to customize the order when multiple search items match.
+ *
+ * \warning When creating lambdas for the #fn argument, be careful not to capture this class
+ * itself, since it is temporary. That is why we tend to use the same variable name for this
+ * class (`params`) that we do for the argument to `LinkSocketFn`.
+ */
+ void add_item(std::string socket_name, SocketLinkOperation::LinkSocketFn fn, int weight = 0);
+};
+
+/**
+ * This callback can be used for a node type when a few things are true about its inputs.
+ * To avoid creating more boilerplate, it is the default callback for node types.
+ * - Either all declared sockets are visible in the default state of the node, *OR* the node's
+ * type's declaration has been extended with #make_available functions for those sockets.
+ *
+ * If a node type does not meet these criteria, the function will do nothing in a release build.
+ * In a debug build, an assert will most likely be hit.
+ *
+ * \note For nodes with the deprecated #bNodeSocketTemplate instead of a declaration,
+ * these criteria do not apply and the function just tries its best without asserting.
+ */
+void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params);
+
+void search_link_ops_for_declarations(GatherLinkSearchOpParams &params,
+ Span<SocketDeclarationPtr> declarations);
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 20ad4d359f1..84bc7bf0ceb 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -267,7 +267,7 @@ DefNode(FunctionNode, FN_NODE_LEGACY_RANDOM_FLOAT, 0, "LEGACY_RANDOM_FLOAT", Leg
DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler To Vector", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
-DefNode(FunctionNode, FN_NODE_COMPARE_FLOATS, def_float_compare, "COMPARE_FLOATS", CompareFloats, "Compare Floats", "")
+DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "")
DefNode(FunctionNode, FN_NODE_INPUT_COLOR, def_fn_input_color, "INPUT_COLOR", InputColor, "Color", "")
@@ -325,6 +325,7 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "L
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
@@ -332,7 +333,7 @@ DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Conve
DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_PARAMETER, 0, "CURVE_PARAMETER", CurveParameter, "Curve Parameter", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
@@ -346,8 +347,10 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "
DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "")
+DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "")
DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "")
DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "")
+DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "")
DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "")
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "")
DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "")
@@ -355,9 +358,16 @@ DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "")
DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS", InputMeshEdgeNeighbors, "Edge Neighbors", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, 0, "MESH_FACE_NEIGHBORS", InputMeshFaceNeighbors, "Face Neighbors", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_ISLAND, 0, "MESH_ISLAND", InputMeshIsland, "Mesh Island", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, 0, "MESH_VERTEX_NEIGHBORS", InputMeshVertexNeighbors, "Vertex Neighbors", "")
DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "Normal", "")
DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "")
DefNode(GeometryNode, GEO_NODE_INPUT_RADIUS, 0, "INPUT_RADIUS", InputRadius, "Radius", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_SCENE_TIME, 0, "INPUT_SCENE_TIME", InputSceneTime, "Scene Time", "")
DefNode(GeometryNode, GEO_NODE_INPUT_SHADE_SMOOTH, 0, "INPUT_SHADE_SMOOTH", InputShadeSmooth, "Is Shade Smooth", "")
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_CYCLIC, 0, "INPUT_SPLINE_CYCLIC", InputSplineCyclic, "Is Spline Cyclic", "")
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_LENGTH, 0, "SPLINE_LENGTH", SplineLength, "Spline Length", "")
@@ -384,7 +394,7 @@ DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", Poin
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "")
DefNode(GeometryNode, GEO_NODE_PROXIMITY, def_geo_proximity, "PROXIMITY", Proximity, "Geometry Proximity", "")
DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "")
-DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, 0, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
+DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, def_geo_realize_instances, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "")
DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE_CURVE", ResampleCurve, "Resample Curve", "")
DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "")
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index a596a85b748..1326c9edab1 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -212,7 +212,7 @@ static bool composite_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetyp
bNodeTreeType *ntreeType_Composite;
-void register_node_tree_type_cmp(void)
+void register_node_tree_type_cmp()
{
bNodeTreeType *tt = ntreeType_Composite = (bNodeTreeType *)MEM_callocN(
sizeof(bNodeTreeType), "compositor node tree type");
@@ -259,16 +259,6 @@ void ntreeCompositExecTree(Scene *scene,
/* *********************************************** */
-/**
- * Update the outputs of the render layer nodes.
- * Since the outputs depend on the render engine, this part is a bit complex:
- * - #ntreeCompositUpdateRLayers is called and loops over all render layer nodes.
- * - Each render layer node calls the update function of the
- * render engine that's used for its scene.
- * - The render engine calls RE_engine_register_pass for each pass.
- * - #RE_engine_register_pass calls #ntreeCompositRegisterPass,
- * which calls #node_cmp_rlayers_register_pass for every render layer node.
- */
void ntreeCompositUpdateRLayers(bNodeTree *ntree)
{
if (ntree == nullptr) {
@@ -299,8 +289,6 @@ void ntreeCompositRegisterPass(bNodeTree *ntree,
}
}
-/* called from render pipeline, to tag render input and output */
-/* need to do all scenes, to prevent errors when you re-render 1 scene */
void ntreeCompositTagRender(Scene *scene)
{
/* XXX Think using G_MAIN here is valid, since you want to update current file's scene nodes,
diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc
index 21269b92e65..1262dfad11f 100644
--- a/source/blender/nodes/composite/node_composite_util.cc
+++ b/source/blender/nodes/composite/node_composite_util.cc
@@ -21,6 +21,8 @@
* \ingroup nodes
*/
+#include "NOD_socket_search_link.hh"
+
#include "node_composite_util.hh"
bool cmp_node_poll_default(bNodeType *UNUSED(ntype),
@@ -28,7 +30,7 @@ bool cmp_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "CompositorNodeTree")) {
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
return true;
@@ -52,4 +54,5 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla
ntype->poll = cmp_node_poll_default;
ntype->updatefunc = cmp_node_update_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/composite/node_composite_util.hh b/source/blender/nodes/composite/node_composite_util.hh
index 6fd82ffc93f..04708d0d854 100644
--- a/source/blender/nodes/composite/node_composite_util.hh
+++ b/source/blender/nodes/composite/node_composite_util.hh
@@ -27,9 +27,6 @@
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "BKE_colorband.h"
@@ -45,8 +42,8 @@
#include "RE_pipeline.h"
-/* only for forward declarations */
#include "NOD_composite.h"
+#include "NOD_socket.h"
#include "NOD_socket_declarations.hh"
#define CMP_SCALE_MAX 12000
diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
index b6f64ed00c7..5e6d59edfd5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
@@ -21,32 +21,46 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** ALPHAOVER ******************** */
-static bNodeSocketTemplate cmp_node_alphaover_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_alphaover_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_alphaover_init(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = MEM_callocN(sizeof(NodeTwoFloats), "NodeTwoFloats");
}
-void register_node_type_cmp_alphaover(void)
+static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "premul", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_alphaover()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_alphaover_in, cmp_node_alphaover_out);
+ ntype.declare = blender::nodes::cmp_node_alphaover_declare;
+ ntype.draw_buttons = node_composit_buts_alphaover;
node_type_init(&ntype, node_alphaover_init);
node_type_storage(
&ntype, "NodeTwoFloats", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
index 23e63b9a53b..02b2652ed6a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
@@ -23,14 +23,22 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Anti-Aliasing (SMAA 1x) ******************** */
-static bNodeSocketTemplate cmp_node_antialiasing_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes {
-static bNodeSocketTemplate cmp_node_antialiasing_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+static void cmp_node_antialiasing_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,13 +52,25 @@ static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = data;
}
-void register_node_type_cmp_antialiasing(void)
+static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_antialiasing()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_antialiasing_in, cmp_node_antialiasing_out);
+ ntype.declare = blender::nodes::cmp_node_antialiasing_declare;
+ ntype.draw_buttons = node_composit_buts_antialiasing;
node_type_size(&ntype, 170, 140, 200);
node_type_init(&ntype, node_composit_init_antialiasing);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
index 3e724d17a10..3f107a13a44 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
@@ -21,18 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** BILATERALBLUR ******************** */
-static bNodeSocketTemplate cmp_node_bilateralblur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Determinator"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_bilateralblur_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Determinator")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,12 +49,25 @@ static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *no
nbbd->sigma_space = 5.0;
}
-void register_node_type_cmp_bilateralblur(void)
+static void node_composit_buts_bilateralblur(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sigma_color", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sigma_space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_bilateralblur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_bilateralblur_in, cmp_node_bilateralblur_out);
+ ntype.declare = blender::nodes::cmp_node_bilateralblur_declare;
+ ntype.draw_buttons = node_composit_buts_bilateralblur;
node_type_init(&ntype, node_composit_init_bilateralblur);
node_type_storage(
&ntype, "NodeBilateralBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc
index c5c0c21929e..bcc8c786ae5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_blur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc
@@ -22,14 +22,25 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** BLUR ******************** */
-static bNodeSocketTemplate cmp_node_blur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_blur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+
+namespace blender::nodes {
+
+static void cmp_node_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -38,12 +49,54 @@ static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_blur(void)
+static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ col = uiLayoutColumn(layout, false);
+ const int filter = RNA_enum_get(ptr, "filter_type");
+ const int reference = RNA_boolean_get(ptr, "use_variable_size");
+
+ uiItemR(col, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ if (filter != R_FILTER_FAST_GAUSS) {
+ uiItemR(col, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (!reference) {
+ uiItemR(col, ptr, "use_bokeh", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ uiItemR(col, ptr, "use_gamma_correction", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+
+ uiItemR(col, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_boolean_get(ptr, "use_relative")) {
+ uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row,
+ ptr,
+ "aspect_correction",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "factor_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "factor_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+ }
+ else {
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "size_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "size_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+ }
+ uiItemR(col, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_blur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_blur_in, cmp_node_blur_out);
+ ntype.declare = blender::nodes::cmp_node_blur_declare;
+ ntype.draw_buttons = node_composit_buts_blur;
node_type_init(&ntype, node_composit_init_blur);
node_type_storage(
&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
index f130a642e20..d0659f6a51e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -22,18 +22,25 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** BLUR ******************** */
-static bNodeSocketTemplate cmp_node_bokehblur_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Bokeh"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f},
- {SOCK_FLOAT, N_("Bounding box"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_bokehblur_out[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Bokeh")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(10.0f);
+ b.add_input<decl::Float>(N_("Bounding box")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,12 +48,21 @@ static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node)
node->custom4 = 16.0f;
}
-void register_node_type_cmp_bokehblur(void)
+static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ // uiItemR(layout, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); /* UNUSED */
+ uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_bokehblur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_bokehblur_in, cmp_node_bokehblur_out);
+ ntype.declare = blender::nodes::cmp_node_bokehblur_declare;
+ ntype.draw_buttons = node_composit_buts_bokehblur;
node_type_init(&ntype, node_composit_init_bokehblur);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
index 3f8a7606d94..8817a07a422 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** Bokeh image Tools ******************** */
@@ -45,12 +48,28 @@ static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_bokehimage(void)
+static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "flaps", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(
+ layout, ptr, "rounding", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(layout,
+ ptr,
+ "catadioptric",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(layout, ptr, "shift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_bokehimage()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_bokehimage_declare;
+ ntype.draw_buttons = node_composit_buts_bokehimage;
node_type_init(&ntype, node_composit_init_bokehimage);
node_type_storage(
&ntype, "NodeBokehImage", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
index cdf96065f97..40859922154 100644
--- a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
@@ -21,16 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_boxmask_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_boxmask_out[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -43,12 +50,29 @@ static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_boxmask(void)
+static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "width", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "height", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_boxmask()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_boxmask_in, cmp_node_boxmask_out);
+ ntype.declare = blender::nodes::cmp_node_boxmask_declare;
+ ntype.draw_buttons = node_composit_buts_boxmask;
node_type_init(&ntype, node_composit_init_boxmask);
node_type_storage(&ntype, "NodeBoxMask", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
index 028afad3cf8..ca03a9b4fbf 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Bright and Contrast ******************** */
@@ -42,12 +45,20 @@ static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *n
node->custom1 = 1;
}
-void register_node_type_cmp_brightcontrast(void)
+static void node_composit_buts_brightcontrast(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_brightcontrast()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_brightcontrast_declare;
+ ntype.draw_buttons = node_composit_buts_brightcontrast;
node_type_init(&ntype, node_composit_init_brightcontrast);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
index e211bc45b17..1b4be78c71b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
@@ -21,19 +21,25 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Channel Matte Node ********************************* */
-static bNodeSocketTemplate cmp_node_channel_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_channel_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_channel_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -50,13 +56,55 @@ static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *no
node->custom2 = 2; /* Green Channel. */
}
-void register_node_type_cmp_channel_matte(void)
+static void node_composit_buts_channel_matte(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(
+ row, ptr, "color_space", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row,
+ ptr,
+ "matte_channel",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemR(col, ptr, "limit_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (RNA_enum_get(ptr, "limit_method") == 0) {
+ uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row,
+ ptr,
+ "limit_channel",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ }
+
+ uiItemR(
+ col, ptr, "limit_max", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_channel_matte()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_channel_matte_in, cmp_node_channel_matte_out);
+ ntype.declare = blender::nodes::cmp_node_channel_matte_declare;
+ ntype.draw_buttons = node_composit_buts_channel_matte;
node_type_init(&ntype, node_composit_init_channel_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
index 990778160df..a7e3a1c148f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Chroma Key ********************************************************** */
-static bNodeSocketTemplate cmp_node_chroma_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_chroma_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -47,12 +51,29 @@ static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *nod
c->fstrength = 1.0f;
}
-void register_node_type_cmp_chroma_matte(void)
+static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ /* Removed for now. */
+ // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ /* Removed for now. */
+ // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_chroma_matte()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_chroma_in, cmp_node_chroma_out);
+ ntype.declare = blender::nodes::cmp_node_chroma_matte_declare;
+ ntype.draw_buttons = node_composit_buts_chroma_matte;
node_type_init(&ntype, node_composit_init_chroma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
index fc9a0075b14..367b046f3f6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* ******************* Color Key ********************************************************** */
-static bNodeSocketTemplate cmp_node_color_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
+/* ******************* Color Matte ********************************************************** */
+
+namespace blender::nodes {
+
+static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
-static bNodeSocketTemplate cmp_node_color_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+} // namespace blender::nodes
static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -47,12 +51,30 @@ static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node
c->fstrength = 1.0f;
}
-void register_node_type_cmp_color_matte(void)
+static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "color_hue", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "color_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ col, ptr, "color_value", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_color_matte()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_color_in, cmp_node_color_out);
+ ntype.declare = blender::nodes::cmp_node_color_matte_declare;
+ ntype.draw_buttons = node_composit_buts_color_matte;
node_type_init(&ntype, node_composit_init_color_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
index 7bdc2e8289e..e136041cf6e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
@@ -21,19 +21,25 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Spill Suppression ********************************* */
-static bNodeSocketTemplate cmp_node_color_spill_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_color_spill_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_color_spill_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -46,12 +52,59 @@ static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node
ncs->unspill = 0; /* do not use unspill */
}
-void register_node_type_cmp_color_spill(void)
+static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row, *col;
+
+ uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "limit_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "limit_method") == 0) {
+ uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row,
+ ptr,
+ "limit_channel",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ }
+
+ uiItemR(col, ptr, "ratio", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_unspill", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (RNA_boolean_get(ptr, "use_unspill") == true) {
+ uiItemR(col,
+ ptr,
+ "unspill_red",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "unspill_green",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(col,
+ ptr,
+ "unspill_blue",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_color_spill()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_color_spill_in, cmp_node_color_spill_out);
+ ntype.declare = blender::nodes::cmp_node_color_spill_declare;
+ ntype.draw_buttons = node_composit_buts_color_spill;
node_type_init(&ntype, node_composit_init_color_spill);
node_type_storage(
&ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
index ef8af5f81a6..a35b3d813e6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
@@ -21,6 +21,11 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Balance ********************************* */
@@ -39,8 +44,7 @@ static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
/* Sync functions update formula parameters for other modes, such that the result is comparable.
* Note that the results are not exactly the same due to differences in color handling
* (sRGB conversion happens for LGG),
- * but this keeps settings comparable.
- */
+ * but this keeps settings comparable. */
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -80,12 +84,88 @@ static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = n;
}
-void register_node_type_cmp_colorbalance(void)
+static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *split, *col, *row;
+
+ uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "correction_method") == 0) {
+
+ split = uiLayoutSplit(layout, 0.0f, false);
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "lift", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "gain", true, true, true, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+
+ split = uiLayoutSplit(layout, 0.0f, false);
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "offset", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "offset_basis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "power", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+ uiTemplateColorPicker(col, ptr, "slope", true, true, false, true);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+static void node_composit_buts_colorbalance_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "correction_method") == 0) {
+
+ uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
+ uiItemR(layout, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true);
+ uiItemR(layout, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true);
+ uiItemR(layout, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+ uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true);
+ uiItemR(layout, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "power", true, true, false, true);
+ uiItemR(layout, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true);
+ uiItemR(layout, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_colorbalance()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_colorbalance_declare;
+ ntype.draw_buttons = node_composit_buts_colorbalance;
+ ntype.draw_buttons_ex = node_composit_buts_colorbalance_ex;
node_type_size(&ntype, 400, 200, 400);
node_type_init(&ntype, node_composit_init_colorbalance);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
index 095fbef826a..e3bba3b6c4f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Correction ********************************* */
@@ -66,12 +69,230 @@ static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *
node->storage = n;
}
-void register_node_type_cmp_colorcorrection(void)
+static void node_composit_buts_colorcorrection(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "red", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "green", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "blue", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, "", ICON_NONE);
+ uiItemL(row, IFACE_("Saturation"), ICON_NONE);
+ uiItemL(row, IFACE_("Contrast"), ICON_NONE);
+ uiItemL(row, IFACE_("Gamma"), ICON_NONE);
+ uiItemL(row, IFACE_("Gain"), ICON_NONE);
+ uiItemL(row, IFACE_("Lift"), ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Master"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_saturation", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "master_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Highlights"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "highlights_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Midtones"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_("Shadows"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ "",
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row,
+ ptr,
+ "midtones_start",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "red", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "green", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "blue", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ row = layout;
+ uiItemL(row, IFACE_("Saturation"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "master_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_saturation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Contrast"), ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "master_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_contrast",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Gamma"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_gamma", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "shadows_gamma",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+
+ uiItemL(row, IFACE_("Gain"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_gain",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_gain",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_gain", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemL(row, IFACE_("Lift"), ICON_NONE);
+ uiItemR(
+ row, ptr, "master_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "highlights_lift",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(row,
+ ptr,
+ "midtones_lift",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ uiItemR(
+ row, ptr, "shadows_lift", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_colorcorrection()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_colorcorrection_declare;
+ ntype.draw_buttons = node_composit_buts_colorcorrection;
+ ntype.draw_buttons_ex = node_composit_buts_colorcorrection_ex;
node_type_size(&ntype, 400, 200, 600);
node_type_init(&ntype, node_composit_init_colorcorrection);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc
index 6432a89ffa0..aa81cecc3e2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_common.cc
@@ -32,14 +32,13 @@
#include "RNA_access.h"
-void register_node_type_cmp_group(void)
+void register_node_type_cmp_group()
{
static bNodeType ntype;
/* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type
* to the shared NODE_GROUP integer type id. */
- node_type_base_custom(
- &ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
+ node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, 0);
ntype.type = NODE_GROUP;
ntype.poll = cmp_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -50,7 +49,7 @@ void register_node_type_cmp_group(void)
node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc
index a1a49133a3a..547e5123579 100644
--- a/source/blender/nodes/composite/nodes/node_composite_composite.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** COMPOSITE ******************** */
@@ -36,13 +39,18 @@ static void cmp_node_composite_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_composite(void)
+static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_composite()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_composite_declare;
-
+ ntype.draw_buttons = node_composit_buts_composite;
ntype.no_muting = true;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
index b5ca1fb015e..2e7a87a576d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
@@ -23,27 +23,39 @@
#include "node_composite_util.hh"
-static bNodeSocketTemplate inputs[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Upper Left"), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Upper Right"), 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Lower Left"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Lower Right"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate outputs[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Plane")},
- {-1, ""},
-};
-
-void register_node_type_cmp_cornerpin(void)
+namespace blender::nodes {
+
+static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Upper Left"))
+ .default_value({0.0f, 1.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Upper Right"))
+ .default_value({1.0f, 1.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Lower Left"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_input<decl::Vector>(N_("Lower Right"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Plane"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_cornerpin()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, inputs, outputs);
+ ntype.declare = blender::nodes::cmp_node_cornerpin_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_crop.cc b/source/blender/nodes/composite/nodes/node_composite_crop.cc
index f07dba8a74b..fa33caa4c0e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_crop.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_crop.cc
@@ -21,18 +21,24 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Crop ******************** */
-static bNodeSocketTemplate cmp_node_crop_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_crop_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_crop_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,12 +50,35 @@ static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
nxy->y2 = 0;
}
-void register_node_type_cmp_crop(void)
+static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "use_crop_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ if (RNA_boolean_get(ptr, "relative")) {
+ uiItemR(col, ptr, "rel_min_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Down"), ICON_NONE);
+ }
+ else {
+ uiItemR(col, ptr, "min_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "max_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "min_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "max_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Down"), ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_crop()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_crop_in, cmp_node_crop_out);
+ ntype.declare = blender::nodes::cmp_node_crop_declare;
+ ntype.draw_buttons = node_composit_buts_crop;
node_type_init(&ntype, node_composit_init_crop);
node_type_storage(&ntype, "NodeTwoXYs", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 6657267b016..65b1f6799d7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -38,8 +38,10 @@
#include <optional>
+/* -------------------------------------------------------------------- */
/** \name Cryptomatte
* \{ */
+
static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node_render(
const bNode &node, const bool use_meta_data)
{
@@ -297,16 +299,16 @@ static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype),
}
if (scene == nullptr) {
- *r_disabled_hint =
- "The node tree must be the compositing node tree of any scene in the file";
+ *r_disabled_hint = TIP_(
+ "The node tree must be the compositing node tree of any scene in the file");
}
return scene != nullptr;
}
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
-void register_node_type_cmp_cryptomatte(void)
+void register_node_type_cmp_cryptomatte()
{
static bNodeType ntype;
@@ -322,8 +324,10 @@ void register_node_type_cmp_cryptomatte(void)
/** \} */
+/* -------------------------------------------------------------------- */
/** \name Cryptomatte Legacy
* \{ */
+
static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
{
node_init_cryptomatte(ntree, node);
@@ -361,7 +365,7 @@ int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
return 1;
}
-void register_node_type_cmp_cryptomatte_legacy(void)
+void register_node_type_cmp_cryptomatte_legacy()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index 5f99bb57768..518b57dc405 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** CURVE Time ******************** */
@@ -42,7 +45,7 @@ static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode *node
node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_time(void)
+void register_node_type_cmp_curve_time()
{
static bNodeType ntype;
@@ -56,27 +59,34 @@ void register_node_type_cmp_curve_time(void)
}
/* **************** CURVE VEC ******************** */
-static bNodeSocketTemplate cmp_node_curve_vec_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_curve_vec_out[] = {
- {SOCK_VECTOR, N_("Vector")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_curve_vec_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).default_value({0.0f, 0.0f, 0.0f}).min(-1.0f).max(1.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_vec(void)
+static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false);
+}
+
+void register_node_type_cmp_curve_vec()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_curve_vec_in, cmp_node_curve_vec_out);
+ ntype.declare = blender::nodes::cmp_node_curve_vec_declare;
+ ntype.draw_buttons = node_buts_curvevec;
node_type_size(&ntype, 200, 140, 320);
node_type_init(&ntype, node_composit_init_curve_vec);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
@@ -105,7 +115,7 @@ static void node_composit_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = BKE_curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
}
-void register_node_type_cmp_curve_rgb(void)
+void register_node_type_cmp_curve_rgb()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.cc b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
index 1103aff4366..0ee8a8da1e8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_defocus.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
@@ -21,20 +21,27 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include <climits>
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* ************ Defocus Node ****************** */
-static bNodeSocketTemplate cmp_node_defocus_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_defocus_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_defocus_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -53,12 +60,52 @@ static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = nbd;
}
-void register_node_type_cmp_defocus(void)
+static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiLayout *sub, *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
+ uiItemR(col, ptr, "bokeh", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "use_gamma_correction", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
+ uiItemR(col, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_preview", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "scene",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_zbuffer", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
+ uiItemR(sub, ptr, "z_scale", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_defocus()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_defocus_in, cmp_node_defocus_out);
+ ntype.declare = blender::nodes::cmp_node_defocus_declare;
+ ntype.draw_buttons = node_composit_buts_defocus;
node_type_init(&ntype, node_composit_init_defocus);
node_type_storage(&ntype, "NodeDefocus", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
index ec085794462..f1e5388a7a3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
@@ -23,14 +23,26 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_denoise_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_RGBA, N_("Albedo"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_denoise_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_denoise_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Normal"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .hide_value();
+ b.add_input<decl::Color>(N_("Albedo")).default_value({1.0f, 1.0f, 1.0f, 1.0f}).hide_value();
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -40,12 +52,31 @@ static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ndg;
}
-void register_node_type_cmp_denoise(void)
+static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+#ifndef WITH_OPENIMAGEDENOISE
+ uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR);
+#else
+ /* Always supported through Accelerate framework BNNS on macOS. */
+# ifndef __APPLE__
+ if (!BLI_cpu_support_sse41()) {
+ uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR);
+ }
+# endif
+#endif
+
+ uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE);
+ uiItemR(layout, ptr, "prefilter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_hdr", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_denoise()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_denoise_in, cmp_node_denoise_out);
+ ntype.declare = blender::nodes::cmp_node_denoise_declare;
+ ntype.draw_buttons = node_composit_buts_denoise;
node_type_init(&ntype, node_composit_init_denonise);
node_type_storage(&ntype, "NodeDenoise", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
index 52d91dabeb1..411bad14f25 100644
--- a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
@@ -21,18 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** FILTER ******************** */
-static bNodeSocketTemplate cmp_node_despeckle_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_despeckle_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_despeckle_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -40,12 +45,22 @@ static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node)
node->custom4 = 0.5f;
}
-void register_node_type_cmp_despeckle(void)
+static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "threshold_neighbor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_despeckle()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_despeckle_in, cmp_node_despeckle_out);
+ ntype.declare = blender::nodes::cmp_node_despeckle_declare;
+ ntype.draw_buttons = node_composit_buts_despeckle;
node_type_init(&ntype, node_composit_init_despeckle);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
index 1e1a48381b7..a9e3258c8fb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* channel Difference Matte ********************************* */
-static bNodeSocketTemplate cmp_node_diff_matte_in[] = {
- {SOCK_RGBA, N_("Image 1"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Image 2"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_diff_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image 1")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image 2")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Color>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,13 +48,24 @@ static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
c->t2 = 0.1f;
}
-void register_node_type_cmp_diff_matte(void)
+static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_diff_matte()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_diff_matte_in, cmp_node_diff_matte_out);
+ ntype.declare = blender::nodes::cmp_node_diff_matte_declare;
+ ntype.draw_buttons = node_composit_buts_diff_matte;
node_type_init(&ntype, node_composit_init_diff_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
index 57884a299da..1af2bb0433b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
@@ -21,13 +21,24 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Dilate/Erode ******************** */
-static bNodeSocketTemplate cmp_node_dilateerode_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_dilateerode_out[] = {{SOCK_FLOAT, N_("Mask")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_dilate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -37,12 +48,27 @@ static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node
node->storage = data;
}
-void register_node_type_cmp_dilateerode(void)
+static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ switch (RNA_enum_get(ptr, "mode")) {
+ case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
+ uiItemR(layout, ptr, "edge", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ break;
+ case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
+ uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ break;
+ }
+}
+
+void register_node_type_cmp_dilateerode()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_dilateerode_in, cmp_node_dilateerode_out);
+ ntype.draw_buttons = node_composit_buts_dilateerode;
+ ntype.declare = blender::nodes::cmp_node_dilate_declare;
node_type_init(&ntype, node_composit_init_dilateerode);
node_type_storage(
&ntype, "NodeDilateErode", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
index d9f82ba5009..36b130d55a4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
@@ -21,12 +21,20 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_dblur_in[] = {{SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
-static bNodeSocketTemplate cmp_node_dblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+} // namespace blender::nodes
static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -37,12 +45,37 @@ static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
ndbd->center_y = 0.5;
}
-void register_node_type_cmp_dblur(void)
+static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_wrap", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Center:"), ICON_NONE);
+ uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
+
+ uiItemS(layout);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemS(layout);
+
+ uiItemR(layout, ptr, "spin", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "zoom", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_dblur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_dblur_in, cmp_node_dblur_out);
+ ntype.declare = blender::nodes::cmp_node_directional_blur_declare;
+ ntype.draw_buttons = node_composit_buts_dblur;
node_type_init(&ntype, node_composit_init_dblur);
node_type_storage(
&ntype, "NodeDBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.cc b/source/blender/nodes/composite/nodes/node_composite_displace.cc
index b1ed7f05794..0137c1f7da8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_displace.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc
@@ -25,24 +25,29 @@
/* **************** Displace ******************** */
-static bNodeSocketTemplate cmp_node_displace_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_VECTOR, N_("Vector"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_TRANSLATION},
- {SOCK_FLOAT, N_("X Scale"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Y Scale"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_displace_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_displace(void)
+namespace blender::nodes {
+
+static void cmp_node_displace_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Vector"))
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Float>(N_("X Scale")).default_value(0.0f).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Y Scale")).default_value(0.0f).min(-1000.0f).max(1000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_displace()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_displace_in, cmp_node_displace_out);
+ ntype.declare = blender::nodes::cmp_node_displace_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
index 3f8767ecd08..47a48ed141e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* channel Distance Matte ********************************* */
-static bNodeSocketTemplate cmp_node_distance_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Key Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_distance_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -45,12 +49,30 @@ static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *n
c->t2 = 0.1f;
}
-void register_node_type_cmp_distance_matte(void)
+static void node_composit_buts_distance_matte(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col, *row;
+
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ uiItemR(
+ col, ptr, "tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_distance_matte()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_distance_matte_in, cmp_node_distance_matte_out);
+ ntype.declare = blender::nodes::cmp_node_distance_matte_declare;
+ ntype.draw_buttons = node_composit_buts_distance_matte;
node_type_init(&ntype, node_composit_init_distance_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
index 7c9a48efc2d..4fde539e6fb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
@@ -20,31 +20,46 @@
/** \file
* \ingroup cmpnodes
*/
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
+
/* **************** Double Edge Mask ******************** */
-static bNodeSocketTemplate cmp_node_doubleedgemask_in[] = {
- /* Inner mask socket definition. */
- {SOCK_FLOAT, "Inner Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- /* Outer mask socket definition. */
- {SOCK_FLOAT, "Outer Mask", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- /* Input socket array terminator. */
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_doubleedgemask_out[] = {
- /* Output socket definition. */
- {SOCK_FLOAT, "Mask"},
- /* Output socket array terminator. */
- {-1, ""},
-};
-
-void register_node_type_cmp_doubleedgemask(void)
+namespace blender::nodes {
+
+static void cmp_node_double_edge_mask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Inner Mask")).default_value(0.8f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Outer Mask")).default_value(0.8f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_double_edge_mask(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
+ uiItemR(col, ptr, "inner_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
+ uiItemR(col, ptr, "edge_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_doubleedgemask()
{
static bNodeType ntype; /* Allocate a node type data structure. */
cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
- node_type_socket_templates(&ntype, cmp_node_doubleedgemask_in, cmp_node_doubleedgemask_out);
+ ntype.declare = blender::nodes::cmp_node_double_edge_mask_declare;
+ ntype.draw_buttons = node_composit_buts_double_edge_mask;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
index 67196fb0d35..8eb89e53790 100644
--- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
@@ -21,16 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_ellipsemask_in[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_ellipsemask_out[] = {
- {SOCK_FLOAT, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_ellipsemask_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Mask")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Mask"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -44,12 +51,27 @@ static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node
node->storage = data;
}
-void register_node_type_cmp_ellipsemask(void)
+static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "width", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(row, ptr, "height", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_ellipsemask()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_ellipsemask_in, cmp_node_ellipsemask_out);
+ ntype.declare = blender::nodes::cmp_node_ellipsemask_declare;
+ ntype.draw_buttons = node_composit_buts_ellipsemask;
node_type_size(&ntype, 260, 110, 320);
node_type_init(&ntype, node_composit_init_ellipsemask);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
index c1e64065f7e..b696db41a3c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
@@ -36,7 +36,7 @@ static void cmp_node_exposure_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_exposure(void)
+void register_node_type_cmp_exposure()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc
index f07619877f4..3671d502539 100644
--- a/source/blender/nodes/composite/nodes/node_composite_filter.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc
@@ -21,26 +21,37 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** FILTER ******************** */
-static bNodeSocketTemplate cmp_node_filter_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_filter_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_filter(void)
+
+namespace blender::nodes {
+
+static void cmp_node_filter_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_filter()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_filter_in, cmp_node_filter_out);
- node_type_label(&ntype, node_filter_label);
+ ntype.declare = blender::nodes::cmp_node_filter_declare;
+ ntype.draw_buttons = node_composit_buts_filter;
+ ntype.labelfunc = node_filter_label;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.cc b/source/blender/nodes/composite/nodes/node_composite_flip.cc
index 42aa3141f5c..38bc0f8b855 100644
--- a/source/blender/nodes/composite/nodes/node_composite_flip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_flip.cc
@@ -21,25 +21,35 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Flip ******************** */
-static bNodeSocketTemplate cmp_node_flip_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_flip_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_flip_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
-void register_node_type_cmp_flip(void)
+void register_node_type_cmp_flip()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_flip_in, cmp_node_flip_out);
+ ntype.declare = blender::nodes::cmp_node_flip_declare;
+ ntype.draw_buttons = node_composit_buts_flip;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.cc b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
index 74152a27485..438770865ae 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
@@ -40,7 +40,7 @@ static void cmp_node_gamma_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_gamma(void)
+void register_node_type_cmp_gamma()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc
index 8a2fd1e1584..adaf22395c3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_glare.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc
@@ -21,16 +21,22 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_glare_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_glare_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_glare_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -49,12 +55,51 @@ static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ndg;
}
-void register_node_type_cmp_glare(void)
+static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "glare_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "quality", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") != 1) {
+ uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") != 0) {
+ uiItemR(layout,
+ ptr,
+ "color_modulation",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+ }
+ }
+
+ uiItemR(layout, ptr, "mix", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") == 2) {
+ uiItemR(layout, ptr, "streaks", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "angle_offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
+ uiItemR(
+ layout, ptr, "fade", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+
+ if (RNA_enum_get(ptr, "glare_type") == 0) {
+ uiItemR(layout, ptr, "use_rotate_45", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ }
+ if (RNA_enum_get(ptr, "glare_type") == 1) {
+ uiItemR(layout, ptr, "size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_glare()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_glare_in, cmp_node_glare_out);
+ ntype.declare = blender::nodes::cmp_node_glare_declare;
+ ntype.draw_buttons = node_composit_buts_glare;
node_type_init(&ntype, node_composit_init_glare);
node_type_storage(&ntype, "NodeGlare", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
index 21430035465..47fbaa4d384 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
@@ -47,7 +47,7 @@ static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_hue_sat(void)
+void register_node_type_cmp_hue_sat()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index 83743bbed18..e78ba0c7f9c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -51,7 +51,7 @@ static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
cumapping->cur = 1;
}
-void register_node_type_cmp_huecorrect(void)
+void register_node_type_cmp_huecorrect()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.cc b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
index 5121370567c..f5b8cb6c567 100644
--- a/source/blender/nodes/composite/nodes/node_composite_idMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** ID Mask ******************** */
@@ -35,12 +38,19 @@ static void cmp_node_idmask_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_idmask(void)
+static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "index", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_antialiasing", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_idmask()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::cmp_node_idmask_declare;
+ ntype.draw_buttons = node_composit_buts_id_mask;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc
index 40d4d4563c9..8e3cc9bcd95 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_image.cc
@@ -26,16 +26,21 @@
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
-#include "DNA_scene_types.h"
-
-#include "RE_engine.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DNA_scene_types.h"
+
+#include "RE_engine.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
/* **************** IMAGE (and RenderResult, multilayer image) ******************** */
static bNodeSocketTemplate cmp_node_rlayers_out[] = {
@@ -443,7 +448,7 @@ static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree),
}
}
-void register_node_type_cmp_image(void)
+void register_node_type_cmp_image()
{
static bNodeType ntype;
@@ -451,7 +456,7 @@ void register_node_type_cmp_image(void)
node_type_init(&ntype, node_composit_init_image);
node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image);
node_type_update(&ntype, cmp_node_image_update);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
nodeRegisterType(&ntype);
}
@@ -499,7 +504,7 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "CompositorNodeTree")) {
- *r_disabled_hint = "Not a compositor node tree";
+ *r_disabled_hint = TIP_("Not a compositor node tree");
return false;
}
@@ -516,7 +521,8 @@ static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype),
}
if (scene == nullptr) {
- *r_disabled_hint = "The node tree must be the compositing node tree of any scene in the file";
+ *r_disabled_hint = TIP_(
+ "The node tree must be the compositing node tree of any scene in the file");
return false;
}
return true;
@@ -554,12 +560,56 @@ static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
cmp_node_update_default(ntree, node);
}
-void register_node_type_cmp_rlayers(void)
+static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ uiLayout *col, *row;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "scene",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "layer", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ PropertyRNA *prop = RNA_struct_find_property(ptr, "layer");
+ const char *layer_name;
+ if (!(RNA_property_enum_identifier(
+ C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) {
+ return;
+ }
+
+ PointerRNA scn_ptr;
+ char scene_name[MAX_ID_NAME - 2];
+ scn_ptr = RNA_pointer_get(ptr, "scene");
+ RNA_string_get(&scn_ptr, "name", scene_name);
+
+ PointerRNA op_ptr;
+ uiItemFullO(
+ row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "layer", layer_name);
+ RNA_string_set(&op_ptr, "scene", scene_name);
+}
+
+void register_node_type_cmp_rlayers()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, nullptr, cmp_node_rlayers_out);
+ ntype.draw_buttons = node_composit_buts_viewlayers;
ntype.initfunc_api = node_composit_init_rlayers;
ntype.poll = node_composit_poll_rlayers;
node_type_storage(&ntype, nullptr, node_composit_free_rlayers, node_composit_copy_rlayers);
diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
index d0ff97a2ca0..976b1cd5a15 100644
--- a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
@@ -21,20 +21,35 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Inpaint/ ******************** */
-static bNodeSocketTemplate cmp_node_inpaint_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_inpaint_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_inpaint_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
-void register_node_type_cmp_inpaint(void)
+void register_node_type_cmp_inpaint()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_inpaint_in, cmp_node_inpaint_out);
+ ntype.declare = blender::nodes::cmp_node_inpaint_declare;
+ ntype.draw_buttons = node_composit_buts_inpaint;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc
index dabf0452628..2243608d5c3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_invert.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** INVERT ******************** */
@@ -41,13 +44,23 @@ static void node_composit_init_invert(bNodeTree *UNUSED(ntree), bNode *node)
node->custom1 |= CMP_CHAN_RGB;
}
+static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "invert_rgb", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "invert_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
/* custom1 = mix type */
-void register_node_type_cmp_invert(void)
+void register_node_type_cmp_invert()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_invert_declare;
+ ntype.draw_buttons = node_composit_buts_invert;
node_type_init(&ntype, node_composit_init_invert);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.cc b/source/blender/nodes/composite/nodes/node_composite_keying.cc
index d5547161069..de1da3289f9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keying.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keying.cc
@@ -21,30 +21,33 @@
* \ingroup cmpnodes
*/
+#include "BLI_math_base.h"
+
#include "BLT_translation.h"
#include "DNA_movieclip_types.h"
-#include "BLI_math_base.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Keying ******************** */
-static bNodeSocketTemplate cmp_node_keying_in[] = {
- {SOCK_RGBA, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, "Key Color", 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, "Garbage Matte", 0.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, "Core Matte", 0.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_keying_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Garbage Matte")).hide_value();
+ b.add_input<decl::Float>(N_("Core Matte")).hide_value();
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+ b.add_output<decl::Float>(N_("Edges"));
+}
-static bNodeSocketTemplate cmp_node_keying_out[] = {
- {SOCK_RGBA, "Image"},
- {SOCK_FLOAT, "Matte"},
- {SOCK_FLOAT, "Edges"},
- {-1, ""},
-};
+} // namespace blender::nodes
static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -60,12 +63,31 @@ static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_keying(void)
+static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */
+
+ uiItemR(layout, ptr, "blur_pre", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "screen_balance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "despill_factor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "despill_balance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_radius", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_tolerance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "clip_black", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "clip_white", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "dilate_distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "feather_falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "feather_distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "blur_post", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_keying()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_keying_in, cmp_node_keying_out);
+ ntype.declare = blender::nodes::cmp_node_keying_declare;
+ ntype.draw_buttons = node_composit_buts_keying;
node_type_init(&ntype, node_composit_init_keying);
node_type_storage(
&ntype, "NodeKeyingData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
index c976a92b92d..d90fbe05211 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
@@ -26,14 +26,23 @@
#include "BLI_math_base.h"
#include "BLI_math_color.h"
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Keying Screen ******************** */
-static bNodeSocketTemplate cmp_node_keyingscreen_out[] = {
- {SOCK_RGBA, "Screen"},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_keyingscreen_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Screen"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -42,12 +51,40 @@ static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = data;
}
-void register_node_type_cmp_keyingscreen(void)
+static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+ }
+}
+
+void register_node_type_cmp_keyingscreen()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, nullptr, cmp_node_keyingscreen_out);
+ ntype.declare = blender::nodes::cmp_node_keyingscreen_declare;
+ ntype.draw_buttons = node_composit_buts_keyingscreen;
node_type_init(&ntype, node_composit_init_keyingscreen);
node_type_storage(
&ntype, "NodeKeyingScreenData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
index 2a8dc035792..11ee0cf0aa3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
@@ -21,18 +21,24 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_lensdist_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Distort"), 0.0f, 0.0f, 0.0f, 0.0f, -0.999f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Dispersion"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_lensdist_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Distort")).default_value(0.0f).min(-0.999f).max(1.0f);
+ b.add_input<decl::Float>(N_("Dispersion")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,12 +47,26 @@ static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = nld;
}
-void register_node_type_cmp_lensdist(void)
+static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "use_projector", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(col, false);
+ uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
+ uiItemR(col, ptr, "use_jitter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_fit", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_lensdist()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_lensdist_in, cmp_node_lensdist_out);
+ ntype.declare = blender::nodes::cmp_node_lensdist_declare;
+ ntype.draw_buttons = node_composit_buts_lensdist;
node_type_init(&ntype, node_composit_init_lensdist);
node_type_storage(
&ntype, "NodeLensDist", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc
index 54064f24e0d..891f79f9bf9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** LEVELS ******************** */
@@ -41,12 +44,18 @@ static void node_composit_init_view_levels(bNodeTree *UNUSED(ntree), bNode *node
node->custom1 = 1; /* All channels. */
}
-void register_node_type_cmp_view_levels(void)
+static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "channel", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_view_levels()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_levels_declare;
+ ntype.draw_buttons = node_composit_buts_view_levels;
node_type_init(&ntype, node_composit_init_view_levels);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
index 600406d22b9..f5193bd5df2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
@@ -21,19 +21,23 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Luma Matte Node ********************************* */
-static bNodeSocketTemplate cmp_node_luma_matte_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_luma_matte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Matte"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -43,12 +47,24 @@ static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node)
c->t2 = 0.0f;
}
-void register_node_type_cmp_luma_matte(void)
+static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(
+ col, ptr, "limit_max", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_luma_matte()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_luma_matte_in, cmp_node_luma_matte_out);
+ ntype.declare = blender::nodes::cmp_node_luma_matte_declare;
+ ntype.draw_buttons = node_composit_buts_luma_matte;
node_type_init(&ntype, node_composit_init_luma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
index 808ad538e55..1ae80f68dfd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
@@ -21,28 +21,42 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* **************** MAP VALUE ******************** */
-static bNodeSocketTemplate cmp_node_map_range_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("From Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_map_range_out[] = {
- {SOCK_FLOAT, N_("Value")},
- {-1, ""},
-};
-
-void register_node_type_cmp_map_range(void)
+/* **************** Map Range ******************** */
+
+namespace blender::nodes {
+
+static void cmp_node_map_range_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("From Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("From Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("To Max")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_clamp", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_map_range()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_map_range_in, cmp_node_map_range_out);
+ ntype.declare = blender::nodes::cmp_node_map_range_declare;
+ ntype.draw_buttons = node_composit_buts_map_range;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
index 99032bd042e..71446e3a3c4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
@@ -21,26 +21,36 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Map UV ******************** */
-static bNodeSocketTemplate cmp_node_mapuv_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_VECTOR, N_("UV"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_mapuv_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_mapuv(void)
+namespace blender::nodes {
+
+static void cmp_node_map_uv_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("UV")).default_value({1.0f, 0.0f, 0.0f}).min(0.0f).max(1.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_mapuv()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_mapuv_in, cmp_node_mapuv_out);
+ ntype.declare = blender::nodes::cmp_node_map_uv_declare;
+ ntype.draw_buttons = node_composit_buts_map_uv;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
index 25c00c2ba13..4bd9124fa68 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
@@ -21,29 +21,58 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** MAP VALUE ******************** */
-static bNodeSocketTemplate cmp_node_map_value_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_map_value_out[] = {
- {SOCK_FLOAT, N_("Value")},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_map_value_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
}
-void register_node_type_cmp_map_value(void)
+static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *sub, *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_min", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
+ uiItemR(sub, ptr, "min", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
+ uiItemR(sub, ptr, "max", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_map_value()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_map_value_in, cmp_node_map_value_out);
+ ntype.declare = blender::nodes::cmp_node_map_value_declare;
+ ntype.draw_buttons = node_composit_buts_map_value;
node_type_init(&ntype, node_composit_init_map_value);
node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc
index 6428fadaa5f..8cbf526a289 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc
@@ -23,6 +23,9 @@
#include "DNA_mask_types.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Mask ******************** */
@@ -46,7 +49,10 @@ static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
node->custom3 = 0.5f; /* shutter */
}
-static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_mask_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
if (node->id != nullptr) {
BLI_strncpy(label, node->id->name + 2, maxlen);
@@ -56,14 +62,45 @@ static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label,
}
}
-void register_node_type_cmp_mask(void)
+static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "mask",
+ nullptr,
+ nullptr,
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+ uiItemR(layout, ptr, "use_feather", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "size_source", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
+ uiItemR(layout, ptr, "size_x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "size_y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
+ uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_mask()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0);
ntype.declare = blender::nodes::cmp_node_mask_declare;
+ ntype.draw_buttons = node_composit_buts_mask;
node_type_init(&ntype, node_composit_init_mask);
- node_type_label(&ntype, node_mask_label);
+ ntype.labelfunc = node_mask_label;
node_type_storage(&ntype, "NodeMask", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_math.cc b/source/blender/nodes/composite/nodes/node_composite_math.cc
index ecddcc2ad32..b34cfab5eb5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_math.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_math.cc
@@ -24,21 +24,32 @@
#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-static bNodeSocketTemplate cmp_node_math_in[] = {
- {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_math_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
+namespace blender::nodes {
-void register_node_type_cmp_math(void)
+static void cmp_node_math_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(0.5f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_001")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_input<decl::Float>(N_("Value"), "Value_002")
+ .default_value(0.5f)
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_math()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, cmp_node_math_in, cmp_node_math_out);
- node_type_label(&ntype, node_math_label);
+ ntype.declare = blender::nodes::cmp_node_math_declare;
+ ntype.labelfunc = node_math_label;
node_type_update(&ntype, node_math_update);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
index 557116f5b7a..4432b031ee7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
@@ -25,25 +25,26 @@
/* **************** MIX RGB ******************** */
-static bNodeSocketTemplate cmp_node_mix_rgb_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_mix_rgb_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_mixrgb_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
/* custom1 = mix type */
-void register_node_type_cmp_mix_rgb(void)
+void register_node_type_cmp_mix_rgb()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_mix_rgb_in, cmp_node_mix_rgb_out);
- node_type_label(&ntype, node_blend_label);
+ ntype.declare = blender::nodes::cmp_node_mixrgb_declare;
+ ntype.labelfunc = node_blend_label;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
index 5d63a1b8002..47a2c89a2f9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
@@ -21,11 +21,16 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
namespace blender::nodes {
static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b)
@@ -53,12 +58,53 @@ static void init(const bContext *C, PointerRNA *ptr)
user->framenr = 1;
}
-void register_node_type_cmp_movieclip(void)
+static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+}
+
+static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ PointerRNA clipptr;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ clipptr = RNA_pointer_get(ptr, "clip");
+
+ uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings");
+}
+
+void register_node_type_cmp_movieclip()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_movieclip_declare;
+ ntype.draw_buttons = node_composit_buts_movieclip;
+ ntype.draw_buttons_ex = node_composit_buts_movieclip_ex;
ntype.initfunc_api = init;
node_type_storage(
&ntype, "MovieClipUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
index 2bac30cc152..e7d9cac7c1a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
@@ -21,24 +21,27 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** Translate ******************** */
-static bNodeSocketTemplate cmp_node_moviedistortion_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_moviedistortion_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
-static bNodeSocketTemplate cmp_node_moviedistortion_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+} // namespace blender::nodes
-static void label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
if (node->custom1 == 0) {
BLI_strncpy(label, IFACE_("Undistortion"), maxlen);
@@ -73,14 +76,36 @@ static void storage_copy(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const
}
}
-void register_node_type_cmp_moviedistortion(void)
+static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ uiItemR(layout, ptr, "distortion_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_moviedistortion()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_moviedistortion_in, cmp_node_moviedistortion_out);
- node_type_label(&ntype, label);
-
+ ntype.declare = blender::nodes::cmp_node_moviedistortion_declare;
+ ntype.draw_buttons = node_composit_buts_moviedistortion;
+ ntype.labelfunc = label;
ntype.initfunc_api = init;
node_type_storage(&ntype, nullptr, storage_free, storage_copy);
diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc
index 7531025daa5..b541761a8cc 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc
@@ -24,23 +24,28 @@
#include "node_composite_util.hh"
/* **************** NORMAL ******************** */
-static bNodeSocketTemplate cmp_node_normal_in[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_normal_out[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {SOCK_FLOAT, N_("Dot")},
- {-1, ""},
-};
-
-void register_node_type_cmp_normal(void)
+
+namespace blender::nodes {
+
+static void cmp_node_normal_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Normal"))
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_DIRECTION);
+ b.add_output<decl::Vector>(N_("Normal"));
+ b.add_output<decl::Float>(N_("Dot"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_normal()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_normal_in, cmp_node_normal_out);
+ ntype.declare = blender::nodes::cmp_node_normal_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
index 7cc54e4eed6..dd3939fa6e2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
@@ -24,16 +24,23 @@
#include "node_composite_util.hh"
/* **************** NORMALIZE single channel, useful for Z buffer ******************** */
-static bNodeSocketTemplate cmp_node_normalize_in[] = {
- {SOCK_FLOAT, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_normalize_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
-void register_node_type_cmp_normalize(void)
+namespace blender::nodes {
+
+static void cmp_node_normalize_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_normalize()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, cmp_node_normalize_in, cmp_node_normalize_out);
+ ntype.declare = blender::nodes::cmp_node_normalize_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
index a372d2f7419..79074375a23 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
@@ -21,14 +21,21 @@
* \ingroup cmpnodes
*/
+#include <cstring>
+
+#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include <cstring>
#include "BKE_context.h"
#include "RNA_access.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+
#include "node_composite_util.hh"
#include "intern/openexr/openexr_multi.h"
@@ -275,12 +282,169 @@ static void update_output_file(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_cmp_output_file(void)
+static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ PointerRNA imfptr = RNA_pointer_get(ptr, "format");
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+
+ if (multilayer) {
+ uiItemL(layout, IFACE_("Path:"), ICON_NONE);
+ }
+ else {
+ uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
+ }
+ uiItemR(layout, ptr, "base_path", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA imfptr = RNA_pointer_get(ptr, "format");
+ PointerRNA active_input_ptr, op_ptr;
+ uiLayout *row, *col;
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+ const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ node_composit_buts_file_output(layout, C, ptr);
+ uiTemplateImageSettings(layout, &imfptr, false);
+
+ /* disable stereo output for multilayer, too much work for something that no one will use */
+ /* if someone asks for that we can implement it */
+ if (is_multiview) {
+ uiTemplateImageFormatViews(layout, &imfptr, nullptr);
+ }
+
+ uiItemS(layout);
+
+ uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket");
+
+ row = uiLayoutRow(layout, false);
+ col = uiLayoutColumn(row, true);
+
+ const int active_index = RNA_int_get(ptr, "active_input_index");
+ /* using different collection properties if multilayer format is enabled */
+ if (multilayer) {
+ uiTemplateList(col,
+ C,
+ "UI_UL_list",
+ "file_output_node",
+ ptr,
+ "layer_slots",
+ ptr,
+ "active_input_index",
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+ RNA_property_collection_lookup_int(
+ ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
+ }
+ else {
+ uiTemplateList(col,
+ C,
+ "UI_UL_list",
+ "file_output_node",
+ ptr,
+ "file_slots",
+ ptr,
+ "active_input_index",
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+ RNA_property_collection_lookup_int(
+ ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
+ }
+ /* XXX collection lookup does not return the ID part of the pointer,
+ * setting this manually here */
+ active_input_ptr.owner_id = ptr->owner_id;
+
+ col = uiLayoutColumn(row, true);
+ wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false);
+ uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_enum_set(&op_ptr, "direction", 1);
+ uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_enum_set(&op_ptr, "direction", 2);
+
+ if (active_input_ptr.data) {
+ if (multilayer) {
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(col, IFACE_("Layer:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, &active_input_ptr, "name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemFullO(row,
+ "NODE_OT_output_file_remove_active_socket",
+ "",
+ ICON_X,
+ nullptr,
+ WM_OP_EXEC_DEFAULT,
+ UI_ITEM_R_ICON_ONLY,
+ nullptr);
+ }
+ else {
+ col = uiLayoutColumn(layout, true);
+
+ uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, &active_input_ptr, "path", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemFullO(row,
+ "NODE_OT_output_file_remove_active_socket",
+ "",
+ ICON_X,
+ nullptr,
+ WM_OP_EXEC_DEFAULT,
+ UI_ITEM_R_ICON_ONLY,
+ nullptr);
+
+ /* format details for individual files */
+ imfptr = RNA_pointer_get(&active_input_ptr, "format");
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Format:"), ICON_NONE);
+ uiItemR(col,
+ &active_input_ptr,
+ "use_node_format",
+ UI_ITEM_R_SPLIT_EMPTY_NAME,
+ nullptr,
+ ICON_NONE);
+
+ const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
+ const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format");
+
+ if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) {
+ uiItemR(col,
+ &active_input_ptr,
+ "save_as_render",
+ UI_ITEM_R_SPLIT_EMPTY_NAME,
+ nullptr,
+ ICON_NONE);
+ }
+
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, use_node_format == false);
+ uiTemplateImageSettings(col, &imfptr, false);
+
+ if (is_multiview) {
+ uiTemplateImageFormatViews(layout, &imfptr, nullptr);
+ }
+ }
+ }
+}
+
+void register_node_type_cmp_output_file()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, nullptr, nullptr);
+ ntype.draw_buttons = node_composit_buts_file_output;
+ ntype.draw_buttons_ex = node_composit_buts_file_output_ex;
ntype.initfunc_api = init_output_file;
node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file);
node_type_update(&ntype, update_output_file);
diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index 19975c21a0b..3679aada759 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -25,16 +25,22 @@
/* **************** Pixelate ******************** */
-static bNodeSocketTemplate cmp_node_pixelate_in[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
-static bNodeSocketTemplate cmp_node_pixelate_out[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}};
+namespace blender::nodes {
-void register_node_type_cmp_pixelate(void)
+static void cmp_node_pixelate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color"));
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_pixelate()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_pixelate_in, cmp_node_pixelate_out);
+ ntype.declare = blender::nodes::cmp_node_pixelate_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
index e122b710b7b..d9d362f5175 100644
--- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
@@ -21,16 +21,23 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_planetrackdeform_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image"));
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Plane"));
+}
-static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Plane")},
- {-1, ""},
-};
+} // namespace blender::nodes
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,13 +48,63 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_planetrackdeform(void)
+static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+
+ object = BKE_tracking_object_get_named(tracking, data->tracking_object);
+ if (object) {
+ PointerRNA object_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
+
+ uiItemPointerR(
+ col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA);
+ }
+ else {
+ uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
+ }
+ }
+
+ uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
+ uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_planetrackdeform()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_planetrackdeform_in, cmp_node_planetrackdeform_out);
+ ntype.declare = blender::nodes::cmp_node_planetrackdeform_declare;
+ ntype.draw_buttons = node_composit_buts_planetrackdeform;
node_type_init(&ntype, init);
node_type_storage(
&ntype, "NodePlaneTrackDeformData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_posterize.cc b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
index 45a98e68b4b..8437c72e76c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_posterize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
@@ -25,22 +25,23 @@
/* **************** Posterize ******************** */
-static bNodeSocketTemplate cmp_node_posterize_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Steps"), 8.0f, 8.0f, 8.0f, 8.0f, 2.0f, 1024.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_posterize_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_posterize(void)
+namespace blender::nodes {
+
+static void cmp_node_posterize_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Steps")).default_value(8.0f).min(2.0f).max(1024.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_posterize()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_posterize_in, cmp_node_posterize_out);
+ ntype.declare = blender::nodes::cmp_node_posterize_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
index 49068429a8d..a70adf68692 100644
--- a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Premul and Key Alpha Convert ******************** */
@@ -35,12 +38,18 @@ static void cmp_node_premulkey_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_premulkey(void)
+static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mapping", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_premulkey()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::cmp_node_premulkey_declare;
+ ntype.draw_buttons = node_composit_buts_premulkey;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
index abe69d6a756..54f152d1cd0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
@@ -34,7 +34,7 @@ static void cmp_node_rgb_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_rgb(void)
+void register_node_type_cmp_rgb()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.cc b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
index d28b35ec9fb..cc1589a47ca 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rotate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
@@ -21,31 +21,45 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Rotate ******************** */
-static bNodeSocketTemplate cmp_node_rotate_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Degr"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_rotate_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_rotate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Degr"))
+ .default_value(0.0f)
+ .min(-10000.0f)
+ .max(10000.0f)
+ .subtype(PROP_ANGLE);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_rotate(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* Bilinear Filter. */
}
-void register_node_type_cmp_rotate(void)
+static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_rotate()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_rotate_in, cmp_node_rotate_out);
+ ntype.declare = blender::nodes::cmp_node_rotate_declare;
+ ntype.draw_buttons = node_composit_buts_rotate;
node_type_init(&ntype, node_composit_init_rotate);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc
index 284d16b9b0d..98c9f6619f4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scale.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc
@@ -21,16 +21,26 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Scale ******************** */
-static bNodeSocketTemplate cmp_node_scale_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_NONE},
- {SOCK_FLOAT, N_("Y"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX, PROP_NONE},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_scale_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+namespace blender::nodes {
+
+static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_input<decl::Float>(N_("Y")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
{
@@ -45,12 +55,31 @@ static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_cmp_scale(void)
+static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
+ uiLayout *row;
+ uiItemR(layout,
+ ptr,
+ "frame_method",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "offset_x", UI_ITEM_R_SPLIT_EMPTY_NAME, "X", ICON_NONE);
+ uiItemR(row, ptr, "offset_y", UI_ITEM_R_SPLIT_EMPTY_NAME, "Y", ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_scale()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_scale_in, cmp_node_scale_out);
+ ntype.declare = blender::nodes::cmp_node_scale_declare;
+ ntype.draw_buttons = node_composit_buts_scale;
node_type_update(&ntype, node_composite_update_scale);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
index 83c54069658..9eafc0e3594 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
@@ -38,7 +38,7 @@ static void cmp_node_sephsva_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_sephsva(void)
+void register_node_type_cmp_sephsva()
{
static bNodeType ntype;
@@ -62,7 +62,7 @@ static void cmp_node_combhsva_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_combhsva(void)
+void register_node_type_cmp_combhsva()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
index 049e798af0a..e81ea6f31be 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
@@ -37,7 +37,7 @@ static void cmp_node_seprgba_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_seprgba(void)
+void register_node_type_cmp_seprgba()
{
static bNodeType ntype;
@@ -62,7 +62,7 @@ static void cmp_node_combrgba_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_combrgba(void)
+void register_node_type_cmp_combrgba()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
index eaf6ba5e9b2..15c8efc2ef8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
@@ -43,7 +43,7 @@ static void node_composit_init_mode_sepycca(bNodeTree *UNUSED(ntree), bNode *nod
node->custom1 = 1; /* BLI_YCC_ITU_BT709 */
}
-void register_node_type_cmp_sepycca(void)
+void register_node_type_cmp_sepycca()
{
static bNodeType ntype;
@@ -74,7 +74,7 @@ static void node_composit_init_mode_combycca(bNodeTree *UNUSED(ntree), bNode *no
node->custom1 = 1; /* BLI_YCC_ITU_BT709 */
}
-void register_node_type_cmp_combycca(void)
+void register_node_type_cmp_combycca()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
index bc7710122d1..4d4b01c2fb3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
@@ -38,7 +38,7 @@ static void cmp_node_sepyuva_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_sepyuva(void)
+void register_node_type_cmp_sepyuva()
{
static bNodeType ntype;
@@ -63,7 +63,7 @@ static void cmp_node_combyuva_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_combyuva(void)
+void register_node_type_cmp_combyuva()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
index f59ba76f0c5..3e66f884efd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
@@ -21,6 +21,9 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** SET ALPHA ******************** */
@@ -43,12 +46,18 @@ static void node_composit_init_setalpha(bNodeTree *UNUSED(ntree), bNode *node)
settings->mode = CMP_NODE_SETALPHA_MODE_APPLY;
}
-void register_node_type_cmp_setalpha(void)
+static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_setalpha()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::cmp_node_setalpha_declare;
+ ntype.draw_buttons = node_composit_buts_set_alpha;
node_type_init(&ntype, node_composit_init_setalpha);
node_type_storage(
&ntype, "NodeSetAlpha", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
index c0403a041db..63772a52840 100644
--- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
@@ -21,17 +21,25 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_global.h"
#include "BKE_image.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** SPLIT VIEWER ******************** */
-static bNodeSocketTemplate cmp_node_splitviewer_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+
+namespace blender::nodes {
+
+static void cmp_node_split_viewer_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image"));
+ b.add_input<decl::Color>(N_("Image"), "Image_001");
+}
+
+} // namespace blender::nodes
static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -43,13 +51,24 @@ static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node
node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node");
}
-void register_node_type_cmp_splitviewer(void)
+static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row, *col;
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, false);
+ uiItemR(row, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_splitviewer()
{
static bNodeType ntype;
cmp_node_type_base(
&ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, cmp_node_splitviewer_in, nullptr);
+ ntype.declare = blender::nodes::cmp_node_split_viewer_declare;
+ ntype.draw_buttons = node_composit_buts_splitviewer;
node_type_init(&ntype, node_composit_init_splitviewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
index e5ce2e8ceb9..de6cc21ccd5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
@@ -21,22 +21,25 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
-/* **************** Translate ******************** */
+#include "node_composite_util.hh"
-static bNodeSocketTemplate cmp_node_stabilize2d_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+/* **************** Stabilize 2D ******************** */
-static bNodeSocketTemplate cmp_node_stabilize2d_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_stabilize2d_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void init(const bContext *C, PointerRNA *ptr)
{
@@ -50,12 +53,36 @@ static void init(const bContext *C, PointerRNA *ptr)
node->custom1 = 1;
}
-void register_node_type_cmp_stabilize2d(void)
+static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (!node->id) {
+ return;
+ }
+
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "invert", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_stabilize2d()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_stabilize2d_in, cmp_node_stabilize2d_out);
+ ntype.declare = blender::nodes::cmp_node_stabilize2d_declare;
+ ntype.draw_buttons = node_composit_buts_stabilize2d;
ntype.initfunc_api = init;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
index 73907d2e27f..f5d69c7d17b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
@@ -21,16 +21,20 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-static bNodeSocketTemplate inputs[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate outputs[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+namespace blender::nodes {
+
+static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -41,12 +45,24 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_sunbeams(void)
+static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "source", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, "", ICON_NONE);
+ uiItemR(layout,
+ ptr,
+ "ray_length",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ nullptr,
+ ICON_NONE);
+}
+
+void register_node_type_cmp_sunbeams()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, inputs, outputs);
+ ntype.declare = blender::nodes::cmp_node_sunbeams_declare;
+ ntype.draw_buttons = node_composit_buts_sunbeams;
node_type_init(&ntype, init);
node_type_storage(
&ntype, "NodeSunBeams", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_switch.cc b/source/blender/nodes/composite/nodes/node_composite_switch.cc
index 71226a6da0b..d13bcc28d10 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switch.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switch.cc
@@ -21,27 +21,37 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
-/* **************** MIX RGB ******************** */
-static bNodeSocketTemplate cmp_node_switch_in[] = {
- {SOCK_RGBA, N_("Off"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("On"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+/* **************** Switch ******************** */
+
+namespace blender::nodes {
+
+static void cmp_node_switch_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Off")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("On")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
-static bNodeSocketTemplate cmp_node_switch_out[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "check", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
/* custom1 = mix type */
-void register_node_type_cmp_switch(void)
+void register_node_type_cmp_switch()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT, 0);
- node_type_socket_templates(&ntype, cmp_node_switch_in, cmp_node_switch_out);
+ ntype.declare = blender::nodes::cmp_node_switch_declare;
+ ntype.draw_buttons = node_composit_buts_switch;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.cc b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
index a61712f7f8d..159d66fc6cc 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switchview.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
@@ -25,9 +25,13 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "../node_composite_util.hh"
/* **************** SWITCH VIEW ******************** */
+
static bNodeSocketTemplate cmp_node_switch_view_out[] = {
{SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
{-1, ""},
@@ -137,13 +141,27 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr)
cmp_node_switch_view_sanitycheck(ntree, node);
}
-void register_node_type_cmp_switch_view(void)
+static void node_composit_buts_switch_view_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr))
+{
+ uiItemFullO(layout,
+ "NODE_OT_switch_view_update",
+ "Update Views",
+ ICON_FILE_REFRESH,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ nullptr);
+}
+
+void register_node_type_cmp_switch_view()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER, 0);
node_type_socket_templates(&ntype, nullptr, cmp_node_switch_view_out);
-
+ ntype.draw_buttons_ex = node_composit_buts_switch_view_ex;
ntype.initfunc_api = init_switch_view;
node_type_update(&ntype, cmp_node_switch_view_update);
diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc
index 55ae6a4185e..5e5fca755b2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_texture.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc
@@ -41,7 +41,7 @@ static void cmp_node_texture_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_texture(void)
+void register_node_type_cmp_texture()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
index 33d6f98201c..c6015eda08c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
@@ -21,6 +21,11 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
namespace blender::nodes {
@@ -49,12 +54,35 @@ static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ntm;
}
-void register_node_type_cmp_tonemap(void)
+static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "tonemap_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ if (RNA_enum_get(ptr, "tonemap_type") == 0) {
+ uiItemR(col, ptr, "key", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+ uiItemR(col, ptr, "intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "contrast", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "adaptation", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ uiItemR(
+ col, ptr, "correction", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_tonemap()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::cmp_node_tonemap_declare;
+ ntype.draw_buttons = node_composit_buts_tonemap;
node_type_init(&ntype, node_composit_init_tonemap);
node_type_storage(&ntype, "NodeTonemap", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
index 537f7e661db..3be52820f15 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
@@ -21,6 +21,11 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
namespace blender::nodes {
@@ -42,12 +47,61 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_trackpos(void)
+static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "clip",
+ nullptr,
+ "CLIP_OT_open",
+ nullptr,
+ UI_TEMPLATE_ID_FILTER_ALL,
+ false,
+ nullptr);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *)node->id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+ NodeTrackPosData *data = (NodeTrackPosData *)node->storage;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+
+ object = BKE_tracking_object_get_named(tracking, data->tracking_object);
+ if (object) {
+ PointerRNA object_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
+
+ uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
+ }
+ else {
+ uiItemR(layout, ptr, "track_name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_ANIM_DATA);
+ }
+
+ uiItemR(layout, ptr, "position", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
+ uiItemR(layout, ptr, "frame_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ }
+}
+
+void register_node_type_cmp_trackpos()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT, 0);
ntype.declare = blender::nodes::cmp_node_trackpos_declare;
+ ntype.draw_buttons = node_composit_buts_trackpos;
node_type_init(&ntype, init);
node_type_storage(
&ntype, "NodeTrackPosData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_transform.cc b/source/blender/nodes/composite/nodes/node_composite_transform.cc
index 1695101cdbf..ad1cc4cd308 100644
--- a/source/blender/nodes/composite/nodes/node_composite_transform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc
@@ -21,30 +21,43 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Transform ******************** */
-static bNodeSocketTemplate cmp_node_transform_in[] = {
- {SOCK_RGBA, N_("Image"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
- {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_ANGLE},
- {SOCK_FLOAT, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX},
- {-1, ""},
-};
-
-static bNodeSocketTemplate cmp_node_transform_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
-
-void register_node_type_cmp_transform(void)
+namespace blender::nodes {
+
+static void cmp_node_transform_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Y")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Angle"))
+ .default_value(0.0f)
+ .min(-10000.0f)
+ .max(10000.0f)
+ .subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "filter_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+void register_node_type_cmp_transform()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_transform_in, cmp_node_transform_out);
+ ntype.declare = blender::nodes::cmp_node_transform_declare;
+ ntype.draw_buttons = node_composit_buts_transform;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_translate.cc b/source/blender/nodes/composite/nodes/node_composite_translate.cc
index 0ee8a41a5ea..ce29cc55ca2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_translate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_translate.cc
@@ -21,20 +21,24 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-/* **************** Translate ******************** */
+/* **************** Translate ******************** */
+
+namespace blender::nodes {
+
+static void cmp_node_translate_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("X")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("Y")).default_value(0.0f).min(-10000.0f).max(10000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+}
-static bNodeSocketTemplate cmp_node_translate_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("X"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Y"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_translate_out[] = {
- {SOCK_RGBA, N_("Image")},
- {-1, ""},
-};
+} // namespace blender::nodes
static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -43,12 +47,19 @@ static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-void register_node_type_cmp_translate(void)
+static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "wrap_axis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_translate()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
- node_type_socket_templates(&ntype, cmp_node_translate_in, cmp_node_translate_out);
+ ntype.declare = blender::nodes::cmp_node_translate_declare;
+ ntype.draw_buttons = node_composit_buts_translate;
node_type_init(&ntype, node_composit_init_translate);
node_type_storage(
&ntype, "NodeTranslateData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
index a0ab056e657..dca6c9c141c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
@@ -41,7 +41,7 @@ static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = BKE_colorband_add(true);
}
-void register_node_type_cmp_valtorgb(void)
+void register_node_type_cmp_valtorgb()
{
static bNodeType ntype;
@@ -66,7 +66,7 @@ static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_rgbtobw(void)
+void register_node_type_cmp_rgbtobw()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_value.cc b/source/blender/nodes/composite/nodes/node_composite_value.cc
index 51214d23472..d2274d2d82a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_value.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_value.cc
@@ -34,7 +34,7 @@ static void cmp_node_value_declare(NodeDeclarationBuilder &b)
} // namespace blender::nodes
-void register_node_type_cmp_value(void)
+void register_node_type_cmp_value()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
index ce6ba659609..c4bea269670 100644
--- a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
@@ -21,15 +21,28 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** VECTOR BLUR ******************** */
-static bNodeSocketTemplate cmp_node_vecblur_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_VECTOR, N_("Speed"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_VELOCITY},
- {-1, ""}};
-static bNodeSocketTemplate cmp_node_vecblur_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}};
+
+namespace blender::nodes {
+
+static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(0.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Vector>(N_("Speed"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_VELOCITY);
+ b.add_output<decl::Color>(N_("Image"));
+}
+
+} // namespace blender::nodes
static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -39,13 +52,30 @@ static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
nbd->fac = 1.0f;
}
+static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "factor", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Blur"), ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("Speed:"), ICON_NONE);
+ uiItemR(col, ptr, "speed_min", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Min"), ICON_NONE);
+ uiItemR(col, ptr, "speed_max", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Max"), ICON_NONE);
+
+ uiItemR(layout, ptr, "use_curved", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
/* custom1: iterations, custom2: max_speed (0 = no_limit). */
-void register_node_type_cmp_vecblur(void)
+void register_node_type_cmp_vecblur()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER, 0);
- node_type_socket_templates(&ntype, cmp_node_vecblur_in, cmp_node_vecblur_out);
+ ntype.declare = blender::nodes::cmp_node_vec_blur_declare;
+ ntype.draw_buttons = node_composit_buts_vecblur;
node_type_init(&ntype, node_composit_init_vecblur);
node_type_storage(
&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
index 90f9882099b..fcebda3b8a4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
@@ -21,11 +21,16 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_global.h"
#include "BKE_image.h"
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
/* **************** VIEWER ******************** */
namespace blender::nodes {
@@ -50,12 +55,32 @@ static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node)
node->id = (ID *)BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node");
}
-void register_node_type_cmp_viewer(void)
+static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ uiItemR(layout, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "tile_order", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (RNA_enum_get(ptr, "tile_order") == 0) {
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
+
+void register_node_type_cmp_viewer()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
ntype.declare = blender::nodes::cmp_node_viewer_declare;
+ ntype.draw_buttons = node_composit_buts_viewer;
+ ntype.draw_buttons_ex = node_composit_buts_viewer_ex;
node_type_init(&ntype, node_composit_init_viewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
index 990f9fcd366..dd6872e4dd9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
@@ -21,29 +21,43 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Z COMBINE ******************** */
-/* lazy coder NOTE: node->custom2 is abused to send signal. */
-static bNodeSocketTemplate cmp_node_zcombine_in[] = {
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
- {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
- {-1, ""},
-};
-static bNodeSocketTemplate cmp_node_zcombine_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Z")},
- {-1, ""},
-};
-
-void register_node_type_cmp_zcombine(void)
+
+namespace blender::nodes {
+
+static void cmp_node_zcombine_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.f).max(10000.0f);
+ b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Z"), "Z_001").default_value(1.0f).min(0.f).max(10000.0f);
+ b.add_output<decl::Color>(N_("Image"));
+ b.add_output<decl::Float>(N_("Z"));
+}
+
+} // namespace blender::nodes
+
+static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "use_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "use_antialias_z", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+void register_node_type_cmp_zcombine()
{
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, cmp_node_zcombine_in, cmp_node_zcombine_out);
+ ntype.declare = blender::nodes::cmp_node_zcombine_declare;
+ ntype.draw_buttons = node_composit_buts_zcombine;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
index a1493d51a11..83f5b571695 100644
--- a/source/blender/nodes/function/node_function_util.cc
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -17,13 +17,15 @@
#include "node_function_util.hh"
#include "node_util.h"
+#include "NOD_socket_search_link.hh"
+
static bool fn_node_poll_default(bNodeType *UNUSED(ntype),
bNodeTree *ntree,
const char **r_disabled_hint)
{
/* Function nodes are only supported in simulation node trees so far. */
if (!STREQ(ntree->idname, "GeometryNodeTree")) {
- *r_disabled_hint = "Not a geometry node tree";
+ *r_disabled_hint = TIP_("Not a geometry node tree");
return false;
}
return true;
@@ -34,4 +36,5 @@ void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclas
node_type_base(ntype, type, name, nclass, flag);
ntype->poll = fn_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
index ed03cc0025d..4b59b49c632 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -47,7 +47,10 @@ static void node_boolean_math_update(bNodeTree *ntree, bNode *node)
ntree, sockB, ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR));
}
-static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_boolean_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_boolean_math_items, node->custom1, &name);
@@ -92,7 +95,7 @@ void register_node_type_fn_boolean_math()
fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::fn_node_boolean_math_declare;
- node_type_label(&ntype, blender::nodes::node_boolean_math_label);
+ ntype.labelfunc = blender::nodes::node_boolean_math_label;
node_type_update(&ntype, blender::nodes::node_boolean_math_update);
ntype.build_multi_function = blender::nodes::fn_node_boolean_math_build_multi_function;
ntype.draw_buttons = blender::nodes::fn_node_boolean_math_layout;
diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc
new file mode 100644
index 00000000000..e773563ca5f
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_compare.cc
@@ -0,0 +1,540 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <cmath>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_enum_types.h"
+
+#include "node_function_util.hh"
+
+#include "NOD_socket_search_link.hh"
+
+namespace blender::nodes::node_fn_compare_cc {
+
+NODE_STORAGE_FUNCS(NodeFunctionCompare)
+
+static void fn_node_compare_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("A")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("B")).min(-10000.0f).max(10000.0f);
+
+ b.add_input<decl::Int>(N_("A"), "A_INT");
+ b.add_input<decl::Int>(N_("B"), "B_INT");
+
+ b.add_input<decl::Vector>(N_("A"), "A_VEC3");
+ b.add_input<decl::Vector>(N_("B"), "B_VEC3");
+
+ b.add_input<decl::Color>(N_("A"), "A_COL");
+ b.add_input<decl::Color>(N_("B"), "B_COL");
+
+ b.add_input<decl::String>(N_("A"), "A_STR");
+ b.add_input<decl::String>(N_("B"), "B_STR");
+
+ b.add_input<decl::Float>(N_("C")).default_value(0.9f);
+ b.add_input<decl::Float>(N_("Angle")).default_value(0.0872665f).subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("Epsilon")).default_value(0.001).min(-10000.0f).max(10000.0f);
+
+ b.add_output<decl::Bool>(N_("Result"));
+};
+
+static void geo_node_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ const NodeFunctionCompare &data = node_storage(*static_cast<const bNode *>(ptr->data));
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ if (data.data_type == SOCK_VECTOR) {
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ }
+ uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
+}
+
+static void node_compare_update(bNodeTree *ntree, bNode *node)
+{
+ NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+
+ bNodeSocket *sock_comp = (bNodeSocket *)BLI_findlink(&node->inputs, 10);
+ bNodeSocket *sock_angle = (bNodeSocket *)BLI_findlink(&node->inputs, 11);
+ bNodeSocket *sock_epsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 12);
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == (eNodeSocketDatatype)data->data_type);
+ }
+
+ nodeSetSocketAvailability(ntree,
+ sock_epsilon,
+ ELEM(data->operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL) &&
+ !ELEM(data->data_type, SOCK_INT, SOCK_STRING));
+
+ nodeSetSocketAvailability(ntree,
+ sock_comp,
+ ELEM(data->mode, NODE_COMPARE_MODE_DOT_PRODUCT) &&
+ data->data_type == SOCK_VECTOR);
+
+ nodeSetSocketAvailability(ntree,
+ sock_angle,
+ ELEM(data->mode, NODE_COMPARE_MODE_DIRECTION) &&
+ data->data_type == SOCK_VECTOR);
+}
+
+static void node_compare_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(sizeof(NodeFunctionCompare),
+ __func__);
+ data->operation = NODE_COMPARE_GREATER_THAN;
+ data->data_type = SOCK_FLOAT;
+ data->mode = NODE_COMPARE_MODE_ELEMENT;
+ node->storage = data;
+}
+
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ eNodeSocketDatatype data_type;
+ NodeCompareOperation operation;
+ NodeCompareMode mode = NODE_COMPARE_MODE_ELEMENT;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("FunctionNodeCompare");
+ node_storage(node).data_type = data_type;
+ node_storage(node).operation = operation;
+ node_storage(node).mode = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_compare_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ return;
+ }
+
+ const eNodeSocketDatatype type = static_cast<eNodeSocketDatatype>(params.other_socket().type);
+
+ if (ELEM(type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_RGBA, SOCK_VECTOR, SOCK_INT)) {
+ params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_GREATER_THAN});
+ params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_GREATER_THAN});
+ params.add_item(
+ IFACE_("C"),
+ SocketSearchOp{
+ "C", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DOT_PRODUCT});
+ params.add_item(
+ IFACE_("Angle"),
+ SocketSearchOp{
+ "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION});
+ }
+ else if (type == SOCK_STRING) {
+ params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_EQUAL});
+ params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_EQUAL});
+ }
+}
+
+static void node_compare_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
+{
+ const NodeFunctionCompare *data = (NodeFunctionCompare *)node->storage;
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_compare_operation_items, data->operation, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+static float component_average(float3 a)
+{
+ return (a.x + a.y + a.z) / 3.0f;
+}
+
+static const fn::MultiFunction *get_multi_function(bNode &node)
+{
+ const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage;
+
+ switch (data->data_type) {
+ case SOCK_FLOAT:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Less Than", [](float a, float b) { return a < b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_LESS_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Less Equal", [](float a, float b) { return a <= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_THAN: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Greater Than", [](float a, float b) { return a > b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<float, float, bool> fn{
+ "Greater Equal", [](float a, float b) { return a >= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{
+ "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL:
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> fn{
+ "Not Equal",
+ [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }};
+ return &fn;
+ }
+ break;
+ case SOCK_INT:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Less Than",
+ [](int a, int b) { return a < b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_LESS_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Less Equal",
+ [](int a, int b) { return a <= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_THAN: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Greater Than",
+ [](int a, int b) { return a > b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_GREATER_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Greater Equal",
+ [](int a, int b) { return a >= b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Equal",
+ [](int a, int b) { return a == b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<int, int, bool> fn{"Not Equal",
+ [](int a, int b) { return a != b; }};
+ return &fn;
+ }
+ }
+ break;
+ case SOCK_VECTOR:
+ switch (data->operation) {
+ case NODE_COMPARE_LESS_THAN:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Average",
+ [](float3 a, float3 b) { return component_average(a) < component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Than - Dot Product",
+ [](float3 a, float3 b, float comp) { return float3::dot(a, b) < comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Than - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) < angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Element-wise",
+ [](float3 a, float3 b) { return a.x < b.x && a.y < b.y && a.z < b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Than - Length",
+ [](float3 a, float3 b) { return a.length() < b.length(); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_LESS_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Average",
+ [](float3 a, float3 b) { return component_average(a) <= component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Equal - Dot Product",
+ [](float3 a, float3 b, float comp) { return float3::dot(a, b) <= comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Less Equal - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) <= angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Element-wise",
+ [](float3 a, float3 b) { return a.x <= b.x && a.y <= b.y && a.z <= b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Less Equal - Length",
+ [](float3 a, float3 b) { return a.length() <= b.length(); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_GREATER_THAN:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Average",
+ [](float3 a, float3 b) { return component_average(a) > component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Than - Dot Product",
+ [](float3 a, float3 b, float comp) { return float3::dot(a, b) > comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Than - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) > angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Element-wise",
+ [](float3 a, float3 b) { return a.x > b.x && a.y > b.y && a.z > b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Than - Length",
+ [](float3 a, float3 b) { return a.length() > b.length(); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_GREATER_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Average",
+ [](float3 a, float3 b) { return component_average(a) >= component_average(b); }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Equal - Dot Product",
+ [](float3 a, float3 b, float comp) { return float3::dot(a, b) >= comp; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Greater Equal - Direction",
+ [](float3 a, float3 b, float angle) { return angle_v3v3(a, b) >= angle; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Element-wise",
+ [](float3 a, float3 b) { return a.x >= b.x && a.y >= b.y && a.z >= b.z; }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SO<float3, float3, bool> fn{
+ "Greater Equal - Length",
+ [](float3 a, float3 b) { return a.length() >= b.length(); }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Average", [](float3 a, float3 b, float epsilon) {
+ return abs(component_average(a) - component_average(b)) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Equal - Dot Product", [](float3 a, float3 b, float comp, float epsilon) {
+ return abs(float3::dot(a, b) - comp) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Equal - Direction", [](float3 a, float3 b, float angle, float epsilon) {
+ return abs(angle_v3v3(a, b) - angle) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Element-wise", [](float3 a, float3 b, float epsilon) {
+ return abs(a.x - b.x) <= epsilon && abs(a.y - b.y) <= epsilon &&
+ abs(a.z - b.z) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Equal - Length", [](float3 a, float3 b, float epsilon) {
+ return abs(a.length() - b.length()) <= epsilon;
+ }};
+ return &fn;
+ }
+ }
+ break;
+ case NODE_COMPARE_NOT_EQUAL:
+ switch (data->mode) {
+ case NODE_COMPARE_MODE_AVERAGE: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Average", [](float3 a, float3 b, float epsilon) {
+ return abs(component_average(a) - component_average(b)) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DOT_PRODUCT: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Not Equal - Dot Product", [](float3 a, float3 b, float comp, float epsilon) {
+ return abs(float3::dot(a, b) - comp) >= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_DIRECTION: {
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float, float, bool> fn{
+ "Not Equal - Direction", [](float3 a, float3 b, float angle, float epsilon) {
+ return abs(angle_v3v3(a, b) - angle) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_ELEMENT: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Element-wise", [](float3 a, float3 b, float epsilon) {
+ return abs(a.x - b.x) > epsilon && abs(a.y - b.y) > epsilon &&
+ abs(a.z - b.z) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_MODE_LENGTH: {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, bool> fn{
+ "Not Equal - Length", [](float3 a, float3 b, float epsilon) {
+ return abs(a.length() - b.length()) > epsilon;
+ }};
+ return &fn;
+ }
+ }
+ break;
+ }
+ break;
+ case SOCK_RGBA:
+ switch (data->operation) {
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
+ "Equal", [](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
+ return abs(a.r - b.r) <= epsilon && abs(a.g - b.g) <= epsilon &&
+ abs(a.b - b.b) <= epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, float, bool> fn{
+ "Not Equal", [](ColorGeometry4f a, ColorGeometry4f b, float epsilon) {
+ return abs(a.r - b.r) > epsilon && abs(a.g - b.g) > epsilon &&
+ abs(a.b - b.b) > epsilon;
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_COLOR_BRIGHTER: {
+ static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{
+ "Brighter", [](ColorGeometry4f a, ColorGeometry4f b) {
+ return rgb_to_grayscale(a) > rgb_to_grayscale(b);
+ }};
+ return &fn;
+ }
+ case NODE_COMPARE_COLOR_DARKER: {
+ static fn::CustomMF_SI_SI_SO<ColorGeometry4f, ColorGeometry4f, bool> fn{
+ "Darker", [](ColorGeometry4f a, ColorGeometry4f b) {
+ return rgb_to_grayscale(a) < rgb_to_grayscale(b);
+ }};
+ return &fn;
+ }
+ }
+ break;
+ case SOCK_STRING:
+ switch (data->operation) {
+ case NODE_COMPARE_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{
+ "Equal", [](std::string a, std::string b) { return a == b; }};
+ return &fn;
+ }
+ case NODE_COMPARE_NOT_EQUAL: {
+ static fn::CustomMF_SI_SI_SO<std::string, std::string, bool> fn{
+ "Not Equal", [](std::string a, std::string b) { return a != b; }};
+ return &fn;
+ }
+ }
+ break;
+ }
+ return nullptr;
+}
+
+static void fn_node_compare_build_multi_function(NodeMultiFunctionBuilder &builder)
+{
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
+ builder.set_matching_fn(fn);
+}
+
+} // namespace blender::nodes::node_fn_compare_cc
+
+void register_node_type_fn_compare()
+{
+ namespace file_ns = blender::nodes::node_fn_compare_cc;
+
+ static bNodeType ntype;
+ fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER, 0);
+ ntype.declare = file_ns::fn_node_compare_declare;
+ ntype.labelfunc = file_ns::node_compare_label;
+ node_type_update(&ntype, file_ns::node_compare_update);
+ node_type_init(&ntype, file_ns::node_compare_init);
+ node_type_storage(
+ &ntype, "NodeFunctionCompare", node_free_standard_storage, node_copy_standard_storage);
+ ntype.build_multi_function = file_ns::fn_node_compare_build_multi_function;
+ ntype.draw_buttons = file_ns::geo_node_compare_layout;
+ ntype.gather_link_search_ops = file_ns::node_compare_gather_link_searches;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
deleted file mode 100644
index b31611a1df2..00000000000
--- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <cmath>
-
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-
-#include "RNA_enum_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_function_util.hh"
-
-namespace blender::nodes {
-
-static void fn_node_float_compare_declare(NodeDeclarationBuilder &b)
-{
- b.is_function_node();
- b.add_input<decl::Float>(N_("A")).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("B")).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("Epsilon")).default_value(0.001f).min(-10000.0f).max(10000.0f);
- b.add_output<decl::Bool>(N_("Result"));
-};
-
-static void geo_node_float_compare_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
-}
-
-static void node_float_compare_update(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
-
- nodeSetSocketAvailability(
- ntree,
- sockEpsilon,
- ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL));
-}
-
-static void node_float_compare_label(bNodeTree *UNUSED(ntree),
- bNode *node,
- char *label,
- int maxlen)
-{
- const char *name;
- bool enum_label = RNA_enum_name(rna_enum_node_float_compare_items, node->custom1, &name);
- if (!enum_label) {
- name = "Unknown";
- }
- BLI_strncpy(label, IFACE_(name), maxlen);
-}
-
-static const fn::MultiFunction *get_multi_function(bNode &node)
-{
- static fn::CustomMF_SI_SI_SO<float, float, bool> less_than_fn{
- "Less Than", [](float a, float b) { return a < b; }};
- static fn::CustomMF_SI_SI_SO<float, float, bool> less_equal_fn{
- "Less Equal", [](float a, float b) { return a <= b; }};
- static fn::CustomMF_SI_SI_SO<float, float, bool> greater_than_fn{
- "Greater Than", [](float a, float b) { return a > b; }};
- static fn::CustomMF_SI_SI_SO<float, float, bool> greater_equal_fn{
- "Greater Equal", [](float a, float b) { return a >= b; }};
- static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> equal_fn{
- "Equal", [](float a, float b, float epsilon) { return std::abs(a - b) <= epsilon; }};
- static fn::CustomMF_SI_SI_SI_SO<float, float, float, bool> not_equal_fn{
- "Not Equal", [](float a, float b, float epsilon) { return std::abs(a - b) > epsilon; }};
-
- switch (node.custom1) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
- return &less_than_fn;
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
- return &less_equal_fn;
- case NODE_FLOAT_COMPARE_GREATER_THAN:
- return &greater_than_fn;
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
- return &greater_equal_fn;
- case NODE_FLOAT_COMPARE_EQUAL:
- return &equal_fn;
- case NODE_FLOAT_COMPARE_NOT_EQUAL:
- return &not_equal_fn;
- }
-
- BLI_assert_unreachable();
- return nullptr;
-}
-
-static void fn_node_float_compare_build_multi_function(NodeMultiFunctionBuilder &builder)
-{
- const fn::MultiFunction *fn = get_multi_function(builder.node());
- builder.set_matching_fn(fn);
-}
-
-} // namespace blender::nodes
-
-void register_node_type_fn_float_compare()
-{
- static bNodeType ntype;
-
- fn_node_type_base(&ntype, FN_NODE_COMPARE_FLOATS, "Compare Floats", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_float_compare_declare;
- node_type_label(&ntype, blender::nodes::node_float_compare_label);
- node_type_update(&ntype, blender::nodes::node_float_compare_update);
- ntype.build_multi_function = blender::nodes::fn_node_float_compare_build_multi_function;
- ntype.draw_buttons = blender::nodes::geo_node_float_compare_layout;
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
index e6ec925f945..21f6734e4aa 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -39,7 +39,10 @@ static void fn_node_float_to_int_layout(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "rounding_mode", 0, "", ICON_NONE);
}
-static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void node_float_to_int_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_float_to_int_items, node->custom1, &name);
@@ -86,7 +89,7 @@ void register_node_type_fn_float_to_int()
fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::fn_node_float_to_int_declare;
- node_type_label(&ntype, blender::nodes::node_float_to_int_label);
+ ntype.labelfunc = blender::nodes::node_float_to_int_label;
ntype.build_multi_function = blender::nodes::fn_node_float_to_int_build_multi_function;
ntype.draw_buttons = blender::nodes::fn_node_float_to_int_layout;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
index 9720a39b740..b053482c99d 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -19,11 +19,15 @@
#include "node_function_util.hh"
+#include "NOD_socket_search_link.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeRandomValue)
+
static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Vector>(N_("Min")).supports_field();
@@ -41,7 +45,8 @@ static void fn_node_random_value_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.default_value(0.5f)
.subtype(PROP_FACTOR)
- .supports_field();
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).data_type = CD_PROP_BOOL; });
b.add_input<decl::Int>(N_("ID")).implicit_field();
b.add_input<decl::Int>(N_("Seed")).default_value(0).min(-10000).max(10000).supports_field();
@@ -65,7 +70,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
static void fn_node_random_value_update(bNodeTree *ntree, bNode *node)
{
- const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage;
+ const NodeRandomValue &storage = node_storage(*node);
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first;
@@ -95,6 +100,55 @@ static void fn_node_random_value_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL);
}
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ return CD_PROP_FLOAT3;
+ case SOCK_RGBA:
+ return CD_PROP_COLOR;
+ default:
+ return {};
+ }
+}
+
+static void fn_node_random_value_gather_link_search(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+ if (params.in_out() == SOCK_IN) {
+ if (ELEM(*type, CD_PROP_INT32, CD_PROP_FLOAT3, CD_PROP_FLOAT)) {
+ params.add_item(IFACE_("Min"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Min");
+ });
+ params.add_item(IFACE_("Max"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Max");
+ });
+ }
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(3));
+ }
+ else {
+ params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeRandomValue");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+}
+
class RandomVectorFunction : public fn::MultiFunction {
public:
RandomVectorFunction()
@@ -203,14 +257,16 @@ class RandomIntFunction : public fn::MultiFunction {
const VArray<int> &seeds = params.readonly_single_input<int>(3, "Seed");
MutableSpan<int> values = params.uninitialized_single_output<int>(4, "Value");
+ /* Add one to the maximum and use floor to produce an even
+ * distribution for the first and last values (See T93591). */
for (int64_t i : mask) {
const float min_value = min_values[i];
- const float max_value = max_values[i];
+ const float max_value = max_values[i] + 1.0f;
const int seed = seeds[i];
const int id = ids[i];
const float value = noise::hash_to_float(id, seed);
- values[i] = round_fl_to_int(value * (max_value - min_value) + min_value);
+ values[i] = floor(value * (max_value - min_value) + min_value);
}
}
};
@@ -251,7 +307,7 @@ class RandomBoolFunction : public fn::MultiFunction {
static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- const NodeRandomValue &storage = *(const NodeRandomValue *)builder.node().storage;
+ const NodeRandomValue &storage = node_storage(builder.node());
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
switch (data_type) {
@@ -293,6 +349,7 @@ void register_node_type_fn_random_value()
ntype.draw_buttons = blender::nodes::fn_node_random_value_layout;
ntype.declare = blender::nodes::fn_node_random_value_declare;
ntype.build_multi_function = blender::nodes::fn_node_random_value_build_multi_function;
+ ntype.gather_link_search_ops = blender::nodes::fn_node_random_value_gather_link_search;
node_type_storage(
&ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 5ee26260790..f9a64381981 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -39,48 +39,49 @@ set(INC
set(SRC
- nodes/legacy/node_geo_align_rotation_to_vector.cc
- nodes/legacy/node_geo_attribute_clamp.cc
- nodes/legacy/node_geo_attribute_color_ramp.cc
- nodes/legacy/node_geo_attribute_combine_xyz.cc
- nodes/legacy/node_geo_attribute_compare.cc
- nodes/legacy/node_geo_attribute_convert.cc
- nodes/legacy/node_geo_attribute_curve_map.cc
- nodes/legacy/node_geo_attribute_fill.cc
- nodes/legacy/node_geo_attribute_map_range.cc
- nodes/legacy/node_geo_attribute_math.cc
- nodes/legacy/node_geo_attribute_mix.cc
- nodes/legacy/node_geo_attribute_proximity.cc
- nodes/legacy/node_geo_attribute_randomize.cc
- nodes/legacy/node_geo_attribute_sample_texture.cc
- nodes/legacy/node_geo_attribute_separate_xyz.cc
- nodes/legacy/node_geo_attribute_transfer.cc
- nodes/legacy/node_geo_attribute_vector_math.cc
- nodes/legacy/node_geo_attribute_vector_rotate.cc
- nodes/legacy/node_geo_curve_endpoints.cc
- nodes/legacy/node_geo_curve_reverse.cc
- nodes/legacy/node_geo_curve_select_by_handle_type.cc
- nodes/legacy/node_geo_curve_set_handles.cc
- nodes/legacy/node_geo_curve_spline_type.cc
- nodes/legacy/node_geo_curve_subdivide.cc
- nodes/legacy/node_geo_curve_to_points.cc
- nodes/legacy/node_geo_delete_geometry.cc
- nodes/legacy/node_geo_edge_split.cc
- nodes/legacy/node_geo_material_assign.cc
- nodes/legacy/node_geo_mesh_to_curve.cc
- nodes/legacy/node_geo_point_distribute.cc
- nodes/legacy/node_geo_point_instance.cc
- nodes/legacy/node_geo_point_rotate.cc
- nodes/legacy/node_geo_point_scale.cc
- nodes/legacy/node_geo_point_separate.cc
- nodes/legacy/node_geo_point_translate.cc
- nodes/legacy/node_geo_points_to_volume.cc
- nodes/legacy/node_geo_raycast.cc
- nodes/legacy/node_geo_select_by_material.cc
- nodes/legacy/node_geo_subdivision_surface.cc
- nodes/legacy/node_geo_volume_to_mesh.cc
+ nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
+ nodes/legacy/node_geo_legacy_attribute_clamp.cc
+ nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
+ nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
+ nodes/legacy/node_geo_legacy_attribute_compare.cc
+ nodes/legacy/node_geo_legacy_attribute_convert.cc
+ nodes/legacy/node_geo_legacy_attribute_curve_map.cc
+ nodes/legacy/node_geo_legacy_attribute_fill.cc
+ nodes/legacy/node_geo_legacy_attribute_map_range.cc
+ nodes/legacy/node_geo_legacy_attribute_math.cc
+ nodes/legacy/node_geo_legacy_attribute_mix.cc
+ nodes/legacy/node_geo_legacy_attribute_proximity.cc
+ nodes/legacy/node_geo_legacy_attribute_randomize.cc
+ nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
+ nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
+ nodes/legacy/node_geo_legacy_attribute_transfer.cc
+ nodes/legacy/node_geo_legacy_attribute_vector_math.cc
+ nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
+ nodes/legacy/node_geo_legacy_curve_endpoints.cc
+ nodes/legacy/node_geo_legacy_curve_reverse.cc
+ nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
+ nodes/legacy/node_geo_legacy_curve_set_handles.cc
+ nodes/legacy/node_geo_legacy_curve_spline_type.cc
+ nodes/legacy/node_geo_legacy_curve_subdivide.cc
+ nodes/legacy/node_geo_legacy_curve_to_points.cc
+ nodes/legacy/node_geo_legacy_delete_geometry.cc
+ nodes/legacy/node_geo_legacy_edge_split.cc
+ nodes/legacy/node_geo_legacy_material_assign.cc
+ nodes/legacy/node_geo_legacy_mesh_to_curve.cc
+ nodes/legacy/node_geo_legacy_point_distribute.cc
+ nodes/legacy/node_geo_legacy_point_instance.cc
+ nodes/legacy/node_geo_legacy_point_rotate.cc
+ nodes/legacy/node_geo_legacy_point_scale.cc
+ nodes/legacy/node_geo_legacy_point_separate.cc
+ nodes/legacy/node_geo_legacy_point_translate.cc
+ nodes/legacy/node_geo_legacy_points_to_volume.cc
+ nodes/legacy/node_geo_legacy_raycast.cc
+ nodes/legacy/node_geo_legacy_select_by_material.cc
+ nodes/legacy/node_geo_legacy_subdivision_surface.cc
+ nodes/legacy/node_geo_legacy_volume_to_mesh.cc
nodes/node_geo_attribute_capture.cc
+ nodes/node_geo_attribute_domain_size.cc
nodes/node_geo_attribute_remove.cc
nodes/node_geo_attribute_statistic.cc
nodes/node_geo_boolean.cc
@@ -93,7 +94,6 @@ set(SRC
nodes/node_geo_curve_fillet.cc
nodes/node_geo_curve_handle_type_selection.cc
nodes/node_geo_curve_length.cc
- nodes/node_geo_curve_parameter.cc
nodes/node_geo_curve_primitive_bezier_segment.cc
nodes/node_geo_curve_primitive_circle.cc
nodes/node_geo_curve_primitive_line.cc
@@ -106,13 +106,16 @@ set(SRC
nodes/node_geo_curve_sample.cc
nodes/node_geo_curve_set_handles.cc
nodes/node_geo_curve_spline_type.cc
+ nodes/node_geo_curve_spline_parameter.cc
nodes/node_geo_curve_subdivide.cc
nodes/node_geo_curve_to_mesh.cc
nodes/node_geo_curve_to_points.cc
nodes/node_geo_curve_trim.cc
nodes/node_geo_delete_geometry.cc
nodes/node_geo_distribute_points_on_faces.cc
+ nodes/node_geo_dual_mesh.cc
nodes/node_geo_edge_split.cc
+ nodes/node_geo_geometry_to_instance.cc
nodes/node_geo_image_texture.cc
nodes/node_geo_input_curve_handles.cc
nodes/node_geo_input_curve_tilt.cc
@@ -120,9 +123,16 @@ set(SRC
nodes/node_geo_input_index.cc
nodes/node_geo_input_material_index.cc
nodes/node_geo_input_material.cc
+ nodes/node_geo_input_mesh_edge_neighbors.cc
+ nodes/node_geo_input_mesh_edge_vertices.cc
+ nodes/node_geo_input_mesh_face_area.cc
+ nodes/node_geo_input_mesh_face_neighbors.cc
+ nodes/node_geo_input_mesh_island.cc
+ nodes/node_geo_input_mesh_vertex_neighbors.cc
nodes/node_geo_input_normal.cc
nodes/node_geo_input_position.cc
nodes/node_geo_input_radius.cc
+ nodes/node_geo_input_scene_time.cc
nodes/node_geo_input_shade_smooth.cc
nodes/node_geo_input_spline_cyclic.cc
nodes/node_geo_input_spline_length.cc
@@ -265,3 +275,8 @@ if(WITH_OPENVDB)
endif()
blender_add_lib(bf_nodes_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_geometry PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index 9747bb63773..89ab4d9961e 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -84,15 +84,16 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
}
-static bool geometry_node_tree_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link)
+static bool geometry_node_tree_validate_link(eNodeSocketDatatype type_a,
+ eNodeSocketDatatype type_b)
{
/* Geometry, string, object, material, texture and collection sockets can only be connected to
* themselves. The other types can be converted between each other. */
- if (ELEM(link->fromsock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT) &&
- ELEM(link->tosock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT)) {
+ if (ELEM(type_a, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT) &&
+ ELEM(type_b, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_BOOLEAN, SOCK_INT)) {
return true;
}
- return (link->tosock->type == link->fromsock->type);
+ return type_a == type_b;
}
static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
@@ -113,7 +114,7 @@ static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype
SOCK_MATERIAL);
}
-void register_node_tree_type_geo(void)
+void register_node_tree_type_geo()
{
bNodeTreeType *tt = ntreeType_Geometry = static_cast<bNodeTreeType *>(
MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type"));
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 5c1d507041c..49991a40c1b 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -24,17 +24,12 @@
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
+#include "NOD_socket_search_link.hh"
+
namespace blender::nodes {
using bke::GeometryInstanceGroup;
-/**
- * Update the availability of a group of input sockets with the same name,
- * used for switching between attribute inputs or single values.
- *
- * \param mode: Controls which socket of the group to make available.
- * \param name_is_available: If false, make all sockets with this name unavailable.
- */
void update_attribute_input_socket_availabilities(bNodeTree &ntree,
bNode &node,
const StringRef name,
@@ -56,6 +51,31 @@ void update_attribute_input_socket_availabilities(bNodeTree &ntree,
}
}
+std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
+{
+ switch (type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ return CD_PROP_FLOAT3;
+ case SOCK_RGBA:
+ return CD_PROP_COLOR;
+ case SOCK_BOOLEAN:
+ return CD_PROP_BOOL;
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_STRING:
+ return CD_PROP_STRING;
+ default:
+ return {};
+ }
+}
+
+std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket)
+{
+ return node_data_type_to_custom_data_type(static_cast<eNodeSocketDatatype>(socket.type));
+}
+
} // namespace blender::nodes
bool geo_node_poll_default(bNodeType *UNUSED(ntype),
@@ -63,7 +83,7 @@ bool geo_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "GeometryNodeTree")) {
- *r_disabled_hint = "Not a geometry node tree";
+ *r_disabled_hint = TIP_("Not a geometry node tree");
return false;
}
return true;
@@ -74,4 +94,5 @@ void geo_node_type_base(bNodeType *ntype, int type, const char *name, short ncla
node_type_base(ntype, type, name, nclass, flag);
ntype->poll = geo_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 79fe2ffc42b..3376b75d05b 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -43,6 +43,13 @@ bool geo_node_poll_default(struct bNodeType *ntype,
const char **r_disabled_hint);
namespace blender::nodes {
+/**
+ * Update the availability of a group of input sockets with the same name,
+ * used for switching between attribute inputs or single values.
+ *
+ * \param mode: Controls which socket of the group to make available.
+ * \param name_is_available: If false, make all sockets with this name unavailable.
+ */
void update_attribute_input_socket_availabilities(bNodeTree &ntree,
bNode &node,
const StringRef name,
@@ -126,4 +133,7 @@ void curve_create_default_rotation_attribute(Span<float3> tangents,
Span<float3> normals,
MutableSpan<float3> rotations);
+std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
+std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
index dc7c251d034..4366c6f9234 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
@@ -22,9 +22,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc {
-static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Factor"));
@@ -40,9 +40,7 @@ static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiLayoutSetPropSep(layout, true);
@@ -53,7 +51,7 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
uiItemR(col, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE);
}
-static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__);
@@ -65,7 +63,7 @@ static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNo
node->storage = node_storage;
}
-static void geo_node_align_rotation_to_vector_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
node->storage;
@@ -199,11 +197,11 @@ static void align_rotations_on_component(GeometryComponent &component,
rotations.save();
}
-static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
align_rotations_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -219,10 +217,12 @@ static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc
void register_node_type_geo_align_rotation_to_vector()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_align_rotation_to_vector_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -230,14 +230,14 @@ void register_node_type_geo_align_rotation_to_vector()
"Align Rotation to Vector",
NODE_CLASS_GEOMETRY,
0);
- node_type_init(&ntype, blender::nodes::geo_node_align_rotation_to_vector_init);
- node_type_update(&ntype, blender::nodes::geo_node_align_rotation_to_vector_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryAlignRotationToVector",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_align_rotation_to_vector_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_align_rotation_to_vector_exec;
- ntype.draw_buttons = blender::nodes::geo_node_align_rotation_to_vector_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
index a11a1bd3825..7435152a966 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
@@ -20,9 +20,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_clamp_cc {
-static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -38,13 +38,13 @@ static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp),
__func__);
@@ -53,7 +53,7 @@ static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_attribute_clamp_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3);
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -243,11 +243,11 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
attribute_result.save();
}
-static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
clamp_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -262,19 +262,21 @@ static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_clamp_cc
void register_node_type_geo_attribute_clamp()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_clamp_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_clamp_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_clamp_update);
- ntype.declare = blender::nodes::geo_node_attribute_clamp_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_clamp_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_clamp_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
index 061f5f3d7ee..4efdf786e4e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
@@ -23,9 +23,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc {
-static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -33,14 +33,12 @@ static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_color_ramp_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiTemplateColorRamp(layout, ptr, "color_ramp", false);
}
-static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN(
sizeof(NodeAttributeColorRamp), __func__);
@@ -100,11 +98,11 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -119,10 +117,12 @@ static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc
void register_node_type_geo_attribute_color_ramp()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attributes_color_ramp_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -132,10 +132,10 @@ void register_node_type_geo_attribute_color_ramp()
0);
node_type_storage(
&ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- ntype.declare = blender::nodes::geo_node_attribute_color_ramp_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_color_ramp_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
index a610356955b..7ba64c8db2b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc {
-static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("X"));
@@ -34,9 +34,7 @@ static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_combine_xyz_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -46,7 +44,7 @@ static void geo_node_attribute_combine_xyz_layout(uiLayout *layout,
uiItemR(col, ptr, "input_type_z", 0, IFACE_("Z"), ICON_NONE);
}
-static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN(
sizeof(NodeAttributeCombineXYZ), __func__);
@@ -57,7 +55,7 @@ static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *
node->storage = data;
}
-static void geo_node_attribute_combine_xyz_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage;
update_attribute_input_socket_availabilities(
@@ -111,11 +109,11 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa
attribute_result.save();
}
-static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
combine_attributes(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -130,10 +128,12 @@ static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc
void register_node_type_geo_attribute_combine_xyz()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_combine_xyz_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -141,13 +141,13 @@ void register_node_type_geo_attribute_combine_xyz()
"Attribute Combine XYZ",
NODE_CLASS_ATTRIBUTE,
0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_combine_xyz_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_combine_xyz_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeCombineXYZ", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_combine_xyz_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_combine_xyz_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_combine_xyz_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
index a4ffe884999..8aa1adb0cf3 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
@@ -21,9 +21,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_compare_cc {
-static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("A"));
@@ -39,9 +39,7 @@ static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_compare_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
uiLayoutSetPropSep(layout, true);
@@ -50,11 +48,11 @@ static void geo_node_attribute_compare_layout(uiLayout *layout,
uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
}
-static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare),
__func__);
- data->operation = NODE_FLOAT_COMPARE_GREATER_THAN;
+ data->operation = NODE_COMPARE_GREATER_THAN;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
@@ -62,10 +60,10 @@ static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node
static bool operation_tests_equality(const NodeAttributeCompare &node_storage)
{
- return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL);
+ return ELEM(node_storage.operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL);
}
-static void geo_node_attribute_compare_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage;
update_attribute_input_socket_availabilities(
@@ -79,7 +77,7 @@ static void geo_node_attribute_compare_update(bNodeTree *ntree, bNode *node)
static void do_math_operation(const VArray<float> &input_a,
const VArray<float> &input_b,
- const FloatCompareOperation operation,
+ const NodeCompareOperation operation,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
@@ -243,7 +241,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
{
const bNode &node = params.node();
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node.storage;
- const FloatCompareOperation operation = static_cast<FloatCompareOperation>(
+ const NodeCompareOperation operation = static_cast<NodeCompareOperation>(
node_storage->operation);
const std::string result_name = params.get_input<std::string>("Result");
@@ -273,7 +271,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
* conversions and float comparison. In other words, the comparison is not element-wise. */
if (operation_tests_equality(*node_storage)) {
const float threshold = params.get_input<float>("Threshold");
- if (operation == NODE_FLOAT_COMPARE_EQUAL) {
+ if (operation == NODE_COMPARE_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
do_equal_operation_float(
attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span);
@@ -293,7 +291,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span);
}
}
- else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) {
+ else if (operation == NODE_COMPARE_NOT_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
do_not_equal_operation_float(
attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span);
@@ -322,11 +320,11 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
attribute_result.save();
}
-static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_compare_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -341,20 +339,22 @@ static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_compare_cc
void register_node_type_geo_attribute_compare()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_compare_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_compare_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_compare_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_compare_layout;
- node_type_update(&ntype, blender::nodes::geo_node_attribute_compare_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_compare_init);
+ node_type_init(&ntype, file_ns::node_init);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
index 13ba8d13618..28c133871f7 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_convert_cc {
-static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -29,9 +29,7 @@ static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_convert_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -39,7 +37,7 @@ static void geo_node_attribute_convert_layout(uiLayout *layout,
uiItemR(layout, ptr, "data_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_attribute_convert_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert),
__func__);
@@ -130,11 +128,11 @@ static void attribute_convert_calc(GeometryComponent &component,
result_attribute.save();
}
-static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const std::string result_name = params.extract_input<std::string>("Result");
const std::string source_name = params.extract_input<std::string>("Attribute");
@@ -143,7 +141,7 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
const AttributeDomain domain = static_cast<AttributeDomain>(node_storage.domain);
if (result_name.empty()) {
- params.set_output("Geometry", geometry_set);
+ params.set_default_remaining_outputs();
return;
}
@@ -175,18 +173,20 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_convert_cc
void register_node_type_geo_attribute_convert()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_convert_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_convert_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_convert_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_convert_layout;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_convert_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeConvert", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
index af56df0dc3f..0a7b5dd8463 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc {
-static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -34,9 +34,7 @@ static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_curve_map_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
bNode *node = (bNode *)ptr->data;
@@ -54,7 +52,7 @@ static void geo_node_attribute_curve_map_layout(uiLayout *layout,
}
}
-static void geo_node_attribute_curve_map_free_storage(bNode *node)
+static void node_free_storage(bNode *node)
{
if (node->storage) {
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
@@ -64,9 +62,9 @@ static void geo_node_attribute_curve_map_free_storage(bNode *node)
}
}
-static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntree),
- bNode *dest_node,
- const bNode *src_node)
+static void node_copy_storage(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
{
dest_node->storage = MEM_dupallocN(src_node->storage);
NodeAttributeCurveMap *src_data = (NodeAttributeCurveMap *)src_node->storage;
@@ -75,7 +73,7 @@ static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntr
dest_data->curve_rgb = BKE_curvemapping_copy(src_data->curve_rgb);
}
-static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap),
__func__);
@@ -87,7 +85,7 @@ static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_attribute_curve_map_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_update(bNodeTree *UNUSED(ntree), bNode *node)
{
/* Set the active curve when data type is changed. */
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
@@ -179,7 +177,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const bNode &bnode = params.node();
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)bnode.storage;
@@ -188,7 +186,7 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -203,23 +201,23 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc
void register_node_type_geo_attribute_curve_map()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_curve_map_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_curve_map_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_curve_map_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_storage(&ntype,
- "NodeAttributeCurveMap",
- blender::nodes::geo_node_attribute_curve_map_free_storage,
- blender::nodes::geo_node_attribute_curve_map_copy_storage);
- ntype.declare = blender::nodes::geo_node_attribute_curve_map_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_curve_map_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_curve_map_layout;
+ node_type_storage(
+ &ntype, "NodeAttributeCurveMap", file_ns::node_free_storage, file_ns::node_copy_storage);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
index a1b537e9657..a05bcf1bed8 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_fill_cc {
-static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute")).is_attribute_name();
@@ -33,7 +33,7 @@ static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -41,13 +41,13 @@ static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C)
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
-static void geo_node_attribute_fill_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = CD_PROP_FLOAT;
node->custom2 = ATTR_DOMAIN_AUTO;
}
-static void geo_node_attribute_fill_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *socket_value_float = socket_value_vector->next;
@@ -127,11 +127,11 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
attribute.save();
}
-static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
fill_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -146,18 +146,20 @@ static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_fill_cc
void register_node_type_geo_attribute_fill()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_fill_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_fill_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_fill_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_fill_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_fill_layout;
- ntype.declare = blender::nodes::geo_node_attribute_fill_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
index 2c70157d586..8ebcf34ad0b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
@@ -22,9 +22,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_map_range_cc {
-static void geo_node_attribute_map_range_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -49,7 +49,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C),
uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
}
-static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange),
__func__);
@@ -58,7 +58,7 @@ static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_attribute_map_range_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage;
@@ -399,7 +399,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
attribute_result.save();
}
-static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -416,20 +416,22 @@ static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_map_range_cc
void register_node_type_geo_attribute_map_range()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_map_range_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_map_range_exec;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_map_range_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_map_range_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeMapRange", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_map_range_declare;
- ntype.draw_buttons = blender::nodes::fn_attribute_map_range_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::fn_attribute_map_range_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
index 193db7355f9..e0a829b4100 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_math_cc {
-static void geo_node_attribute_math_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("A"));
@@ -100,7 +100,7 @@ static bool operation_use_input_b(const NodeMathOperation operation)
return false;
}
-static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
@@ -119,7 +119,7 @@ static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C)
}
}
-static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__);
@@ -130,7 +130,10 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+static void geo_node_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
const char *name;
@@ -141,7 +144,7 @@ static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *lab
BLI_strncpy(label, IFACE_(name), maxlen);
}
-static void geo_node_attribute_math_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation);
@@ -278,11 +281,11 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
attribute_result.save();
}
-static void geo_node_attribute_math_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -297,20 +300,22 @@ static void geo_node_attribute_math_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_math_cc
void register_node_type_geo_attribute_math()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_math_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_math_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_math_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_math_layout;
- node_type_label(&ntype, blender::nodes::geo_node_math_label);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_math_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_math_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.labelfunc = file_ns::geo_node_math_label;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeMath", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
index 6c7f2313633..4a110e9690a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_mix_cc {
-static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Factor"));
@@ -48,7 +48,7 @@ static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -59,7 +59,7 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C),
uiItemR(col, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
}
-static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix),
"attribute mix node");
@@ -70,7 +70,7 @@ static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-static void geo_node_attribute_mix_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage;
update_attribute_input_socket_availabilities(
@@ -222,11 +222,11 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
attribute_result.save();
}
-static void geo_node_attribute_mix_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_mix_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -241,19 +241,21 @@ static void geo_node_attribute_mix_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_mix_cc
void register_node_type_geo_attribute_mix()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_mix_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_mix_update);
- ntype.declare = blender::nodes::geo_node_mix_attribute_declare;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_mix_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeMix", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_mix_exec;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
index 0122f9b7598..080bf38a740 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
@@ -26,9 +26,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_proximity_cc {
-static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Geometry>(N_("Target"));
@@ -37,14 +37,12 @@ static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_proximity_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target_geometry_element", 0, "", ICON_NONE);
}
-static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN(
sizeof(NodeGeometryAttributeProximity), __func__);
@@ -203,16 +201,16 @@ static void attribute_calc_proximity(GeometryComponent &component,
}
}
-static void geo_node_attribute_proximity_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
/* This isn't required. This node should be rewritten to handle instances
* for the target geometry set. However, the generic BVH API complicates this. */
- geometry_set_target = geometry_set_realize_instances(geometry_set_target);
+ geometry_set_target = geometry::realize_instances_legacy(geometry_set_target);
if (geometry_set.has<MeshComponent>()) {
attribute_calc_proximity(
@@ -230,22 +228,24 @@ static void geo_node_attribute_proximity_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_proximity_cc
void register_node_type_geo_legacy_attribute_proximity()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_proximity_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_attribute_proximity_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeProximity",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_proximity_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_proximity_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_proximity_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
index f8d9dcdaf87..ab2bc7b379c 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
@@ -25,7 +25,41 @@
namespace blender::nodes {
-static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &b)
+Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
+ const AttributeDomain domain)
+{
+ const int domain_size = component.attribute_domain_size(domain);
+
+ /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
+ GVArray hash_attribute = component.attribute_try_get_for_read("id", domain);
+ Array<uint32_t> hashes(domain_size);
+ if (hash_attribute) {
+ BLI_assert(hashes.size() == hash_attribute.size());
+ const CPPType &cpp_type = hash_attribute.type();
+ BLI_assert(cpp_type.is_hashable());
+ GVArray_GSpan items{hash_attribute};
+ threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ hashes[i] = cpp_type.hash(items[i]);
+ }
+ });
+ }
+ else {
+ /* If there is no "id" attribute for per-point variation, just create it here. */
+ RandomNumberGenerator rng(0);
+ for (const int i : hashes.index_range()) {
+ hashes[i] = rng.get_uint32();
+ }
+ }
+
+ return hashes;
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_attribute_randomize_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute"));
@@ -39,15 +73,13 @@ static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_legacy_attribute_random_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
sizeof(NodeAttributeRandomize), __func__);
@@ -57,7 +89,7 @@ static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bN
node->storage = data;
}
-static void geo_node_legacy_attribute_randomize_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -174,36 +206,6 @@ static void randomize_attribute_bool(MutableSpan<bool> span,
});
}
-Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
- const AttributeDomain domain)
-{
- const int domain_size = component.attribute_domain_size(domain);
-
- /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
- GVArray hash_attribute = component.attribute_try_get_for_read("id", domain);
- Array<uint32_t> hashes(domain_size);
- if (hash_attribute) {
- BLI_assert(hashes.size() == hash_attribute.size());
- const CPPType &cpp_type = hash_attribute.type();
- BLI_assert(cpp_type.is_hashable());
- GVArray_GSpan items{hash_attribute};
- threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- hashes[i] = cpp_type.hash(items[i]);
- }
- });
- }
- else {
- /* If there is no "id" attribute for per-point variation, just create it here. */
- RandomNumberGenerator rng(0);
- for (const int i : hashes.index_range()) {
- hashes[i] = rng.get_uint32();
- }
- }
-
- return hashes;
-}
-
static AttributeDomain get_result_domain(const GeometryComponent &component,
const GeoNodeExecParams &params,
const StringRef name)
@@ -280,12 +282,12 @@ static void randomize_attribute_on_component(GeometryComponent &component,
attribute.save();
}
-static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const std::string attribute_name = params.get_input<std::string>("Attribute");
if (attribute_name.empty()) {
- params.set_output("Geometry", geometry_set);
+ params.set_default_remaining_outputs();
return;
}
const int seed = params.get_input<int>("Seed");
@@ -294,7 +296,7 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
const GeometryNodeAttributeRandomizeMode operation =
static_cast<GeometryNodeAttributeRandomizeMode>(storage.operation);
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
randomize_attribute_on_component(geometry_set.get_component_for_write<MeshComponent>(),
@@ -324,20 +326,22 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_randomize_cc
void register_node_type_geo_legacy_attribute_randomize()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_randomize_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_init);
- node_type_update(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
- ntype.declare = blender::nodes::geo_node_legacy_attribute_randomize_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_random_attribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_legacy_attribute_random_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
index 9748ca3f2ad..bc18cb32e73 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
@@ -28,9 +28,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc {
-static void geo_node_attribute_sample_texture_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Texture>(N_("Texture")).hide_label();
@@ -100,11 +100,11 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
attribute_out.save();
}
-static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -119,10 +119,12 @@ static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc
void register_node_type_geo_sample_texture()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_sample_texture_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -131,7 +133,7 @@ void register_node_type_geo_sample_texture()
NODE_CLASS_ATTRIBUTE,
0);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- ntype.declare = blender::nodes::geo_node_attribute_sample_texture_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
index bfc69780bf6..c5aac118baf 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc {
-static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Vector"));
@@ -32,16 +32,14 @@ static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_separate_xyz_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN(
sizeof(NodeAttributeSeparateXYZ), __func__);
@@ -49,7 +47,7 @@ static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode
node->storage = data;
}
-static void geo_node_attribute_separate_xyz_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage;
update_attribute_input_socket_availabilities(
@@ -132,11 +130,11 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa
}
}
-static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
separate_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -151,10 +149,12 @@ static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc
void register_node_type_geo_attribute_separate_xyz()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_separate_xyz_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -162,12 +162,12 @@ void register_node_type_geo_attribute_separate_xyz()
"Attribute Separate XYZ",
NODE_CLASS_ATTRIBUTE,
0);
- ntype.declare = blender::nodes::geo_node_attribute_separate_xyz_declare;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_separate_xyz_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_separate_xyz_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeAttributeSeparateXYZ", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_separate_xyz_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_separate_xyz_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
index b8827f82efc..686edc80f62 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
@@ -29,9 +29,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_transfer_cc {
-static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Geometry>(N_("Source Geometry"));
@@ -40,9 +40,7 @@ static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_transfer_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -50,7 +48,7 @@ static void geo_node_attribute_transfer_layout(uiLayout *layout,
uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE);
}
-static void geo_node_attribute_transfer_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN(
sizeof(NodeGeometryAttributeTransfer), __func__);
@@ -405,7 +403,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry,
data_type);
for (const int i : IndexRange(tot_samples)) {
if (pointcloud_distances_sq[i] < mesh_distances_sq[i]) {
- /* Point-cloud point is closer. */
+ /* Point cloud point is closer. */
const int index = pointcloud_indices[i];
pointcloud_src_attribute.varray.get(index, buffer);
dst_attribute->set_by_relocate(i, buffer);
@@ -477,7 +475,7 @@ static void transfer_attribute(const GeoNodeExecParams &params,
}
}
-static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet dst_geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet src_geometry_set = params.extract_input<GeometrySet>("Source Geometry");
@@ -485,12 +483,12 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
const std::string dst_attribute_name = params.extract_input<std::string>("Destination");
if (src_attribute_name.empty() || dst_attribute_name.empty()) {
- params.set_output("Geometry", dst_geometry_set);
+ params.set_default_remaining_outputs();
return;
}
- dst_geometry_set = bke::geometry_set_realize_instances(dst_geometry_set);
- src_geometry_set = bke::geometry_set_realize_instances(src_geometry_set);
+ dst_geometry_set = geometry::realize_instances_legacy(dst_geometry_set);
+ src_geometry_set = geometry::realize_instances_legacy(src_geometry_set);
if (dst_geometry_set.has<MeshComponent>()) {
transfer_attribute(params,
@@ -510,21 +508,23 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params)
params.set_output("Geometry", dst_geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_transfer_cc
void register_node_type_geo_legacy_attribute_transfer()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_transfer_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_transfer_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeTransfer",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_attribute_transfer_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_transfer_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_transfer_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
index e7fdd0f2eef..68051e81f57 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
@@ -26,9 +26,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc {
-static void geo_node_attribute_vector_math_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("A"));
@@ -66,9 +66,7 @@ static bool operation_use_input_c(const NodeVectorMathOperation operation)
NODE_VECTOR_MATH_MULTIPLY_ADD);
}
-static void geo_node_attribute_vector_math_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
const NodeAttributeVectorMath &node_storage = *(NodeAttributeVectorMath *)node->storage;
@@ -103,7 +101,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op
return CD_PROP_FLOAT3;
}
-static void geo_node_attribute_vector_math_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN(
sizeof(NodeAttributeVectorMath), __func__);
@@ -152,8 +150,8 @@ static CustomDataType operation_get_result_type(const NodeVectorMathOperation op
return CD_PROP_FLOAT3;
}
-static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree),
- bNode *node,
+static void geo_node_vector_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
char *label,
int maxlen)
{
@@ -166,7 +164,7 @@ static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree),
BLI_snprintf(label, maxlen, IFACE_("Vector %s"), IFACE_(name));
}
-static void geo_node_attribute_vector_math_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage;
const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation;
@@ -531,11 +529,11 @@ static void attribute_vector_math_calc(GeometryComponent &component,
attribute_result.save();
}
-static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
attribute_vector_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -551,10 +549,12 @@ static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc
void register_node_type_geo_attribute_vector_math()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_math_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -562,12 +562,12 @@ void register_node_type_geo_attribute_vector_math()
"Attribute Vector Math",
NODE_CLASS_ATTRIBUTE,
0);
- ntype.declare = blender::nodes::geo_node_attribute_vector_math_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_math_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_math_layout;
- node_type_label(&ntype, blender::nodes::geo_node_vector_math_label);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_math_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_math_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.labelfunc = file_ns::geo_node_vector_math_label;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeAttributeVectorMath", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
index a6cd24ed72d..1ef50e69775 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
@@ -21,9 +21,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc {
-static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Vector"));
@@ -42,9 +42,7 @@ static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_attribute_vector_rotate_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
const NodeAttributeVectorRotate &node_storage = *(NodeAttributeVectorRotate *)node->storage;
@@ -70,7 +68,7 @@ static void geo_node_attribute_vector_rotate_layout(uiLayout *layout,
}
}
-static void geo_node_attribute_vector_rotate_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage;
const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode)
@@ -112,7 +110,7 @@ static float3 vector_rotate_around_axis(const float3 vector,
return result + center;
}
-static void geo_node_attribute_vector_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN(
sizeof(NodeAttributeVectorRotate), __func__);
@@ -309,11 +307,11 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
attribute_result.save();
}
-static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -328,10 +326,12 @@ static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc
void register_node_type_geo_attribute_vector_rotate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_rotate_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -339,13 +339,13 @@ void register_node_type_geo_attribute_vector_rotate()
"Attribute Vector Rotate",
NODE_CLASS_ATTRIBUTE,
0);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_rotate_update);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_rotate_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_size(&ntype, 165, 100, 600);
node_type_storage(
&ntype, "NodeAttributeVectorRotate", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_rotate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_rotate_layout;
- ntype.declare = blender::nodes::geo_node_attribute_vector_rotate_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
index 67c8200a9c2..e61dee4bee1 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_endpoints_cc {
-static void geo_node_curve_endpoints_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Start Points"));
@@ -145,15 +145,14 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines,
});
}
-static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
- params.set_output("Start Points", GeometrySet());
- params.set_output("End Points", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -168,8 +167,7 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
const int total_size = offsets.size();
if (total_size == 0) {
- params.set_output("Start Points", GeometrySet());
- params.set_output("End Points", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -206,16 +204,18 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
params.set_output("End Points", std::move(end_result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_endpoints_cc
void register_node_type_geo_legacy_curve_endpoints()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_endpoints_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_endpoints_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoints_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
index bc4612e2b8b..7c550495b41 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
@@ -20,19 +20,19 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_reverse_cc {
-static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -58,14 +58,16 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
params.set_output("Curve", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_reverse_cc
void register_node_type_geo_legacy_curve_reverse()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_reverse_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
index 40d827ae141..c702e9ff686 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
@@ -23,24 +23,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc {
-static void geo_node_select_by_handle_type_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_curve_select_by_handle_type_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_select_by_handle_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
sizeof(NodeGeometryCurveSelectHandles), __func__);
@@ -94,7 +92,7 @@ static void select_curve_by_handle_type(const CurveEval &curve,
});
}
-static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSelectHandles *storage =
(const NodeGeometryCurveSelectHandles *)params.node().storage;
@@ -103,7 +101,7 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
const CurveEval *curve = curve_component.get_for_read();
@@ -121,10 +119,12 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc
void register_node_type_geo_legacy_select_by_handle_type()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -132,14 +132,14 @@ void register_node_type_geo_legacy_select_by_handle_type()
"Select by Handle Type",
NODE_CLASS_GEOMETRY,
0);
- ntype.declare = blender::nodes::geo_node_select_by_handle_type_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_select_by_handle_type_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_select_by_handle_type_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSelectHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_select_by_handle_type_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
index b92db315d94..1e476d01148 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
@@ -21,24 +21,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_set_handles_cc {
-static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b)
+static void node_decalre(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_set_handles_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
sizeof(NodeGeometryCurveSetHandles), __func__);
@@ -64,7 +62,7 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan
return BezierSpline::HandleType::Auto;
}
-static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSetHandles *node_storage =
(NodeGeometryCurveSetHandles *)params.node().storage;
@@ -72,7 +70,7 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -124,21 +122,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
params.set_output("Curve", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_set_handles_cc
void register_node_type_geo_legacy_curve_set_handles()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_set_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_set_handles_decalre;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init);
+ ntype.declare = file_ns::node_decalre;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSetHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
index 36d4519cac3..f3599f4328f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
@@ -23,23 +23,21 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_spline_type_cc {
-static void geo_node_legacy_curve_spline_type_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_legacy_curve_spline_type_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
}
-static void geo_node_legacy_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
sizeof(NodeGeometryCurveSplineType), __func__);
@@ -238,14 +236,14 @@ static SplinePtr convert_to_nurbs(const Spline &input)
return {};
}
-static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType *storage =
(const NodeGeometryCurveSplineType *)params.node().storage;
const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage->spline_type;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Curve", geometry_set);
return;
@@ -282,21 +280,23 @@ static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc
void register_node_type_geo_legacy_curve_spline_type()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_spline_type_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_curve_spline_type_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_curve_spline_type_exec;
- node_type_init(&ntype, blender::nodes::geo_node_legacy_curve_spline_type_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSplineType",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_legacy_curve_spline_type_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
index 603547a8e69..9878402dd35 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_curve_subdivide_cc {
-static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Cuts"));
@@ -35,14 +35,14 @@ static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_curve_subdivide_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "cuts_type", 0, IFACE_("Cuts"), ICON_NONE);
}
-static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
sizeof(NodeGeometryCurveSubdivide), __func__);
@@ -51,7 +51,7 @@ static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_subdivide_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
@@ -347,11 +347,11 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
return output_curve;
}
-static void geo_node_subdivide_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Geometry", geometry_set);
@@ -370,22 +370,24 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params)
params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc
void register_node_type_geo_legacy_curve_subdivide()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_subdivide_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_subdivide_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_subdivide_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(&ntype,
"NodeGeometryCurveSubdivide",
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_subdivide_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_subdivide_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
index ab51258cc69..3bd03f3cee0 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
@@ -28,7 +28,59 @@
namespace blender::nodes {
-static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
+static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
+ const AttributeIDRef &attribute_id,
+ const CustomDataType data_type)
+{
+ points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
+ WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
+ BLI_assert(attribute);
+ return attribute.varray.get_internal_span();
+}
+
+template<typename T>
+static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
+ const AttributeIDRef &attribute_id)
+{
+ GMutableSpan attribute = create_attribute_and_retrieve_span(
+ points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
+ return attribute.typed<T>();
+}
+
+CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
+ const CurveEval &curve)
+{
+ CurveToPointsResults attributes;
+
+ attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position");
+ attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius");
+ attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt");
+
+ /* Because of the invariants of the curve component, we use the attributes of the
+ * first spline as a representative for the attribute meta data all splines. */
+ curve.splines().first()->attributes.foreach_attribute(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ attributes.point_attributes.add_new(
+ attribute_id,
+ create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type));
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+
+ attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent");
+ attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal");
+ attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation");
+
+ return attributes;
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_curve_to_points_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000);
@@ -36,12 +88,12 @@ static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
sizeof(NodeGeometryCurveToPoints), __func__);
@@ -50,7 +102,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_to_points_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
@@ -114,54 +166,6 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
return {0};
}
-static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
- const AttributeIDRef &attribute_id,
- const CustomDataType data_type)
-{
- points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
- WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
- BLI_assert(attribute);
- return attribute.varray.get_internal_span();
-}
-
-template<typename T>
-static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
- const AttributeIDRef &attribute_id)
-{
- GMutableSpan attribute = create_attribute_and_retrieve_span(
- points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
- return attribute.typed<T>();
-}
-
-CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
- const CurveEval &curve)
-{
- CurveToPointsResults attributes;
-
- attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT);
-
- attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position");
- attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius");
- attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt");
-
- /* Because of the invariants of the curve component, we use the attributes of the
- * first spline as a representative for the attribute meta data all splines. */
- curve.splines().first()->attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- attributes.point_attributes.add_new(
- attribute_id,
- create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type));
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent");
- attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal");
- attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation");
-
- return attributes;
-}
-
/**
* TODO: For non-poly splines, this has double copies that could be avoided as part
* of a general look at optimizing uses of #Spline::interpolate_to_evaluated.
@@ -286,13 +290,13 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
});
}
-static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_curve()) {
params.set_output("Geometry", GeometrySet());
@@ -340,21 +344,23 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_curve_to_points_cc
void register_node_type_geo_legacy_curve_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_curve_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
index f62a22d7934..abd75e710ae 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
@@ -29,23 +29,23 @@
using blender::bke::CustomDataAttributes;
/* Code from the mask modifier in MOD_mask.cc. */
-extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map);
-extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map);
-extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map,
- blender::Span<int> masked_poly_indices,
- blender::Span<int> new_loop_starts);
-
-namespace blender::nodes {
-
-static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b)
+void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map);
+void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map,
+ blender::Span<int> edge_map);
+void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map,
+ blender::Span<int> edge_map,
+ blender::Span<int> masked_poly_indices,
+ blender::Span<int> new_loop_starts);
+
+namespace blender::nodes::node_geo_legacy_delete_geometry_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Selection"));
@@ -627,10 +627,10 @@ static void delete_mesh_selection(MeshComponent &component,
component.replace(mesh_out);
}
-static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const bool invert = params.extract_input<bool>("Invert");
const std::string selection_name = params.extract_input<std::string>("Selection");
@@ -662,16 +662,18 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(out_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_delete_geometry_cc
void register_node_type_geo_legacy_delete_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_delete_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_delete_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
index 8f2bf05d2b4..c046fda4686 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
@@ -22,9 +22,9 @@ extern "C" {
Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd);
}
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_edge_split_cc {
-static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Bool>(N_("Edge Angle")).default_value(true);
@@ -37,11 +37,11 @@ static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_edge_split_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", std::move(geometry_set));
@@ -76,14 +76,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_edge_split_cc
void register_node_type_geo_legacy_edge_split()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_edge_split_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec;
- ntype.declare = blender::nodes::geo_node_edge_split_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
index 58374679a95..88e8374f5d6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
@@ -24,9 +24,9 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_material_assign_cc {
-static void geo_node_legacy_material_assign_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Material>(N_("Material")).hide_label(true);
@@ -59,14 +59,14 @@ static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask,
}
}
-static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const std::string mask_name = params.extract_input<std::string>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
@@ -81,15 +81,17 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_material_assign_cc
void register_node_type_geo_legacy_material_assign()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_material_assign_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_material_assign_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_material_assign_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
index 321de24a3dc..2ff7410f3f6 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
@@ -18,23 +18,23 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc {
-static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh"));
b.add_input<decl::String>(N_("Selection"));
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_mesh()) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -55,7 +55,7 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
}
if (selected_edge_indices.size() == 0) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -65,15 +65,17 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc
void register_node_type_geo_legacy_mesh_to_curve()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_mesh_to_curve_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
index 4e13a490d89..2451a7447ec 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
@@ -36,11 +36,11 @@
#include "node_geometry_util.hh"
-using blender::bke::GeometryInstanceGroup;
+namespace blender::nodes::node_geo_legacy_point_distribute_cc {
-namespace blender::nodes {
+using blender::bke::GeometryInstanceGroup;
-static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).max(100000.0f).subtype(PROP_DISTANCE);
@@ -54,9 +54,7 @@ static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_distribute_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
}
@@ -541,7 +539,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group
}
}
-static void geo_node_point_distribute_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -554,14 +552,14 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
"Density Attribute");
if (density <= 0.0f) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
Vector<GeometryInstanceGroup> set_groups;
geometry_set_gather_instances(geometry_set, set_groups);
if (set_groups.is_empty()) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -575,7 +573,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
if (set_groups.is_empty()) {
params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh"));
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -625,7 +623,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
}
if (final_points_len == 0) {
- params.set_output("Geometry", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -655,17 +653,19 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_distribute_cc
void register_node_type_geo_point_distribute()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_distribute_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0);
- node_type_update(&ntype, blender::nodes::node_point_distribute_update);
- ntype.declare = blender::nodes::geo_node_point_distribute_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_distribute_layout;
+ node_type_update(&ntype, file_ns::node_point_distribute_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
index 713971941ea..8915a58feb1 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_instance_cc {
-static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Object>(N_("Object")).hide_label();
@@ -36,7 +36,7 @@ static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "instance_type", 0, "", ICON_NONE);
if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) {
@@ -44,7 +44,7 @@ static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C)
}
}
-static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
sizeof(NodeGeometryPointInstance), __func__);
@@ -53,7 +53,7 @@ static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_point_instance_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *collection_socket = object_socket->next;
@@ -173,6 +173,9 @@ static void add_instances_from_component(InstancesComponent &instances,
const AttributeDomain domain = ATTR_DOMAIN_POINT;
const int domain_size = src_geometry.attribute_domain_size(domain);
+ if (domain_size == 0) {
+ return;
+ }
VArray<float3> positions = src_geometry.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
@@ -186,7 +189,9 @@ static void add_instances_from_component(InstancesComponent &instances,
instances.resize(start_len + domain_size);
MutableSpan<int> handles = instances.instance_reference_handles().slice(start_len, domain_size);
MutableSpan<float4x4> transforms = instances.instance_transforms().slice(start_len, domain_size);
- MutableSpan<int> instance_ids = instances.instance_ids_ensure().slice(start_len, domain_size);
+ OutputAttribute_Typed<int> instance_id_attribute =
+ instances.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_INSTANCE);
+ MutableSpan<int> instance_ids = instance_id_attribute.as_span();
/* Skip all of the randomness handling if there is only a single possible instance
* (anything except for collection mode with "Whole Collection" turned off). */
@@ -213,16 +218,18 @@ static void add_instances_from_component(InstancesComponent &instances,
}
});
}
+
+ instance_id_attribute.save();
}
-static void geo_node_point_instance_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
/* TODO: This node should be able to instance on the input instances component
* rather than making the entire input geometry set real. */
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
const Vector<InstanceReference> possible_references = get_instance_references(params);
if (possible_references.is_empty()) {
@@ -255,20 +262,22 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_instance_cc
void register_node_type_geo_point_instance()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_instance_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_instance_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_instance_declare;
- ntype.draw_buttons = blender::nodes::geo_node_point_instance_layout;
- node_type_update(&ntype, blender::nodes::geo_node_point_instance_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_point_instance_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
index ab1d68bfe4f..a0a7674797a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
@@ -21,9 +21,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_rotate_cc {
-static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Axis"));
@@ -37,7 +37,7 @@ static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage;
@@ -57,7 +57,7 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C),
}
}
-static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN(
sizeof(NodeGeometryRotatePoints), __func__);
@@ -71,7 +71,7 @@ static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = node_storage;
}
-static void geo_node_point_rotate_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage;
update_attribute_input_socket_availabilities(
@@ -199,11 +199,11 @@ static void point_rotate_on_component(GeometryComponent &component,
rotation_attribute.save();
}
-static void geo_node_point_rotate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
point_rotate_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
@@ -218,19 +218,21 @@ static void geo_node_point_rotate_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_rotate_cc
void register_node_type_geo_point_rotate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_rotate_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_rotate_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_rotate_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryRotatePoints", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_rotate_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_rotate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_rotate_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
index 8d6345ce6b1..d38df124979 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
@@ -21,9 +21,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_scale_cc {
-static void geo_node_point_scale_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Factor"));
@@ -34,14 +34,14 @@ static void geo_node_point_scale_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_scale_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE);
}
-static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN(
sizeof(NodeGeometryPointScale), __func__);
@@ -50,7 +50,7 @@ static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_point_scale_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage;
@@ -101,11 +101,11 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
scale_attribute.save();
}
-static void geo_node_point_scale_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -120,20 +120,22 @@ static void geo_node_point_scale_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_scale_cc
void register_node_type_geo_point_scale()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_scale_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_point_scale_declare;
- node_type_init(&ntype, blender::nodes::geo_node_point_scale_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_scale_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryPointScale", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_point_scale_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_scale_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
index 3539fe2de64..9260928b311 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
@@ -25,14 +25,6 @@
namespace blender::nodes {
-static void geo_node_point_instance_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Mask"));
- b.add_output<decl::Geometry>(N_("Geometry 1"));
- b.add_output<decl::Geometry>(N_("Geometry 2"));
-}
-
template<typename T>
static void copy_data_based_on_mask(Span<T> data,
Span<bool> masks,
@@ -78,6 +70,18 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
}
}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_legacy_point_separate_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::String>(N_("Mask"));
+ b.add_output<decl::Geometry>(N_("Geometry 1"));
+ b.add_output<decl::Geometry>(N_("Geometry 2"));
+}
+
static void create_component_points(GeometryComponent &component, const int total)
{
switch (component.type()) {
@@ -133,7 +137,7 @@ static GeometrySet separate_geometry_set(const GeometrySet &set_in,
return set_out;
}
-static void geo_node_point_separate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
bool wait_for_inputs = false;
wait_for_inputs |= params.lazy_require_input("Geometry");
@@ -146,7 +150,7 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params)
/* TODO: This is not necessary-- the input geometry set can be read only,
* but it must be rewritten to handle instance groups. */
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (params.lazy_output_is_required("Geometry 1")) {
params.set_output("Geometry 1",
@@ -158,16 +162,18 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_separate_cc
void register_node_type_geo_point_separate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_separate_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_point_instance_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.geometry_node_execute_supports_laziness = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
index 3b2959beb86..c70478182ec 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
@@ -19,9 +19,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_point_translate_cc {
-static void geo_node_point_translate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Translation"));
@@ -29,7 +29,7 @@ static void geo_node_point_translate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_point_translate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -53,11 +53,11 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
position_attribute.save();
}
-static void geo_node_point_translate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
@@ -72,7 +72,7 @@ static void geo_node_point_translate_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN(
sizeof(NodeGeometryPointTranslate), __func__);
@@ -81,7 +81,7 @@ static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_point_translate_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
@@ -89,22 +89,24 @@ static void geo_node_point_translate_update(bNodeTree *ntree, bNode *node)
*ntree, *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_point_translate_cc
void register_node_type_geo_point_translate()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_point_translate_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_point_translate_init);
- node_type_update(&ntype, blender::nodes::geo_node_point_translate_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryPointTranslate",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_point_translate_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_translate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_translate_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
index d465a9ab1a8..ec1ab67b530 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
@@ -28,9 +28,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_points_to_volume_cc {
-static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
@@ -41,9 +41,7 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_points_to_volume_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -51,7 +49,7 @@ static void geo_node_points_to_volume_layout(uiLayout *layout,
uiItemR(layout, ptr, "input_type_radius", 0, IFACE_("Radius"), ICON_NONE);
}
-static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
sizeof(NodeGeometryPointsToVolume), __func__);
@@ -65,7 +63,7 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node
STRNCPY(radius_attribute_socket_value->value, "radius");
}
-static void geo_node_points_to_volume_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage;
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
@@ -244,13 +242,13 @@ static void initialize_volume_component_from_points(const GeometrySet &geometry_
}
#endif
-static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
/* TODO: Read-only access to instances should be supported here, for now they are made real. */
- geometry_set_in = geometry_set_realize_instances(geometry_set_in);
+ geometry_set_in = geometry::realize_instances_legacy(geometry_set_in);
#ifdef WITH_OPENVDB
initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params);
@@ -259,10 +257,12 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_points_to_volume_cc
void register_node_type_geo_legacy_points_to_volume()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_points_to_volume_cc;
+
static bNodeType ntype;
geo_node_type_base(
@@ -272,10 +272,10 @@ void register_node_type_geo_legacy_points_to_volume()
node_free_standard_storage,
node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init);
- node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update);
- ntype.declare = blender::nodes::geo_node_points_to_volume_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec;
- ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
index 5aa683ca232..599ffd617a5 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_raycast_cc {
-static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Geometry>(N_("Target Geometry"));
@@ -47,7 +47,7 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -56,7 +56,7 @@ static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), Point
uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE);
}
-static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
__func__);
@@ -65,7 +65,7 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_raycast_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage;
update_attribute_input_socket_availabilities(
@@ -272,7 +272,7 @@ static void raycast_from_points(const GeoNodeExecParams &params,
}
}
-static void geo_node_raycast_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry");
@@ -285,8 +285,8 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
const Array<std::string> hit_names = {params.extract_input<std::string>("Target Attribute")};
const Array<std::string> hit_output_names = {params.extract_input<std::string>("Hit Attribute")};
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
- target_geometry_set = bke::geometry_set_realize_instances(target_geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
+ target_geometry_set = geometry::realize_instances_legacy(target_geometry_set);
static const Array<GeometryComponentType> types = {
GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
@@ -307,20 +307,22 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_raycast_cc
void register_node_type_geo_legacy_raycast()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_raycast_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, blender::nodes::geo_node_raycast_init);
- node_type_update(&ntype, blender::nodes::geo_node_raycast_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_raycast_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec;
- ntype.draw_buttons = blender::nodes::geo_node_raycast_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
index a8d6f33a5fd..b61ba5ff67e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
@@ -26,9 +26,9 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_select_by_material_cc {
-static void geo_node_legacy_select_by_material_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Material>(N_("Material")).hide_label();
@@ -54,13 +54,13 @@ static void select_mesh_by_material(const Mesh &mesh,
});
}
-static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const std::string selection_name = params.extract_input<std::string>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (geometry_set.has<MeshComponent>()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
@@ -78,15 +78,17 @@ static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_select_by_material_cc
void register_node_type_geo_legacy_select_by_material()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_select_by_material_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_select_by_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_select_by_material_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
index 295cd05fd01..819ffb2c20c 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
@@ -23,9 +23,9 @@
#include "UI_resources.h"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_subdivision_surface_cc {
-static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
@@ -33,9 +33,7 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_subdivision_surface_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
#ifdef WITH_OPENSUBDIV
uiLayoutSetPropSep(layout, true);
@@ -47,7 +45,7 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout,
#endif
}
-static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
sizeof(NodeGeometrySubdivisionSurface), __func__);
@@ -56,11 +54,11 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
+ geometry_set = geometry::realize_instances_legacy(geometry_set);
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", geometry_set);
@@ -126,18 +124,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_subdivision_surface_cc
void register_node_type_geo_legacy_subdivision_surface()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_subdivision_surface_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_subdivision_surface_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec;
- ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout;
- node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_storage(&ntype,
"NodeGeometrySubdivisionSurface",
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
index 6a52b943967..acff0be7126 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
@@ -35,9 +35,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc {
-static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Density"));
@@ -48,14 +48,14 @@ static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
sizeof(NodeGeometryVolumeToMesh), __func__);
@@ -68,7 +68,7 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-static void geo_node_volume_to_mesh_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
@@ -140,7 +140,7 @@ static void create_mesh_from_volume(GeometrySet &geometry_set_in,
#endif /* WITH_OPENVDB */
-static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
@@ -155,21 +155,23 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set_out);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc
void register_node_type_geo_legacy_volume_to_mesh()
{
+ namespace file_ns = blender::nodes::node_geo_legacy_volume_to_mesh_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare;
+ ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init);
- node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec;
- ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index 19deb761948..be0baa706af 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -19,11 +19,15 @@
#include "BKE_attribute_math.hh"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_capture_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryAttributeCapture)
-static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Vector>(N_("Value")).supports_field();
@@ -40,9 +44,7 @@ static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source();
}
-static void geo_node_attribute_capture_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -50,7 +52,7 @@ static void geo_node_attribute_capture_layout(uiLayout *layout,
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
-static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN(
sizeof(NodeGeometryAttributeCapture), __func__);
@@ -60,10 +62,9 @@ static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node
node->storage = data;
}
-static void geo_node_attribute_capture_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
- node->storage;
+ const NodeGeometryAttributeCapture &storage = node_storage(*node);
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first;
@@ -93,6 +94,33 @@ static void geo_node_attribute_capture_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32);
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+ search_link_ops_for_declarations(params, declaration.outputs().take_front(1));
+
+ const bNodeType &node_type = params.node_type();
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+ else {
+ params.add_item(IFACE_("Value"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+ }
+}
+
static void try_capture_field_on_geometry(GeometryComponent &component,
const AttributeIDRef &attribute_id,
const AttributeDomain domain,
@@ -113,13 +141,11 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
output_attribute.save();
}
-static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- const bNode &node = params.node();
- const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
- node.storage;
+ const NodeGeometryAttributeCapture &storage = node_storage(params.node());
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
@@ -147,16 +173,27 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
WeakAnonymousAttributeID anonymous_id{"Attribute"};
const CPPType &type = field.cpp_type();
- static const Array<GeometryComponentType> types = {
- GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- for (const GeometryComponentType type : types) {
- if (geometry_set.has(type)) {
- GeometryComponent &component = geometry_set.get_component_for_write(type);
- try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
- }
+ /* Run on the instances component separately to only affect the top level of instances. */
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ if (geometry_set.has_instances()) {
+ GeometryComponent &component = geometry_set.get_component_for_write(
+ GEO_COMPONENT_TYPE_INSTANCES);
+ try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
}
- });
+ }
+ else {
+ static const Array<GeometryComponentType> types = {
+ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ for (const GeometryComponentType type : types) {
+ if (geometry_set.has(type)) {
+ GeometryComponent &component = geometry_set.get_component_for_write(type);
+ try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
+ }
+ }
+ });
+ }
GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>(
std::move(anonymous_id), type, params.attribute_producer_name())};
@@ -189,10 +226,12 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_capture_cc
void register_node_type_geo_attribute_capture()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_capture_cc;
+
static bNodeType ntype;
geo_node_type_base(
@@ -201,10 +240,11 @@ void register_node_type_geo_attribute_capture()
"NodeGeometryAttributeCapture",
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_attribute_capture_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_capture_update);
- ntype.declare = blender::nodes::geo_node_attribute_capture_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_capture_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_capture_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
new file mode 100644
index 00000000000..d6662e4e637
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -0,0 +1,155 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_attribute_domain_size_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_output<decl::Int>("Point Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Edge Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Face Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Face Corner Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_MESH;
+ });
+ b.add_output<decl::Int>("Spline Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_CURVE;
+ });
+ b.add_output<decl::Int>("Instance Count").make_available([](bNode &node) {
+ node.custom1 = GEO_COMPONENT_TYPE_INSTANCES;
+ });
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ node->custom1 = GEO_COMPONENT_TYPE_MESH;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *point_socket = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *edge_socket = point_socket->next;
+ bNodeSocket *face_socket = edge_socket->next;
+ bNodeSocket *face_corner_socket = face_socket->next;
+ bNodeSocket *spline_socket = face_corner_socket->next;
+ bNodeSocket *instances_socket = spline_socket->next;
+
+ nodeSetSocketAvailability(ntree,
+ point_socket,
+ ELEM(node->custom1,
+ GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_POINT_CLOUD));
+ nodeSetSocketAvailability(ntree, edge_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, face_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, face_corner_socket, node->custom1 == GEO_COMPONENT_TYPE_MESH);
+ nodeSetSocketAvailability(ntree, spline_socket, node->custom1 == GEO_COMPONENT_TYPE_CURVE);
+ nodeSetSocketAvailability(
+ ntree, instances_socket, node->custom1 == GEO_COMPONENT_TYPE_INSTANCES);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometryComponentType component = (GeometryComponentType)params.node().custom1;
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ switch (component) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ if (geometry_set.has_mesh()) {
+ const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Edge Count", component->attribute_domain_size(ATTR_DOMAIN_EDGE));
+ params.set_output("Face Count", component->attribute_domain_size(ATTR_DOMAIN_FACE));
+ params.set_output("Face Corner Count",
+ component->attribute_domain_size(ATTR_DOMAIN_CORNER));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ if (geometry_set.has_curve()) {
+ const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Spline Count", component->attribute_domain_size(ATTR_DOMAIN_CURVE));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ if (geometry_set.has_pointcloud()) {
+ const PointCloudComponent *component =
+ geometry_set.get_component_for_read<PointCloudComponent>();
+ params.set_output("Point Count", component->attribute_domain_size(ATTR_DOMAIN_POINT));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ if (geometry_set.has_instances()) {
+ const InstancesComponent *component =
+ geometry_set.get_component_for_read<InstancesComponent>();
+ params.set_output("Instance Count",
+ component->attribute_domain_size(ATTR_DOMAIN_INSTANCE));
+ }
+ else {
+ params.set_default_remaining_outputs();
+ }
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+}
+
+} // namespace blender::nodes::node_geo_attribute_domain_size_cc
+
+void register_node_type_geo_attribute_domain_size()
+{
+ namespace file_ns = blender::nodes::node_geo_attribute_domain_size_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE, 0);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.updatefunc = file_ns::node_update;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
index f80b8ccc971..6f26b2c756b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_remove_cc {
-static void geo_node_attribute_remove_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::String>(N_("Attribute")).multi_input();
@@ -42,7 +42,7 @@ static void remove_attribute(GeometryComponent &component,
}
}
-static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute");
@@ -66,15 +66,17 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_remove_cc
void register_node_type_geo_attribute_remove()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_remove_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_remove_exec;
- ntype.declare = blender::nodes::geo_node_attribute_remove_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index d9513332078..b79125d43d1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -22,13 +22,16 @@
#include "BLI_math_base_safe.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_attribute_statistic_cc {
-static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
b.add_input<decl::Float>(N_("Attribute")).hide_value().supports_field();
b.add_input<decl::Vector>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
@@ -51,24 +54,23 @@ static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Variance"), "Variance_001");
}
-static void geo_node_attribute_statistic_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void geo_node_attribute_statistic_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = CD_PROP_FLOAT;
node->custom2 = ATTR_DOMAIN_POINT;
}
-static void geo_node_attribute_statistic_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first;
- bNodeSocket *socket_float_attr = socket_geo->next;
+ bNodeSocket *socket_selection = socket_geo->next;
+ bNodeSocket *socket_float_attr = socket_selection->next;
bNodeSocket *socket_float3_attr = socket_float_attr->next;
bNodeSocket *socket_float_mean = (bNodeSocket *)node->outputs.first;
@@ -112,6 +114,54 @@ static void geo_node_attribute_statistic_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3);
}
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const bNodeType &node_type = params.node_type();
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (params.in_out() == SOCK_IN) {
+ if (params.other_socket().type == SOCK_GEOMETRY) {
+ params.add_item(IFACE_("Geometry"), [node_type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ params.connect_available_socket(node, "Geometry");
+ });
+ }
+ if (type) {
+ params.add_item(IFACE_("Attribute"), [&](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+ }
+ else if (type) {
+ /* Only use the first 8 declarations since we set the type automatically. */
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ for (const SocketDeclarationPtr &socket_decl : declaration.outputs().take_front(8)) {
+ StringRefNull name = socket_decl->name();
+ params.add_item(IFACE_(name.c_str()), [node_type, name, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, name);
+ });
+ }
+ }
+}
+
template<typename T> static T compute_sum(const Span<T> data)
{
return std::accumulate(data.begin(), data.end(), T());
@@ -146,65 +196,40 @@ static float median_of_sorted_span(const Span<float> data)
}
return median;
}
-static void set_empty(CustomDataType data_type, GeoNodeExecParams &params)
-{
- if (data_type == CD_PROP_FLOAT) {
- params.set_output("Mean", 0.0f);
- params.set_output("Median", 0.0f);
- params.set_output("Sum", 0.0f);
- params.set_output("Min", 0.0f);
- params.set_output("Max", 0.0f);
- params.set_output("Range", 0.0f);
- params.set_output("Standard Deviation", 0.0f);
- params.set_output("Variance", 0.0f);
- }
- else if (data_type == CD_PROP_FLOAT3) {
- params.set_output("Mean_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Median_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Sum_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Min_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Max_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Range_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Standard Deviation_001", float3{0.0f, 0.0f, 0.0f});
- params.set_output("Variance_001", float3{0.0f, 0.0f, 0.0f});
- }
-}
-static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry");
-
const bNode &node = params.node();
const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2);
-
- int64_t total_size = 0;
Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
- for (const GeometryComponent *component : components) {
- if (component->attribute_domain_supported(domain)) {
- total_size += component->attribute_domain_size(domain);
- }
- }
- if (total_size == 0) {
- set_empty(data_type, params);
- return;
- }
+ const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
switch (data_type) {
case CD_PROP_FLOAT: {
const Field<float> input_field = params.get_input<Field<float>>("Attribute");
- Array<float> data = Array<float>(total_size);
- int offset = 0;
+ Vector<float> data;
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
const int domain_size = component->attribute_domain_size(domain);
+
fn::FieldEvaluator data_evaluator{field_context, domain_size};
- MutableSpan<float> component_result = data.as_mutable_span().slice(offset, domain_size);
- data_evaluator.add_with_destination(input_field, component_result);
+ data_evaluator.add(input_field);
+ data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- offset += domain_size;
+ const VArray<float> &component_data = data_evaluator.get_evaluated<float>(0);
+ const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
+
+ const int next_data_index = data.size();
+ data.resize(next_data_index + selection.size());
+ MutableSpan<float> selected_data = data.as_mutable_span().slice(next_data_index,
+ selection.size());
+ for (const int i : selection.index_range()) {
+ selected_data[i] = component_data[selection[i]];
+ }
}
}
@@ -225,7 +250,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
const bool variance_required = params.output_is_required("Standard Deviation") ||
params.output_is_required("Variance");
- if (total_size != 0) {
+ if (data.size() != 0) {
if (sort_required) {
std::sort(data.begin(), data.end());
median = median_of_sorted_span(data);
@@ -236,7 +261,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
if (sum_required || variance_required) {
sum = compute_sum<float>(data);
- mean = sum / total_size;
+ mean = sum / data.size();
if (variance_required) {
variance = compute_variance(data, mean);
@@ -263,18 +288,26 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
case CD_PROP_FLOAT3: {
const Field<float3> input_field = params.get_input<Field<float3>>("Attribute_001");
-
- Array<float3> data = Array<float3>(total_size);
- int offset = 0;
+ Vector<float3> data;
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
const int domain_size = component->attribute_domain_size(domain);
+
fn::FieldEvaluator data_evaluator{field_context, domain_size};
- MutableSpan<float3> component_result = data.as_mutable_span().slice(offset, domain_size);
- data_evaluator.add_with_destination(input_field, component_result);
+ data_evaluator.add(input_field);
+ data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- offset += domain_size;
+ const VArray<float3> &component_data = data_evaluator.get_evaluated<float3>(0);
+ const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
+
+ const int next_data_index = data.size();
+ data.resize(data.size() + selection.size());
+ MutableSpan<float3> selected_data = data.as_mutable_span().slice(next_data_index,
+ selection.size());
+ for (const int i : selection.index_range()) {
+ selected_data[i] = component_data[selection[i]];
+ }
}
}
@@ -299,9 +332,9 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
Array<float> data_y;
Array<float> data_z;
if (sort_required || variance_required) {
- data_x.reinitialize(total_size);
- data_y.reinitialize(total_size);
- data_z.reinitialize(total_size);
+ data_x.reinitialize(data.size());
+ data_y.reinitialize(data.size());
+ data_z.reinitialize(data.size());
for (const int i : data.index_range()) {
data_x[i] = data[i].x;
data_y[i] = data[i].y;
@@ -309,7 +342,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
}
- if (total_size != 0) {
+ if (data.size() != 0) {
if (sort_required) {
std::sort(data_x.begin(), data_x.end());
std::sort(data_y.begin(), data_y.end());
@@ -326,7 +359,7 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
if (sum_required || variance_required) {
sum = compute_sum(data.as_span());
- mean = sum / total_size;
+ mean = sum / data.size();
if (variance_required) {
const float x_variance = compute_variance(data_x, mean.x);
@@ -360,19 +393,22 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_attribute_statistic_cc
void register_node_type_geo_attribute_statistic()
{
+ namespace file_ns = blender::nodes::node_geo_attribute_statistic_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0);
- ntype.declare = blender::nodes::geo_node_attribute_statistic_declare;
- node_type_init(&ntype, blender::nodes::geo_node_attribute_statistic_init);
- node_type_update(&ntype, blender::nodes::geo_node_attribute_statistic_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_attribute_statistic_exec;
- ntype.draw_buttons = blender::nodes::geo_node_attribute_statistic_layout;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index dba051fe13d..0947632cc09 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -23,9 +23,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_boolean_cc {
-static void geo_node_boolean_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh 1"))
.only_realized_data()
@@ -36,12 +36,12 @@ static void geo_node_boolean_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_boolean_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
-static void geo_node_boolean_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
@@ -63,12 +63,12 @@ static void geo_node_boolean_update(bNodeTree *ntree, bNode *node)
}
}
-static void geo_node_boolean_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
node->custom1 = GEO_NODE_BOOLEAN_DIFFERENCE;
}
-static void geo_node_boolean_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)params.node().custom1;
const bool use_self = params.get_input<bool>("Self Intersection");
@@ -119,17 +119,19 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_boolean_cc
void register_node_type_geo_boolean()
{
+ namespace file_ns = blender::nodes::node_geo_boolean_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_boolean_declare;
- ntype.draw_buttons = blender::nodes::geo_node_boolean_layout;
- ntype.updatefunc = blender::nodes::geo_node_boolean_update;
- node_type_init(&ntype, blender::nodes::geo_node_boolean_init);
- ntype.geometry_node_execute = blender::nodes::geo_node_boolean_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.updatefunc = file_ns::node_update;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
index e7c9715934a..da1f9a00c69 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_bounding_box_cc {
-static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Bounding Box"));
@@ -26,7 +26,7 @@ static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Max"));
}
-static void geo_node_bounding_box_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -78,14 +78,16 @@ static void geo_node_bounding_box_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_bounding_box_cc
void register_node_type_geo_bounding_box()
{
+ namespace file_ns = blender::nodes::node_geo_bounding_box_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_bounding_box_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_bounding_box_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
index 503711fedfe..6b8c895879d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -27,9 +27,11 @@
#include <algorithm>
-namespace blender::nodes {
+namespace blender::nodes::node_geo_collection_info_cc {
-static void geo_node_collection_info_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCollectionInfo)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Collection>(N_("Collection")).hide_label();
b.add_input<decl::Bool>(N_("Separate Children"))
@@ -42,12 +44,12 @@ static void geo_node_collection_info_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_collection_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_collection_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN(
sizeof(NodeGeometryCollectionInfo), __func__);
@@ -61,14 +63,12 @@ struct InstanceListEntry {
float4x4 transform;
};
-static void geo_node_collection_info_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Collection *collection = params.get_input<Collection *>("Collection");
- GeometrySet geometry_set_out;
-
if (collection == nullptr) {
- params.set_output("Geometry", geometry_set_out);
+ params.set_default_remaining_outputs();
return;
}
const Object *self_object = params.self_object();
@@ -76,15 +76,15 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
(Object *)self_object);
if (is_recursive) {
params.error_message_add(NodeWarningType::Error, "Collection contains current object");
- params.set_output("Geometry", geometry_set_out);
+ params.set_default_remaining_outputs();
return;
}
- const bNode &bnode = params.node();
- NodeGeometryCollectionInfo *node_storage = (NodeGeometryCollectionInfo *)bnode.storage;
- const bool use_relative_transform = (node_storage->transform_space ==
+ const NodeGeometryCollectionInfo &storage = node_storage(params.node());
+ const bool use_relative_transform = (storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
+ GeometrySet geometry_set_out;
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
const bool separate_children = params.get_input<bool>("Separate Children");
@@ -155,20 +155,22 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params)
params.set_output("Geometry", geometry_set_out);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_collection_info_cc
void register_node_type_geo_collection_info()
{
+ namespace file_ns = blender::nodes::node_geo_collection_info_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::geo_node_collection_info_declare;
- node_type_init(&ntype, blender::nodes::geo_node_collection_info_node_init);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(&ntype,
"NodeGeometryCollectionInfo",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_collection_info_exec;
- ntype.draw_buttons = blender::nodes::geo_node_collection_info_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc
index 9ebbdd349de..64b7a80bdb4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_common.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc
@@ -22,7 +22,7 @@
#include "node_common.h"
#include "node_geometry_util.hh"
-void register_node_type_geo_group(void)
+void register_node_type_geo_group()
{
static bNodeType ntype;
@@ -37,7 +37,7 @@ void register_node_type_geo_group(void)
node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 221fb421ab4..56c1e95bd70 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -28,9 +28,9 @@
# include "RBI_hull_api.h"
#endif
-namespace blender::nodes {
+namespace blender::nodes::node_geo_convex_hull_cc {
-static void geo_node_convex_hull_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Convex Hull"));
@@ -296,7 +296,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set)
#endif /* WITH_BULLET */
-static void geo_node_convex_hull_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -312,18 +312,20 @@ static void geo_node_convex_hull_exec(GeoNodeExecParams params)
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without Bullet"));
- params.set_output("Convex Hull", geometry_set);
+ params.set_default_remaining_outputs();
#endif /* WITH_BULLET */
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_convex_hull_cc
void register_node_type_geo_convex_hull()
{
+ namespace file_ns = blender::nodes::node_geo_convex_hull_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_convex_hull_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_convex_hull_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index c41b76412e9..fc407414667 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -21,9 +21,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_endpoint_select_cc {
-static void geo_node_curve_endpoint_selection_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Start Size"))
.min(0)
@@ -51,69 +51,61 @@ static void select_by_spline(const int start, const int end, MutableSpan<bool> r
r_selection.slice(size - end_use, end_use).fill(true);
}
-class EndpointFieldInput final : public fn::FieldInput {
+class EndpointFieldInput final : public GeometryFieldInput {
Field<int> start_size_;
Field<int> end_size_;
public:
EndpointFieldInput(Field<int> start_size, Field<int> end_size)
- : FieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
+ : GeometryFieldInput(CPPType::get<bool>(), "Endpoint Selection node"),
start_size_(start_size),
end_size_(end_size)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
+ return nullptr;
+ }
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
- return nullptr;
- }
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
+ Array<int> control_point_offsets = curve->control_point_offsets();
- Array<int> control_point_offsets = curve->control_point_offsets();
+ if (curve == nullptr || control_point_offsets.last() == 0) {
+ return nullptr;
+ }
- if (curve == nullptr || control_point_offsets.last() == 0) {
- return nullptr;
+ GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{size_context, curve->splines().size()};
+ evaluator.add(start_size_);
+ evaluator.add(end_size_);
+ evaluator.evaluate();
+ const VArray<int> &start_size = evaluator.get_evaluated<int>(0);
+ const VArray<int> &end_size = evaluator.get_evaluated<int>(1);
+
+ const int point_size = control_point_offsets.last();
+ Array<bool> selection(point_size, false);
+ int current_point = 0;
+ MutableSpan<bool> selection_span = selection.as_mutable_span();
+ for (int i : IndexRange(curve->splines().size())) {
+ const SplinePtr &spline = curve->splines()[i];
+ if (start_size[i] <= 0 && end_size[i] <= 0) {
+ selection_span.slice(current_point, spline->size()).fill(false);
}
-
- GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
- fn::FieldEvaluator evaluator{size_context, curve->splines().size()};
- evaluator.add(start_size_);
- evaluator.add(end_size_);
- evaluator.evaluate();
- const VArray<int> &start_size = evaluator.get_evaluated<int>(0);
- const VArray<int> &end_size = evaluator.get_evaluated<int>(1);
-
- const int point_size = control_point_offsets.last();
- Array<bool> selection(point_size, false);
- int current_point = 0;
- MutableSpan<bool> selection_span = selection.as_mutable_span();
- for (int i : IndexRange(curve->splines().size())) {
- const SplinePtr &spline = curve->splines()[i];
- if (start_size[i] <= 0 && end_size[i] <= 0) {
- selection_span.slice(current_point, spline->size()).fill(false);
- }
- else {
- int start_use = std::max(start_size[i], 0);
- int end_use = std::max(end_size[i], 0);
- select_by_spline(
- start_use, end_use, selection_span.slice(current_point, spline->size()));
- }
- current_point += spline->size();
+ else {
+ int start_use = std::max(start_size[i], 0);
+ int end_use = std::max(end_size[i], 0);
+ select_by_spline(start_use, end_use, selection_span.slice(current_point, spline->size()));
}
- return VArray<bool>::ForContainer(std::move(selection));
+ current_point += spline->size();
}
- return {};
+ return VArray<bool>::ForContainer(std::move(selection));
};
uint64_t hash() const override
@@ -131,23 +123,25 @@ class EndpointFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_curve_endpoint_selection_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> start_size = params.extract_input<Field<int>>("Start Size");
Field<int> end_size = params.extract_input<Field<int>>("End Size");
Field<bool> selection_field{std::make_shared<EndpointFieldInput>(start_size, end_size)};
params.set_output("Selection", std::move(selection_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_endpoint_select_cc
void register_node_type_geo_curve_endpoint_selection()
{
+ namespace file_ns = blender::nodes::node_geo_curve_endpoint_select_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::geo_node_curve_endpoint_selection_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoint_selection_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index 219effadec4..3aabf8e21eb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -31,20 +31,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_fill_cc {
-static void geo_node_curve_fill_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveFill)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_curve_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_fill_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill),
__func__);
@@ -147,11 +149,11 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
geometry_set.replace_curve(nullptr);
}
-static void geo_node_curve_fill_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- const NodeGeometryCurveFill &storage = *(const NodeGeometryCurveFill *)params.node().storage;
+ const NodeGeometryCurveFill &storage = node_storage(params.node());
const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode;
geometry_set.modify_geometry_sets(
@@ -160,19 +162,21 @@ static void geo_node_curve_fill_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_fill_cc
void register_node_type_geo_curve_fill()
{
+ namespace file_ns = blender::nodes::node_geo_curve_fill_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_fill_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryCurveFill", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_fill_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_fill_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_fill_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index a320f35c539..a438c1d6086 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -25,12 +25,19 @@
#include "BKE_spline.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_fillet_cc {
-static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveFillet)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
- b.add_input<decl::Int>(N_("Count")).default_value(1).min(1).max(1000).supports_field();
+ b.add_input<decl::Int>(N_("Count"))
+ .default_value(1)
+ .min(1)
+ .max(1000)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_FILLET_POLY; });
b.add_input<decl::Float>(N_("Radius"))
.min(0.0f)
.max(FLT_MAX)
@@ -41,12 +48,12 @@ static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_fillet_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_fillet_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN(
sizeof(NodeGeometryCurveFillet), __func__);
@@ -76,10 +83,10 @@ struct FilletData {
Array<int> counts;
};
-static void geo_node_curve_fillet_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)node->storage;
- const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
+ const NodeGeometryCurveFillet &storage = node_storage(*node);
+ const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode;
bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next;
@@ -332,14 +339,17 @@ static void copy_common_attributes_by_mapping(const Spline &src,
copy_attribute_by_mapping(src.radii(), dst.radii(), mapping);
copy_attribute_by_mapping(src.tilts(), dst.tilts(), mapping);
- dst.attributes.reallocate(1);
src.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id);
if (dst.attributes.create(attribute_id, meta_data.data_type)) {
std::optional<GMutableSpan> dst_attribute = dst.attributes.get_for_write(attribute_id);
if (dst_attribute) {
- src_attribute->type().copy_assign(src_attribute->data(), dst_attribute->data());
+ attribute_math::convert_to_static_type(dst_attribute->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_attribute_by_mapping(
+ src_attribute->typed<T>(), dst_attribute->typed<T>(), mapping);
+ });
return true;
}
}
@@ -607,12 +617,12 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
geometry_set.replace_curve(output_curve.release());
}
-static void geo_node_fillet_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)params.node().storage;
- const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
+ const NodeGeometryCurveFillet &storage = node_storage(params.node());
+ const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode;
Field<float> radius_field = params.extract_input<Field<float>>("Radius");
const bool limit_radius = params.extract_input<bool>("Limit Radius");
@@ -629,19 +639,21 @@ static void geo_node_fillet_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_fillet_cc
void register_node_type_geo_curve_fillet()
{
+ namespace file_ns = blender::nodes::node_geo_curve_fillet_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.draw_buttons = blender::nodes::geo_node_curve_fillet_layout;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_fillet_declare;
- node_type_init(&ntype, blender::nodes::geo_node_curve_fillet_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_fillet_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_fillet_exec;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index 5fb17270301..381bb0fc1d0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -21,22 +21,22 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_handle_type_selection_cc {
-static void geo_node_curve_handle_type_selection_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveSelectHandles)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Selection")).field_source();
}
-static void geo_node_curve_handle_type_selection_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_handle_type_selection_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
sizeof(NodeGeometryCurveSelectHandles), __func__);
@@ -85,44 +85,40 @@ static void select_by_handle_type(const CurveEval &curve,
}
}
-class HandleTypeFieldInput final : public fn::FieldInput {
+class HandleTypeFieldInput final : public GeometryFieldInput {
BezierSpline::HandleType type_;
GeometryNodeCurveHandleMode mode_;
public:
HandleTypeFieldInput(BezierSpline::HandleType type, GeometryNodeCurveHandleMode mode)
- : FieldInput(CPPType::get<bool>(), "Handle Type Selection node"), type_(type), mode_(mode)
+ : GeometryFieldInput(CPPType::get<bool>(), "Handle Type Selection node"),
+ type_(type),
+ mode_(mode)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
- return {};
- }
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
+ return {};
+ }
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve == nullptr) {
- return {};
- }
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve == nullptr) {
+ return {};
+ }
- if (domain == ATTR_DOMAIN_POINT) {
- Array<bool> selection(mask.min_array_size());
- select_by_handle_type(*curve, type_, mode_, selection);
- return VArray<bool>::ForContainer(std::move(selection));
- }
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<bool> selection(mask.min_array_size());
+ select_by_handle_type(*curve, type_, mode_, selection);
+ return VArray<bool>::ForContainer(std::move(selection));
}
return {};
- };
+ }
uint64_t hash() const override
{
@@ -140,34 +136,35 @@ class HandleTypeFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_curve_handle_type_selection_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveSelectHandles *storage =
- (const NodeGeometryCurveSelectHandles *)params.node().storage;
+ const NodeGeometryCurveSelectHandles &storage = node_storage(params.node());
const BezierSpline::HandleType handle_type = handle_type_from_input_type(
- (GeometryNodeCurveHandleType)storage->handle_type);
- const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode;
+ (GeometryNodeCurveHandleType)storage.handle_type);
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
Field<bool> selection_field{std::make_shared<HandleTypeFieldInput>(handle_type, mode)};
params.set_output("Selection", std::move(selection_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_handle_type_selection_cc
void register_node_type_geo_curve_handle_type_selection()
{
+ namespace file_ns = blender::nodes::node_geo_curve_handle_type_selection_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::geo_node_curve_handle_type_selection_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_handle_type_selection_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_handle_type_selection_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSelectHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_handle_type_selection_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index 0d0dc0ec89c..73ad8a8cf65 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -17,19 +17,19 @@
#include "BKE_spline.hh"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_length_cc {
-static void geo_node_curve_length_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_output<decl::Float>(N_("Length"));
}
-static void geo_node_curve_length_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
if (!curve_set.has_curve()) {
- params.set_output("Length", 0.0f);
+ params.set_default_remaining_outputs();
return;
}
const CurveEval &curve = *curve_set.get_curve_for_read();
@@ -40,14 +40,16 @@ static void geo_node_curve_length_exec(GeoNodeExecParams params)
params.set_output("Length", length);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_length_cc
void register_node_type_geo_curve_length()
{
+ namespace file_ns = blender::nodes::node_geo_curve_length_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_length_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_length_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 673a5095044..4299b5cc022 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc {
-static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveBezierSegment)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Resolution"))
.default_value(16)
@@ -53,14 +55,12 @@ static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuild
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_bezier_segment_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_bezier_segment_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *)
MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__);
@@ -120,12 +120,11 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
return curve;
}
-static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveBezierSegment *node_storage =
- (NodeGeometryCurvePrimitiveBezierSegment *)params.node().storage;
+ const NodeGeometryCurvePrimitiveBezierSegment &storage = node_storage(params.node());
const GeometryNodeCurvePrimitiveBezierSegmentMode mode =
- (const GeometryNodeCurvePrimitiveBezierSegmentMode)node_storage->mode;
+ (const GeometryNodeCurvePrimitiveBezierSegmentMode)storage.mode;
std::unique_ptr<CurveEval> curve = create_bezier_segment_curve(
params.extract_input<float3>("Start"),
@@ -137,20 +136,22 @@ static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams param
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc
void register_node_type_geo_curve_primitive_bezier_segment()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_bezier_segment_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_bezier_segment_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveBezierSegment",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_bezier_segment_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_bezier_segment_layout;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_bezier_segment_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 5d8beb9c9d8..70abf4c64a7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_circle_cc {
-static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveCircle)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Resolution"))
.default_value(32)
@@ -54,17 +56,17 @@ static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b)
.subtype(PROP_DISTANCE)
.description(N_("Distance of the points from the origin"));
b.add_output<decl::Geometry>(N_("Curve"));
- b.add_output<decl::Vector>(N_("Center"));
+ b.add_output<decl::Vector>(N_("Center")).make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS;
+ });
}
-static void geo_node_curve_primitive_circle_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN(
sizeof(NodeGeometryCurvePrimitiveCircle), __func__);
@@ -73,12 +75,11 @@ static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode
node->storage = data;
}
-static void geo_node_curve_primitive_circle_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *)
- node->storage;
- const GeometryNodeCurvePrimitiveCircleMode mode = (const GeometryNodeCurvePrimitiveCircleMode)
- node_storage->mode;
+ const NodeGeometryCurvePrimitiveCircle &storage = node_storage(*node);
+ const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode)
+ storage.mode;
bNodeSocket *start_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *middle_socket = start_socket->next;
@@ -195,13 +196,11 @@ static std::unique_ptr<CurveEval> create_radius_circle_curve(const int resolutio
return curve;
}
-static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveCircle *node_storage =
- (NodeGeometryCurvePrimitiveCircle *)params.node().storage;
-
+ const NodeGeometryCurvePrimitiveCircle &storage = node_storage(params.node());
const GeometryNodeCurvePrimitiveCircleMode mode = (GeometryNodeCurvePrimitiveCircleMode)
- node_storage->mode;
+ storage.mode;
std::unique_ptr<CurveEval> curve;
if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) {
@@ -222,26 +221,28 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
else {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_circle_cc
void register_node_type_geo_curve_primitive_circle()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_circle_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_circle_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveCircle",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_circle_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_circle_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_circle_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index 238fc77e1cc..6d71c97b15a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_line_cc {
-static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveLine)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Vector>(N_("Start"))
.subtype(PROP_TRANSLATION)
@@ -43,14 +45,12 @@ static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_line_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN(
sizeof(NodeGeometryCurvePrimitiveLine), __func__);
@@ -59,12 +59,10 @@ static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *n
node->storage = data;
}
-static void geo_node_curve_primitive_line_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurvePrimitiveLine *node_storage = (NodeGeometryCurvePrimitiveLine *)
- node->storage;
- const GeometryNodeCurvePrimitiveLineMode mode = (const GeometryNodeCurvePrimitiveLineMode)
- node_storage->mode;
+ const NodeGeometryCurvePrimitiveLine &storage = node_storage(*node);
+ const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode;
bNodeSocket *p2_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *direction_socket = p2_socket->next;
@@ -112,13 +110,10 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start
return curve;
}
-static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
-
- const NodeGeometryCurvePrimitiveLine *node_storage =
- (NodeGeometryCurvePrimitiveLine *)params.node().storage;
-
- GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)node_storage->mode;
+ const NodeGeometryCurvePrimitiveLine &storage = node_storage(params.node());
+ const GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)storage.mode;
std::unique_ptr<CurveEval> curve;
if (mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS) {
@@ -134,20 +129,22 @@ static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_line_cc
void register_node_type_geo_curve_primitive_line()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_line_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_line_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveLine",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_curve_primitive_line_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_line_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_line_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
index 27bf4a310df..92a9b1b4966 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
@@ -17,9 +17,9 @@
#include "BKE_spline.hh"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc {
-static void geo_node_curve_primitive_quadratic_bezier_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Resolution"))
.default_value(16)
@@ -64,7 +64,7 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
return curve;
}
-static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
std::unique_ptr<CurveEval> curve = create_quadratic_bezier_curve(
params.extract_input<float3>("Start"),
@@ -74,17 +74,19 @@ static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams par
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc
void register_node_type_geo_curve_primitive_quadratic_bezier()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER,
"Quadratic Bezier",
NODE_CLASS_GEOMETRY,
0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_quadratic_bezier_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadratic_bezier_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index 114ae441d99..ff6294b9b6b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -17,11 +17,16 @@
#include "BKE_spline.hh"
#include "UI_interface.h"
#include "UI_resources.h"
+
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveQuad)
-static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>(N_("Width"))
.default_value(2.0f)
@@ -77,14 +82,12 @@ static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilde
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN(
sizeof(NodeGeometryCurvePrimitiveQuad), __func__);
@@ -92,11 +95,11 @@ static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree),
node->storage = data;
}
-static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage;
+ const NodeGeometryCurvePrimitiveQuad &storage = node_storage(*node);
GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
- node_storage.mode);
+ storage.mode);
bNodeSocket *width = ((bNodeSocket *)node->inputs.first);
bNodeSocket *height = width->next;
@@ -142,6 +145,41 @@ static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *ntree, bNod
}
}
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ GeometryNodeCurvePrimitiveQuadMode quad_mode;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("GeometryNodeCurvePrimitiveQuadrilateral");
+ node_storage(node).mode = quad_mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ }
+ else if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Width"),
+ SocketSearchOp{"Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE});
+ params.add_item(IFACE_("Height"),
+ SocketSearchOp{"Height", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE});
+ params.add_item(IFACE_("Bottom Width"),
+ SocketSearchOp{"Bottom Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID});
+ params.add_item(IFACE_("Top Width"),
+ SocketSearchOp{"Top Width", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID});
+ params.add_item(IFACE_("Offset"),
+ SocketSearchOp{"Offset", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM});
+ params.add_item(IFACE_("Point 1"),
+ SocketSearchOp{"Point 1", GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS});
+ }
+}
+
static void create_rectangle_curve(MutableSpan<float3> positions,
const float height,
const float width)
@@ -197,12 +235,10 @@ static void create_kite_curve(MutableSpan<float3> positions,
positions[3] = float3(-width / 2.0f, 0, 0);
}
-static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurvePrimitiveQuad &node_storage =
- *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage;
- const GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
- node_storage.mode);
+ const NodeGeometryCurvePrimitiveQuad &storage = node_storage(params.node());
+ const GeometryNodeCurvePrimitiveQuadMode mode = (GeometryNodeCurvePrimitiveQuadMode)storage.mode;
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
@@ -246,7 +282,7 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params
params.extract_input<float3>("Point 4"));
break;
default:
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -255,21 +291,24 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc
void register_node_type_geo_curve_primitive_quadrilateral()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_quadrilaterial_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_quadrilateral_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_quadrilateral_layout;
- node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update);
- node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveQuad",
node_free_standard_storage,
node_copy_standard_storage);
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index 1384165e520..d5ae3551904 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_spiral_cc {
-static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Resolution"))
.default_value(32)
@@ -81,11 +81,11 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
return curve;
}
-static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const float rotations = std::max(params.extract_input<float>("Rotations"), 0.0f);
if (rotations == 0.0f) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -99,14 +99,16 @@ static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_spiral_cc
void register_node_type_geo_curve_primitive_spiral()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_spiral_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_spiral_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_spiral_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 9004681c246..731be0f0f49 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_primitive_star_cc {
-static void geo_node_curve_primitive_star_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Points"))
.default_value(8)
@@ -85,7 +85,7 @@ static void create_selection_output(CurveComponent &component,
attribute.save();
}
-static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
std::unique_ptr<CurveEval> curve = create_star_curve(
std::max(params.extract_input<float>("Inner Radius"), 0.0f),
@@ -103,13 +103,15 @@ static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params)
}
params.set_output("Curve", std::move(output));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_primitive_star_cc
void register_node_type_geo_curve_primitive_star()
{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_primitive_star_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_star_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index f72978bae50..7e465714265 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -26,9 +26,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_resample_cc {
-static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveResample)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
@@ -41,12 +43,12 @@ static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_resample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN(
sizeof(NodeGeometryCurveResample), __func__);
@@ -55,10 +57,10 @@ static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_resample_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)node->storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveResample &storage = node_storage(*node);
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next->next;
bNodeSocket *length_socket = count_socket->next;
@@ -189,7 +191,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
BLI_assert(mode_param.count);
- if (selections[i]) {
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1));
}
else {
@@ -208,7 +210,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- if (selections[i]) {
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
/* Don't allow asymptotic count increase for low resolution values. */
const float divide_length = std::max(lengths[i], 0.0001f);
const float spline_length = input_splines[i]->length();
@@ -229,7 +231,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component
threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
- if (selections[i]) {
+ if (selections[i] && input_splines[i]->evaluated_points_size() > 0) {
output_splines[i] = resample_spline_evaluated(*input_splines[i]);
}
else {
@@ -255,12 +257,12 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set,
geometry_set.replace_curve(output_curve.release());
}
-static void geo_node_resample_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)params.node().storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveResample &storage = node_storage(params.node());
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
SampleModeParam mode_param;
mode_param.mode = mode;
@@ -269,7 +271,7 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
Field<int> count = params.extract_input<Field<int>>("Count");
if (count < 1) {
- params.set_output("Curve", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
mode_param.count.emplace(count);
@@ -285,19 +287,21 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_resample_cc
void register_node_type_geo_curve_resample()
{
+ namespace file_ns = blender::nodes::node_geo_curve_resample_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_resample_declare;
- ntype.draw_buttons = blender::nodes::geo_node_curve_resample_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveResample", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_resample_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_resample_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_resample_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index b1dc45a426a..d07e89ec7f2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -20,16 +20,16 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_reverse_cc {
-static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -60,13 +60,15 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_reverse_cc
void register_node_type_geo_curve_reverse()
{
+ namespace file_ns = blender::nodes::node_geo_curve_reverse_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_reverse_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index 8f42aacab43..eff760266f5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -23,27 +23,37 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_sample_cc {
-static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveSample)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve"))
.only_realized_data()
.supported_type(GEO_COMPONENT_TYPE_CURVE);
- b.add_input<decl::Float>(N_("Factor")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
- b.add_input<decl::Float>(N_("Length")).min(0.0f).subtype(PROP_DISTANCE).supports_field();
-
+ b.add_input<decl::Float>(N_("Factor"))
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; });
+ b.add_input<decl::Float>(N_("Length"))
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .supports_field()
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; });
b.add_output<decl::Vector>(N_("Position")).dependent_field();
b.add_output<decl::Vector>(N_("Tangent")).dependent_field();
b.add_output<decl::Vector>(N_("Normal")).dependent_field();
}
-static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_type_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN(
sizeof(NodeGeometryCurveSample), __func__);
@@ -51,10 +61,10 @@ static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node
node->storage = data;
}
-static void geo_node_curve_sample_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)node->storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveSample &storage = node_storage(*node);
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
bNodeSocket *factor = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *length = factor->next;
@@ -200,8 +210,8 @@ class SampleCurveFunction : public fn::MultiFunction {
static Field<float> get_length_input_field(const GeoNodeExecParams &params,
const float curve_total_length)
{
- const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)params.node().storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveSample &storage = node_storage(params.node());
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
/* Just make sure the length is in bounds of the curve. */
@@ -229,34 +239,32 @@ static Field<float> get_length_input_field(const GeoNodeExecParams &params,
return Field<float>(std::move(process_op), 0);
}
-static void geo_node_curve_sample_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- auto return_default = [&]() {
- params.set_output("Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Tangent", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- };
-
const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
if (component == nullptr) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const CurveEval *curve = component->get_for_read();
if (curve == nullptr) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
if (curve->splines().is_empty()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
Array<float> spline_lengths = curve->accumulated_spline_lengths();
const float total_length = spline_lengths.last();
if (total_length == 0.0f) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
Field<float> length_field = get_length_input_field(params, total_length);
@@ -271,20 +279,22 @@ static void geo_node_curve_sample_exec(GeoNodeExecParams params)
params.set_output("Normal", Field<float3>(sample_op, 2));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_sample_cc
void register_node_type_geo_curve_sample()
{
+ namespace file_ns = blender::nodes::node_geo_curve_sample_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, " Sample Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_sample_exec;
- ntype.declare = blender::nodes::geo_node_curve_sample_declare;
- node_type_init(&ntype, blender::nodes::geo_node_curve_sample_type_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_sample_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_type_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryCurveSample", node_free_standard_storage, node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_sample_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
index 8b0a6ca840c..8c0827570c6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -21,24 +21,24 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_set_handles_cc {
-static void geo_node_curve_set_handles_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveSetHandles)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_set_handles_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
sizeof(NodeGeometryCurveSetHandles), __func__);
@@ -64,12 +64,11 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan
return BezierSpline::HandleType::Auto;
}
-static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveSetHandles *node_storage =
- (NodeGeometryCurveSetHandles *)params.node().storage;
- const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)node_storage->handle_type;
- const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
+ const NodeGeometryCurveSetHandles &storage = node_storage(params.node());
+ const GeometryNodeCurveHandleType type = (GeometryNodeCurveHandleType)storage.handle_type;
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -130,21 +129,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params)
}
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_set_handles_cc
void register_node_type_geo_curve_set_handles()
{
+ namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_set_handles_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSetHandles",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index 63518b38090..de352d217ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -20,9 +20,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_spline_parameter_cc {
-static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Factor"))
.field_source()
@@ -34,6 +34,9 @@ static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b)
.description(
N_("For points, the distance along the control point's spline, For splines, the "
"distance along the entire curve"));
+ b.add_output<decl::Int>(N_("Index"))
+ .field_source()
+ .description(N_("Each control point's index on its spline"));
}
/**
@@ -182,29 +185,39 @@ static VArray<float> construct_curve_length_varray(const CurveEval &curve,
return {};
}
-class CurveParameterFieldInput final : public fn::FieldInput {
+static VArray<int> construct_index_on_spline_varray(const CurveEval &curve,
+ const IndexMask UNUSED(mask),
+ const AttributeDomain domain)
+{
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> output(curve.total_control_point_size());
+ int output_index = 0;
+ for (int spline_index : curve.splines().index_range()) {
+ for (int point_index : IndexRange(curve.splines()[spline_index]->size())) {
+ output[output_index++] = point_index;
+ }
+ }
+ return VArray<int>::ForContainer(std::move(output));
+ }
+ return {};
+}
+
+class CurveParameterFieldInput final : public GeometryFieldInput {
public:
- CurveParameterFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Parameter node")
+ CurveParameterFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Parameter node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
- return construct_curve_parameter_varray(*curve, mask, domain);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_curve_parameter_varray(*curve, mask, domain);
}
}
return {};
@@ -222,28 +235,22 @@ class CurveParameterFieldInput final : public fn::FieldInput {
}
};
-class CurveLengthFieldInput final : public fn::FieldInput {
+class CurveLengthFieldInput final : public GeometryFieldInput {
public:
- CurveLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Length node")
+ CurveLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Curve Length node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
- return construct_curve_length_varray(*curve, mask, domain);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_curve_length_varray(*curve, mask, domain);
}
}
return {};
@@ -261,21 +268,59 @@ class CurveLengthFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_curve_parameter_exec(GeoNodeExecParams params)
+class IndexOnSplineFieldInput final : public GeometryFieldInput {
+ public:
+ IndexOnSplineFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveEval *curve = curve_component.get_for_read();
+ if (curve) {
+ return construct_index_on_spline_varray(*curve, mask, domain);
+ }
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 4536246522;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()};
Field<float> length_field{std::make_shared<CurveLengthFieldInput>()};
+ Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()};
params.set_output("Factor", std::move(parameter_field));
params.set_output("Length", std::move(length_field));
+ params.set_output("Index", std::move(index_on_spline_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_spline_parameter_cc
-void register_node_type_geo_curve_parameter()
+void register_node_type_geo_curve_spline_parameter()
{
+ namespace file_ns = blender::nodes::node_geo_curve_spline_parameter_cc;
+
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PARAMETER, "Curve Parameter", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_parameter_exec;
- ntype.declare = blender::nodes::geo_node_curve_parameter_declare;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT, 0);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index ae4453929ac..eef8c1b0db5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -23,23 +23,23 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_spline_type_cc {
-static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryCurveSplineType)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_spline_type_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
}
-static void geo_node_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
sizeof(NodeGeometryCurveSplineType), __func__);
@@ -238,11 +238,10 @@ static SplinePtr convert_to_nurbs(const Spline &input)
return {};
}
-static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveSplineType *storage =
- (const NodeGeometryCurveSplineType *)params.node().storage;
- const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage->spline_type;
+ const NodeGeometryCurveSplineType &storage = node_storage(params.node());
+ const GeometryNodeSplineType output_type = (const GeometryNodeSplineType)storage.spline_type;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -263,24 +262,28 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- for (const int i : curve.splines().index_range()) {
- if (selection[i]) {
- switch (output_type) {
- case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->add_spline(convert_to_poly_spline(*curve.splines()[i]));
- break;
- case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->add_spline(convert_to_bezier(*curve.splines()[i], params));
- break;
- case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->add_spline(convert_to_nurbs(*curve.splines()[i]));
- break;
+ new_curve->resize(curve.splines().size());
+
+ threading::parallel_for(curve.splines().index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ if (selection[i]) {
+ switch (output_type) {
+ case GEO_NODE_SPLINE_TYPE_POLY:
+ new_curve->splines()[i] = convert_to_poly_spline(*curve.splines()[i]);
+ break;
+ case GEO_NODE_SPLINE_TYPE_BEZIER:
+ new_curve->splines()[i] = convert_to_bezier(*curve.splines()[i], params);
+ break;
+ case GEO_NODE_SPLINE_TYPE_NURBS:
+ new_curve->splines()[i] = convert_to_nurbs(*curve.splines()[i]);
+ break;
+ }
+ }
+ else {
+ new_curve->splines()[i] = curve.splines()[i]->copy();
}
}
- else {
- new_curve->add_spline(curve.splines()[i]->copy());
- }
- }
+ });
new_curve->attributes = curve.attributes;
geometry_set.replace_curve(new_curve.release());
});
@@ -288,21 +291,23 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_spline_type_cc
void register_node_type_geo_curve_spline_type()
{
+ namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_spline_type_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_spline_type_exec;
- node_type_init(&ntype, blender::nodes::geo_node_curve_spline_type_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurveSplineType",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_curve_spline_type_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 7c4c17e69e0..6de188fc1c4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_subdivide_cc {
-static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Int>(N_("Cuts")).default_value(1).min(0).max(1000).supports_field();
@@ -322,7 +322,7 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
return output_curve;
}
-static void geo_node_subdivide_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<int> cuts_field = params.extract_input<Field<int>>("Cuts");
@@ -351,14 +351,16 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params)
params.set_output("Curve", geometry_set);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_subdivide_cc
void register_node_type_geo_curve_subdivide()
{
+ namespace file_ns = blender::nodes::node_geo_curve_subdivide_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_subdivide_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index 1977b465de4..ff3e85cb6b7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -23,9 +23,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_curve_to_mesh_cc {
-static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Geometry>(N_("Profile Curve"))
@@ -54,7 +54,7 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set,
}
}
-static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
@@ -72,14 +72,16 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(curve_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_to_mesh_cc
void register_node_type_geo_curve_to_mesh()
{
+ namespace file_ns = blender::nodes::node_geo_curve_to_mesh_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_to_mesh_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_mesh_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index b9f129a5f75..0e9425246cb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -27,24 +27,50 @@
#include "node_geometry_util.hh"
namespace blender::nodes {
+void curve_create_default_rotation_attribute(Span<float3> tangents,
+ Span<float3> normals,
+ MutableSpan<float3> rotations)
+{
+ threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ rotations[i] =
+ float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler();
+ }
+ });
+}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_curve_to_points_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurveToPoints)
-static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
- b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000);
- b.add_input<decl::Float>(N_("Length")).default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Int>(N_("Count"))
+ .default_value(10)
+ .min(2)
+ .max(100000)
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_RESAMPLE_COUNT; });
+ b.add_input<decl::Float>(N_("Length"))
+ .default_value(0.1f)
+ .min(0.001f)
+ .subtype(PROP_DISTANCE)
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_RESAMPLE_LENGTH; });
b.add_output<decl::Geometry>(N_("Points"));
b.add_output<decl::Vector>(N_("Tangent")).field_source();
b.add_output<decl::Vector>(N_("Normal")).field_source();
b.add_output<decl::Vector>(N_("Rotation")).field_source();
}
-static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
sizeof(NodeGeometryCurveToPoints), __func__);
@@ -53,10 +79,10 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_to_points_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveToPoints &storage = node_storage(*node);
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *length_socket = count_socket->next;
@@ -78,9 +104,14 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
return {0};
}
Array<int> offsets(size + 1);
- for (const int i : offsets.index_range()) {
- offsets[i] = count * i;
+ int offset = 0;
+ for (const int i : IndexRange(size)) {
+ offsets[i] = offset;
+ if (splines[i]->evaluated_points_size() > 0) {
+ offset += count;
+ }
}
+ offsets.last() = offset;
return offsets;
}
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
@@ -90,7 +121,9 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
int offset = 0;
for (const int i : IndexRange(size)) {
offsets[i] = offset;
- offset += splines[i]->length() / resolution + 1;
+ if (splines[i]->evaluated_points_size() > 0) {
+ offset += splines[i]->length() / resolution + 1;
+ }
}
offsets.last() = offset;
return offsets;
@@ -289,22 +322,10 @@ static void copy_spline_domain_attributes(const CurveEval &curve,
ATTR_DOMAIN_CURVE);
}
-void curve_create_default_rotation_attribute(Span<float3> tangents,
- Span<float3> normals,
- MutableSpan<float3> rotations)
+static void node_geo_exec(GeoNodeExecParams params)
{
- threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
- for (const int i : range) {
- rotations[i] =
- float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler();
- }
- });
-}
-
-static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
-{
- NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+ const NodeGeometryCurveToPoints &storage = node_storage(params.node());
+ const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
AnonymousAttributeIDs attribute_outputs;
@@ -374,20 +395,21 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_to_points_cc
void register_node_type_geo_curve_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_curve_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_curve_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update);
-
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index b281876d314..746392a66cc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -20,40 +20,52 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
+namespace blender::nodes::node_geo_curve_trim_cc {
+
using blender::attribute_math::mix2;
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
-static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
- b.add_input<decl::Float>(N_("Start")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field();
+ b.add_input<decl::Float>(N_("Start"))
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; })
+ .supports_field();
b.add_input<decl::Float>(N_("End"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
.subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR; })
.supports_field();
b.add_input<decl::Float>(N_("Start"), "Start_001")
.min(0.0f)
.subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; })
.supports_field();
b.add_input<decl::Float>(N_("End"), "End_001")
.min(0.0f)
.default_value(1.0f)
.subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH; })
.supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim),
__func__);
@@ -62,10 +74,10 @@ static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_trim_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveTrim &storage = node_storage(*node);
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
bNodeSocket *start_fac = ((bNodeSocket *)node->inputs.first)->next;
bNodeSocket *end_fac = start_fac->next;
@@ -78,6 +90,38 @@ static void geo_node_curve_trim_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
}
+class SocketSearchOp {
+ public:
+ StringRef socket_name;
+ GeometryNodeCurveSampleMode mode;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("GeometryNodeTrimCurve");
+ node_storage(node).mode = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+
+ search_link_ops_for_declarations(params, declaration.outputs());
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+
+ if (params.in_out() == SOCK_IN) {
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Start (Factor)"),
+ SocketSearchOp{"Start", GEO_NODE_CURVE_SAMPLE_FACTOR});
+ params.add_item(IFACE_("End (Factor)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_FACTOR});
+ params.add_item(IFACE_("Start (Length)"),
+ SocketSearchOp{"Start", GEO_NODE_CURVE_SAMPLE_LENGTH});
+ params.add_item(IFACE_("End (Length)"), SocketSearchOp{"End", GEO_NODE_CURVE_SAMPLE_LENGTH});
+ }
+ }
+}
+
struct TrimLocation {
/* Control point index at the start side of the trim location. */
int left_index;
@@ -532,10 +576,10 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
});
}
-static void geo_node_curve_trim_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+ const NodeGeometryCurveTrim &storage = node_storage(params.node());
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -557,18 +601,21 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_curve_trim_cc
void register_node_type_geo_curve_trim()
{
+ namespace file_ns = blender::nodes::node_geo_curve_trim_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec;
- ntype.draw_buttons = blender::nodes::geo_node_curve_trim_layout;
- ntype.declare = blender::nodes::geo_node_curve_trim_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_curve_trim_init);
- node_type_update(&ntype, blender::nodes::geo_node_curve_trim_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index d07644f8403..1de809b30e4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -29,63 +29,26 @@
#include "node_geometry_util.hh"
-using blender::bke::CustomDataAttributes;
-
-/* Code from the mask modifier in MOD_mask.cc. */
-extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map);
-extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map);
-extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- blender::Span<int> vertex_map,
- blender::Span<int> edge_map,
- blender::Span<int> masked_poly_indices,
- blender::Span<int> new_loop_starts);
-
namespace blender::nodes {
-static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Bool>(N_("Selection"))
- .default_value(true)
- .hide_value()
- .supports_field()
- .description(N_("The parts of the geometry to be deleted"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
+using blender::bke::CustomDataAttributes;
-static void geo_node_delete_geometry_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+template<typename T>
+static void copy_data_based_on_mask(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
{
- const bNode *node = static_cast<bNode *>(ptr->data);
- const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node->storage;
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
-
- uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
- /* Only show the mode when it is relevant. */
- if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) {
- uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ for (const int i_out : mask.index_range()) {
+ r_data[i_out] = data[mask[i_out]];
}
}
-static void geo_node_delete_geometry_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN(
- sizeof(NodeGeometryDeleteGeometry), __func__);
- data->domain = ATTR_DOMAIN_POINT;
- data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL;
-
- node->storage = data;
-}
-
-template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
+template<typename T>
+static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> index_map)
{
- for (const int i_out : mask.index_range()) {
- r_data[i_out] = data[mask[i_out]];
+ for (const int i_src : index_map.index_range()) {
+ const int i_dst = index_map[i_src];
+ if (i_dst != -1) {
+ dst[i_dst] = src[i_src];
+ }
}
}
@@ -102,23 +65,6 @@ static IndexMask index_mask_indices(Span<bool> mask, const bool invert, Vector<i
return IndexMask(indices);
}
-/** Utility function for making an IndexMask from an array of integers, where the negative integers
- * are seen as false. The indices vector should live at least as long as the returned IndexMask.
- */
-static IndexMask index_mask_indices(Span<int> mask,
- const int num_indices,
- Vector<int64_t> &indices)
-{
- indices.clear();
- indices.reserve(num_indices);
- for (const int i : mask.index_range()) {
- if (mask[i] >= 0) {
- indices.append_unchecked(i);
- }
- }
- return IndexMask(indices);
-}
-
/**
* Copies the attributes with a domain in `domains` to `result_component`.
*/
@@ -191,12 +137,87 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
using T = decltype(dummy);
VArray_Span<T> span{attribute.varray.typed<T>()};
MutableSpan<T> out_span = result_attribute.as_span<T>();
- copy_data(span, out_span, mask);
+ copy_data_based_on_mask(span, out_span, mask);
});
result_attribute.save();
}
}
+static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind> &attributes,
+ const GeometryComponent &in_component,
+ GeometryComponent &result_component,
+ const AttributeDomain domain,
+ const Span<int> index_map)
+{
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
+ if (!attribute) {
+ continue;
+ }
+
+ /* Only copy if it is on a domain we want. */
+ if (domain != attribute.domain) {
+ continue;
+ }
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+
+ OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
+ attribute_id, attribute.domain, data_type);
+
+ if (!result_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> span{attribute.varray.typed<T>()};
+ MutableSpan<T> out_span = result_attribute.as_span<T>();
+ copy_data_based_on_map(span, out_span, index_map);
+ });
+ result_attribute.save();
+ }
+}
+
+static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind> &attributes,
+ const GeometryComponent &in_component,
+ GeometryComponent &out_component,
+ const int num_selected_loops,
+ const Span<int> selected_poly_indices,
+ const Mesh &mesh_in)
+{
+ Vector<int64_t> indices;
+ indices.reserve(num_selected_loops);
+ for (const int src_poly_index : selected_poly_indices) {
+ const MPoly &src_poly = mesh_in.mpoly[src_poly_index];
+ const int src_loop_start = src_poly.loopstart;
+ const int tot_loop = src_poly.totloop;
+ for (const int i : IndexRange(tot_loop)) {
+ indices.append_unchecked(src_loop_start + i);
+ }
+ }
+ copy_attributes_based_on_mask(
+ attributes, in_component, out_component, ATTR_DOMAIN_CORNER, IndexMask(indices));
+}
+
+static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ for (const int i_src : vertex_map.index_range()) {
+ const int i_dst = vertex_map[i_src];
+ if (i_dst == -1) {
+ continue;
+ }
+
+ const MVert &v_src = src_mesh.mvert[i_src];
+ MVert &v_dst = dst_mesh.mvert[i_dst];
+
+ v_dst = v_src;
+ }
+}
+
static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> edge_map)
{
BLI_assert(src_mesh.totedge == edge_map.size());
@@ -215,6 +236,28 @@ static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh,
}
}
+static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ BLI_assert(src_mesh.totedge == edge_map.size());
+ for (const int i_src : IndexRange(src_mesh.totedge)) {
+ const int i_dst = edge_map[i_src];
+ if (i_dst == -1) {
+ continue;
+ }
+
+ const MEdge &e_src = src_mesh.medge[i_src];
+ MEdge &e_dst = dst_mesh.medge[i_dst];
+
+ e_dst = e_src;
+ e_dst.v1 = vertex_map[e_src.v1];
+ e_dst.v2 = vertex_map[e_src.v2];
+ }
+}
+
/* Faces and edges changed but vertices are the same. */
static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
@@ -268,29 +311,56 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
}
}
+static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map,
+ Span<int> masked_poly_indices,
+ Span<int> new_loop_starts)
+{
+ for (const int i_dst : masked_poly_indices.index_range()) {
+ const int i_src = masked_poly_indices[i_dst];
+
+ const MPoly &mp_src = src_mesh.mpoly[i_src];
+ MPoly &mp_dst = dst_mesh.mpoly[i_dst];
+ const int i_ml_src = mp_src.loopstart;
+ const int i_ml_dst = new_loop_starts[i_dst];
+
+ const MLoop *ml_src = src_mesh.mloop + i_ml_src;
+ MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
+
+ mp_dst = mp_src;
+ mp_dst.loopstart = i_ml_dst;
+ for (int i : IndexRange(mp_src.totloop)) {
+ ml_dst[i].v = vertex_map[ml_src[i].v];
+ ml_dst[i].e = edge_map[ml_src[i].e];
+ }
+ }
+}
+
static void spline_copy_builtin_attributes(const Spline &spline,
Spline &r_spline,
const IndexMask mask)
{
- copy_data(spline.positions(), r_spline.positions(), mask);
- copy_data(spline.radii(), r_spline.radii(), mask);
- copy_data(spline.tilts(), r_spline.tilts(), mask);
+ copy_data_based_on_mask(spline.positions(), r_spline.positions(), mask);
+ copy_data_based_on_mask(spline.radii(), r_spline.radii(), mask);
+ copy_data_based_on_mask(spline.tilts(), r_spline.tilts(), mask);
switch (spline.type()) {
case Spline::Type::Poly:
break;
case Spline::Type::Bezier: {
const BezierSpline &src = static_cast<const BezierSpline &>(spline);
BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
- copy_data(src.handle_positions_left(), dst.handle_positions_left(), mask);
- copy_data(src.handle_positions_right(), dst.handle_positions_right(), mask);
- copy_data(src.handle_types_left(), dst.handle_types_left(), mask);
- copy_data(src.handle_types_right(), dst.handle_types_right(), mask);
+ copy_data_based_on_mask(src.handle_positions_left(), dst.handle_positions_left(), mask);
+ copy_data_based_on_mask(src.handle_positions_right(), dst.handle_positions_right(), mask);
+ copy_data_based_on_mask(src.handle_types_left(), dst.handle_types_left(), mask);
+ copy_data_based_on_mask(src.handle_types_right(), dst.handle_types_right(), mask);
break;
}
case Spline::Type::NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(spline);
NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
- copy_data(src.weights(), dst.weights(), mask);
+ copy_data_based_on_mask(src.weights(), dst.weights(), mask);
break;
}
}
@@ -316,7 +386,7 @@ static void copy_dynamic_attributes(const CustomDataAttributes &src,
attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
using T = decltype(dummy);
- copy_data(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
+ copy_data_based_on_mask(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
});
return true;
},
@@ -986,6 +1056,23 @@ static void do_mesh_separation(GeometrySet &geometry_set,
copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, vertex_map, edge_map);
copy_masked_polys_to_new_mesh(
mesh_in, *mesh_out, vertex_map, edge_map, selected_poly_indices, new_loop_starts);
+
+ /* Copy attributes. */
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_POINT, vertex_map);
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map);
+ copy_attributes_based_on_mask(attributes,
+ in_component,
+ out_component,
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
break;
}
case GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE: {
@@ -1041,22 +1128,25 @@ static void do_mesh_separation(GeometrySet &geometry_set,
/* Copy the selected parts of the mesh over to the new mesh. */
memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert));
- copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT});
copy_masked_edges_to_new_mesh(mesh_in, *mesh_out, edge_map);
copy_masked_polys_to_new_mesh(
mesh_in, *mesh_out, edge_map, selected_poly_indices, new_loop_starts);
- Vector<int64_t> indices;
+
+ /* Copy attributes. */
+ copy_attributes(attributes, in_component, out_component, {ATTR_DOMAIN_POINT});
+ copy_attributes_based_on_map(
+ attributes, in_component, out_component, ATTR_DOMAIN_EDGE, edge_map);
copy_attributes_based_on_mask(attributes,
in_component,
out_component,
- ATTR_DOMAIN_EDGE,
- index_mask_indices(edge_map, num_selected_edges, indices));
- copy_attributes_based_on_mask(
- attributes,
- in_component,
- out_component,
- ATTR_DOMAIN_FACE,
- index_mask_indices(selected_poly_indices, num_selected_polys, indices));
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
break;
}
case GEO_NODE_DELETE_GEOMETRY_MODE_ONLY_FACE: {
@@ -1100,14 +1190,22 @@ static void do_mesh_separation(GeometrySet &geometry_set,
/* Copy the selected parts of the mesh over to the new mesh. */
memcpy(mesh_out->mvert, mesh_in.mvert, mesh_in.totvert * sizeof(MVert));
memcpy(mesh_out->medge, mesh_in.medge, mesh_in.totedge * sizeof(MEdge));
+ copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts);
+
+ /* Copy attributes. */
copy_attributes(
attributes, in_component, out_component, {ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE});
- copy_masked_polys_to_new_mesh(mesh_in, *mesh_out, selected_poly_indices, new_loop_starts);
- Vector<int64_t> indices;
- const IndexMask mask = index_mask_indices(
- selected_poly_indices, num_selected_polys, indices);
- copy_attributes_based_on_mask(
- attributes, in_component, out_component, ATTR_DOMAIN_FACE, mask);
+ copy_attributes_based_on_mask(attributes,
+ in_component,
+ out_component,
+ ATTR_DOMAIN_FACE,
+ IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
+ copy_face_corner_attributes(attributes,
+ in_component,
+ out_component,
+ num_selected_loops,
+ selected_poly_indices,
+ mesh_in);
break;
}
}
@@ -1177,17 +1275,55 @@ void separate_geometry(GeometrySet &geometry_set,
r_is_error = !some_valid_domain && geometry_set.has_realized_data();
}
-static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_delete_geometry_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryDeleteGeometry)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection"))
+ .default_value(true)
+ .hide_value()
+ .supports_field()
+ .description(N_("The parts of the geometry to be deleted"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ const bNode *node = static_cast<bNode *>(ptr->data);
+ const NodeGeometryDeleteGeometry &storage = node_storage(*node);
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ /* Only show the mode when it is relevant. */
+ if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) {
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ }
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN(
+ sizeof(NodeGeometryDeleteGeometry), __func__);
+ data->domain = ATTR_DOMAIN_POINT;
+ data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL;
+
+ node->storage = data;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- const bNode &node = params.node();
- const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node.storage;
+ const NodeGeometryDeleteGeometry &storage = node_storage(params.node());
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
- const GeometryNodeDeleteGeometryMode mode = static_cast<GeometryNodeDeleteGeometryMode>(
- storage.mode);
+ const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode;
bool all_is_error = false;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
@@ -1204,10 +1340,12 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_delete_geometry_cc
void register_node_type_geo_delete_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_delete_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
@@ -1217,10 +1355,10 @@ void register_node_type_geo_delete_geometry()
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_delete_geometry_init);
+ node_type_init(&ntype, file_ns::node_init);
- ntype.declare = blender::nodes::geo_node_delete_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec;
- ntype.draw_buttons = blender::nodes::geo_node_delete_geometry_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index b2c76b76590..3537b62c76e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -36,11 +36,9 @@
#include "node_geometry_util.hh"
-using blender::bke::GeometryInstanceGroup;
+namespace blender::nodes::node_geo_distribute_points_on_faces_cc {
-namespace blender::nodes {
-
-static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -60,9 +58,7 @@ static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBui
b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source();
}
-static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
}
@@ -403,16 +399,12 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
GeometryComponentFieldContext field_context{component, attribute_domain};
const int domain_size = component.attribute_domain_size(attribute_domain);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection_mask = selection_evaluator.get_evaluated_as_mask(0);
-
Array<float> densities(domain_size, 0.0f);
- fn::FieldEvaluator density_evaluator{field_context, &selection_mask};
- density_evaluator.add_with_destination(density_field, densities.as_mutable_span());
- density_evaluator.evaluate();
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(density_field, densities.as_mutable_span());
+ evaluator.evaluate();
return densities;
}
@@ -528,7 +520,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs);
}
-static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
@@ -570,10 +562,12 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_distribute_points_on_faces_cc
void register_node_type_geo_distribute_points_on_faces()
{
+ namespace file_ns = blender::nodes::node_geo_distribute_points_on_faces_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype,
@@ -581,10 +575,10 @@ void register_node_type_geo_distribute_points_on_faces()
"Distribute Points on Faces",
NODE_CLASS_GEOMETRY,
0);
- node_type_update(&ntype, blender::nodes::node_point_distribute_points_on_faces_update);
+ node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update);
node_type_size(&ntype, 170, 100, 320);
- ntype.declare = blender::nodes::geo_node_point_distribute_points_on_faces_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_points_on_faces_exec;
- ntype.draw_buttons = blender::nodes::geo_node_point_distribute_points_on_faces_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
new file mode 100644
index 00000000000..a3bbeca7af3
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -0,0 +1,847 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_dual_mesh_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>("Keep Boundaries")
+ .default_value(false)
+ .description(
+ "Keep non-manifold boundaries of the input mesh in place by avoiding the dual "
+ "transformation there");
+ b.add_output<decl::Geometry>("Dual Mesh");
+}
+
+enum class EdgeType : int8_t {
+ Loose = 0, /* No polygons connected to it. */
+ Boundary = 1, /* An edge connected to exactly one polygon. */
+ Normal = 2, /* A normal edge (connected to two polygons). */
+ NonManifold = 3, /* An edge connected to more than two polygons. */
+};
+
+static EdgeType get_edge_type_with_added_neighbor(EdgeType old_type)
+{
+ switch (old_type) {
+ case EdgeType::Loose:
+ return EdgeType::Boundary;
+ case EdgeType::Boundary:
+ return EdgeType::Normal;
+ case EdgeType::Normal:
+ case EdgeType::NonManifold:
+ return EdgeType::NonManifold;
+ }
+ BLI_assert_unreachable();
+ return EdgeType::Loose;
+}
+
+enum class VertexType : int8_t {
+ Loose = 0, /* Either no edges connected or only loose edges connected. */
+ Normal = 1, /* A normal vertex. */
+ Boundary = 2, /* A vertex on a boundary edge. */
+ NonManifold = 3, /* A vertex on a non-manifold edge. */
+};
+
+static VertexType get_vertex_type_with_added_neighbor(VertexType old_type)
+{
+ switch (old_type) {
+ case VertexType::Loose:
+ return VertexType::Normal;
+ case VertexType::Normal:
+ return VertexType::Boundary;
+ case VertexType::Boundary:
+ case VertexType::NonManifold:
+ return VertexType::NonManifold;
+ }
+ BLI_assert_unreachable();
+ return VertexType::Loose;
+}
+
+/* Copy only where vertex_types is 'normal'. If keep boundaries is selected, also copy from
+ * boundary vertices. */
+template<typename T>
+static void copy_data_based_on_vertex_types(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<VertexType> vertex_types,
+ const bool keep_boundaries)
+{
+ if (keep_boundaries) {
+ int out_i = 0;
+ for (const int i : data.index_range()) {
+ if (ELEM(vertex_types[i], VertexType::Normal, VertexType::Boundary)) {
+ r_data[out_i] = data[i];
+ out_i++;
+ }
+ }
+ }
+ else {
+ int out_i = 0;
+ for (const int i : data.index_range()) {
+ if (vertex_types[i] == VertexType::Normal) {
+ r_data[out_i] = data[i];
+ out_i++;
+ }
+ }
+ }
+}
+
+template<typename T>
+static void copy_data_based_on_pairs(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<std::pair<int, int>> new_to_old_map)
+{
+ for (const std::pair<int, int> &pair : new_to_old_map) {
+ r_data[pair.first] = data[pair.second];
+ }
+}
+
+/* Copy using the map. */
+template<typename T>
+static void copy_data_based_on_new_to_old_map(Span<T> data,
+ MutableSpan<T> r_data,
+ const Span<int> new_to_old_map)
+{
+ for (const int i : r_data.index_range()) {
+ const int old_i = new_to_old_map[i];
+ r_data[i] = data[old_i];
+ }
+}
+
+/**
+ * Transfers the attributes from the original mesh to the new mesh using the following logic:
+ * - If the attribute was on the face domain it is now on the point domain, and this is true
+ * for all faces, so we can just copy these.
+ * - If the attribute was on the vertex domain there are three cases:
+ * - It was a 'bad' vertex so it is not in the dual mesh, and we can just ignore it
+ * - It was a normal vertex so it has a corresponding face in the dual mesh to which we can
+ * transfer.
+ * - It was a boundary vertex so it has a corresponding face, if keep_boundaries is true.
+ * Otherwise we can just ignore it.
+ * - If the attribute was on the edge domain we lookup for the new edges which edge it originated
+ * from using `new_to_old_edges_map`. We have to do it in this reverse order, because there can
+ * be more edges in the new mesh if keep boundaries is on.
+ * - We do the same thing for face corners as we do for edges.
+ *
+ * Some of the vertices (on the boundary) in the dual mesh don't come from faces, but from edges or
+ * vertices. For these the `boundary_vertex_to_relevant_face_map` is used, which maps them to the
+ * closest face.
+ */
+static void transfer_attributes(
+ const Map<AttributeIDRef, AttributeKind> &attributes,
+ const Span<VertexType> vertex_types,
+ const bool keep_boundaries,
+ const Span<int> new_to_old_edges_map,
+ const Span<int> new_to_old_face_corners_map,
+ const Span<std::pair<int, int>> boundary_vertex_to_relevant_face_map,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute) {
+ continue;
+ }
+
+ AttributeDomain out_domain;
+ if (src_attribute.domain == ATTR_DOMAIN_FACE) {
+ out_domain = ATTR_DOMAIN_POINT;
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_POINT) {
+ out_domain = ATTR_DOMAIN_FACE;
+ }
+ else {
+ /* Edges and Face Corners. */
+ out_domain = src_attribute.domain;
+ }
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+
+ if (!dst_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> span{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst_span = dst_attribute.as_span<T>();
+ if (src_attribute.domain == ATTR_DOMAIN_FACE) {
+ dst_span.take_front(span.size()).copy_from(span);
+ if (keep_boundaries) {
+ copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map);
+ }
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_POINT) {
+ copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries);
+ }
+ else if (src_attribute.domain == ATTR_DOMAIN_EDGE) {
+ copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_edges_map);
+ }
+ else {
+ copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map);
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Calculates the boundaries of the mesh. Boundary polygons are not computed since we don't need
+ * them later on. We use the following definitions:
+ * - An edge is on a boundary if it is connected to only one polygon.
+ * - A vertex is on a boundary if it is on an edge on a boundary.
+ */
+static void calc_boundaries(const Mesh &mesh,
+ MutableSpan<VertexType> r_vertex_types,
+ MutableSpan<EdgeType> r_edge_types)
+{
+ BLI_assert(r_vertex_types.size() == mesh.totvert);
+ BLI_assert(r_edge_types.size() == mesh.totedge);
+ r_vertex_types.fill(VertexType::Loose);
+ r_edge_types.fill(EdgeType::Loose);
+
+ /* Add up the number of polys connected to each edge. */
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[i];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ r_edge_types[loop.e] = get_edge_type_with_added_neighbor(r_edge_types[loop.e]);
+ }
+ }
+
+ /* Update vertices. */
+ for (const int i : IndexRange(mesh.totedge)) {
+ const EdgeType edge_type = r_edge_types[i];
+ if (edge_type == EdgeType::Loose) {
+ continue;
+ }
+ const MEdge &edge = mesh.medge[i];
+ if (edge_type == EdgeType::Boundary) {
+ r_vertex_types[edge.v1] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v1]);
+ r_vertex_types[edge.v2] = get_vertex_type_with_added_neighbor(r_vertex_types[edge.v2]);
+ }
+ else if (edge_type >= EdgeType::NonManifold) {
+ r_vertex_types[edge.v1] = VertexType::NonManifold;
+ r_vertex_types[edge.v2] = VertexType::NonManifold;
+ }
+ }
+
+ /* Normal verts are on a normal edge, and not on boundary edges or non-manifold edges. */
+ for (const int i : IndexRange(mesh.totedge)) {
+ const EdgeType edge_type = r_edge_types[i];
+ if (edge_type == EdgeType::Normal) {
+ const MEdge &edge = mesh.medge[i];
+ if (r_vertex_types[edge.v1] == VertexType::Loose) {
+ r_vertex_types[edge.v1] = VertexType::Normal;
+ }
+ if (r_vertex_types[edge.v2] == VertexType::Loose) {
+ r_vertex_types[edge.v2] = VertexType::Normal;
+ }
+ }
+ }
+}
+
+/**
+ * Stores the indices of the polygons connected to each vertex.
+ */
+static void create_vertex_poly_map(const Mesh &mesh,
+ MutableSpan<Vector<int>> r_vertex_poly_indices)
+{
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[i];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ r_vertex_poly_indices[loop.v].append(i);
+ }
+ }
+}
+
+/**
+ * Sorts the polygons connected to the given vertex based on polygon adjacency. The ordering is
+ * so such that the normals point in the same way as the original mesh. If the vertex is a
+ * boundary vertex, the first and last polygon have a boundary edge connected to the vertex. The
+ * `r_shared_edges` array at index i is set to the index of the shared edge between the i-th and
+ * `(i+1)-th` sorted polygon. Similarly the `r_sorted_corners` array at index i is set to the
+ * corner in the i-th sorted polygon.
+ *
+ * How the faces are sorted (see diagrams below):
+ * (For this explanation we'll assume all faces are oriented clockwise)
+ * (The vertex whose connected polygons we need to sort is "v0")
+ *
+ * \code{.unparsed}
+ * Normal case: Boundary Vertex case:
+ * v1 ----- v2 ----- v3 | | |
+ * | f3 | f0 | v2 ---- v4 --------- v3---
+ * | | | | / ,-' |
+ * v8 ----- v0 ----- v4 | f0 / f1 ,-' |
+ * | f2 | f1 | | / ,-' |
+ * | | | | / ,-' |
+ * v7 ----- v6 ----- v5 | / ,-' f2 |
+ * | /,-' |
+ * v0 ------------------ v1---
+ * \endcode
+ *
+ * - First we get the two corners of each face that have an edge which contains v0. A corner is
+ * simply a vertex followed by an edge. In this case for the face "f0" for example, we'd end up
+ * with the corners (v: v4, e: v4<->v0) and (v: v0, e: v0<->v2). Note that if the face was
+ * oriented counter-clockwise we'd end up with the corners (v: v0, e: v0<->v4) and (v: v2, e:
+ * v0<->v2) instead.
+ * - Then we need to choose one polygon as our first. If "v0" is not on a boundary we can just
+ * choose any polygon. If it is on a boundary some more care needs to be taken. Here we need to
+ * pick a polygon which lies on the boundary (in the diagram either f0 or f2). To choose between
+ * the two we need the next step.
+ * - In the normal case we use this polygon to set `shared_edge_i` which indicates the index of the
+ * shared edge between this polygon and the next one. There are two possible choices: v0<->v4 and
+ * v2<->v0. To choose we look at the corners. Since the edge v0<->v2 lies on the corner which has
+ * v0, we set `shared_edge_i` to the other edge (v0<->v4), such that the next face will be "f1"
+ * which is the next face in clockwise order.
+ * - In the boundary vertex case, we do something similar, but we are also forced to choose the
+ * edge which is not on the boundary. If this doesn't line up with orientation of the polygon, we
+ * know we'll need to choose the other boundary polygon as our first polygon. If the orientations
+ * don't line up there as well, it means that the mesh normals are not consistent, and we just
+ * have to force an orientation for ourselves. (Imagine if f0 is oriented counter-clockwise and
+ * f2 is oriented clockwise for example)
+ * - Next comes a loop where we look at the other faces and find the one which has the shared
+ * edge. Then we set the next shared edge to the other edge on the polygon connected to "v0", and
+ * continue. Because of the way we've chosen the first shared edge the order of the faces will
+ * have the same orientation as that of the first polygon.
+ * (In this case we'd have f0 -> f1 -> f2 -> f3 which also goes around clockwise).
+ * - Every time we determine a shared edge, we can also add a corner to `r_sorted_corners`. This
+ * will simply be the corner which doesn't contain the shared edge.
+ * - Finally if we are in the normal case we also need to add the last "shared edge" to close the
+ * loop.
+ */
+static void sort_vertex_polys(const Mesh &mesh,
+ const int vertex_index,
+ const bool boundary_vertex,
+ const Span<EdgeType> edge_types,
+ MutableSpan<int> connected_polygons,
+ MutableSpan<int> r_shared_edges,
+ MutableSpan<int> r_sorted_corners)
+{
+ if (connected_polygons.size() <= 2 && (!boundary_vertex || connected_polygons.size() == 0)) {
+ return;
+ }
+
+ /* For each polygon store the two corners whose edge contains the vertex. */
+ Array<std::pair<int, int>> poly_vertex_corners(connected_polygons.size());
+ for (const int i : connected_polygons.index_range()) {
+ const MPoly &poly = mesh.mpoly[connected_polygons[i]];
+ bool first_edge_done = false;
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (mesh.medge[loop.e].v1 == vertex_index || mesh.medge[loop.e].v2 == vertex_index) {
+ if (!first_edge_done) {
+ poly_vertex_corners[i].first = loop_index;
+ first_edge_done = true;
+ }
+ else {
+ poly_vertex_corners[i].second = loop_index;
+ break;
+ }
+ }
+ }
+ }
+
+ int shared_edge_i = -1;
+ /* Determine first polygon and orientation. For now the orientation of the whole loop depends
+ * on the one polygon we chose as first. It's probably not worth it to check every polygon in
+ * the loop to determine the 'average' orientation. */
+ if (boundary_vertex) {
+ /* Our first polygon needs to be one which has a boundary edge. */
+ for (const int i : connected_polygons.index_range()) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second];
+ if (edge_types[first_loop.e] == EdgeType::Boundary && first_loop.v == vertex_index) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].first;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ if (edge_types[second_loop.e] == EdgeType::Boundary && second_loop.v == vertex_index) {
+ shared_edge_i = first_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].second;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ }
+ if (shared_edge_i == -1) {
+ /* The rotation is inconsistent between the two polygons on the boundary. Just choose one
+ * of the polygon's orientation. */
+ for (const int i : connected_polygons.index_range()) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[i].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[i].second];
+ if (edge_types[first_loop.e] == EdgeType::Boundary) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].first;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ if (edge_types[second_loop.e] == EdgeType::Boundary) {
+ shared_edge_i = first_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[i].second;
+ std::swap(connected_polygons[i], connected_polygons[0]);
+ std::swap(poly_vertex_corners[i], poly_vertex_corners[0]);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* Any polygon can be the first. Just need to check the orientation.*/
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[0].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[0].second];
+ if (first_loop.v == vertex_index) {
+ shared_edge_i = second_loop.e;
+ r_sorted_corners[0] = poly_vertex_corners[0].first;
+ }
+ else {
+ r_sorted_corners[0] = poly_vertex_corners[0].second;
+ shared_edge_i = first_loop.e;
+ }
+ }
+ BLI_assert(shared_edge_i != -1);
+
+ for (const int i : IndexRange(connected_polygons.size() - 1)) {
+ r_shared_edges[i] = shared_edge_i;
+
+ /* Look at the other polys to see if it has this shared edge. */
+ int j = i + 1;
+ for (; j < connected_polygons.size(); ++j) {
+ const MLoop &first_loop = mesh.mloop[poly_vertex_corners[j].first];
+ const MLoop &second_loop = mesh.mloop[poly_vertex_corners[j].second];
+ if (first_loop.e == shared_edge_i) {
+ r_sorted_corners[i + 1] = poly_vertex_corners[j].first;
+ shared_edge_i = second_loop.e;
+ break;
+ }
+ if (second_loop.e == shared_edge_i) {
+ r_sorted_corners[i + 1] = poly_vertex_corners[j].second;
+ shared_edge_i = first_loop.e;
+ break;
+ }
+ }
+
+ BLI_assert(j != connected_polygons.size());
+
+ std::swap(connected_polygons[i + 1], connected_polygons[j]);
+ std::swap(poly_vertex_corners[i + 1], poly_vertex_corners[j]);
+ }
+
+ if (!boundary_vertex) {
+ /* Shared edge between first and last polygon. */
+ r_shared_edges.last() = shared_edge_i;
+ }
+}
+
+/**
+ * Get the edge on the poly that contains the given vertex and is a boundary edge.
+ */
+static void boundary_edge_on_poly(const MPoly &poly,
+ const Mesh &mesh,
+ const int vertex_index,
+ const Span<EdgeType> edge_types,
+ int &r_edge)
+{
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ if (edge_types[loop.e] == EdgeType::Boundary) {
+ const MEdge &edge = mesh.medge[loop.e];
+ if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
+ r_edge = loop.e;
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * Get the two edges on the poly that contain the given vertex and are boundary edges. The
+ * orientation of the poly is taken into account.
+ */
+static void boundary_edges_on_poly(const MPoly &poly,
+ const Mesh &mesh,
+ const int vertex_index,
+ const Span<EdgeType> edge_types,
+ int &r_edge1,
+ int &r_edge2)
+{
+ bool edge1_done = false;
+ /* This is set to true if the order in which we encounter the two edges is inconsistent with the
+ * orientation of the polygon. */
+ bool needs_swap = false;
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ if (edge_types[loop.e] == EdgeType::Boundary) {
+ const MEdge &edge = mesh.medge[loop.e];
+ if (edge.v1 == vertex_index || edge.v2 == vertex_index) {
+ if (edge1_done) {
+ if (needs_swap) {
+ r_edge2 = r_edge1;
+ r_edge1 = loop.e;
+ }
+ else {
+ r_edge2 = loop.e;
+ }
+ return;
+ }
+ r_edge1 = loop.e;
+ edge1_done = true;
+ if (loop.v == vertex_index) {
+ needs_swap = true;
+ }
+ }
+ }
+ }
+}
+
+static void add_edge(const Mesh &mesh,
+ const int old_edge_i,
+ const int v1,
+ const int v2,
+ Vector<int> &new_to_old_edges_map,
+ Vector<MEdge> &new_edges,
+ Vector<int> &loop_edges)
+{
+ MEdge new_edge = MEdge(mesh.medge[old_edge_i]);
+ new_edge.v1 = v1;
+ new_edge.v2 = v2;
+ const int new_edge_i = new_edges.size();
+ new_to_old_edges_map.append(old_edge_i);
+ new_edges.append(new_edge);
+ loop_edges.append(new_edge_i);
+}
+
+/**
+ * Calculate the barycentric dual of a mesh. The dual is only "dual" in terms of connectivity,
+ * i.e. applying the function twice will give the same vertices, edges, and faces, but not the
+ * same positions. When the option "Keep Boundaries" is selected the connectivity is no
+ * longer dual.
+ *
+ * For the dual mesh of a manifold input mesh:
+ * - The vertices are at the centers of the faces of the input mesh.
+ * - The edges connect the two vertices created from the two faces next to the edge in the input
+ * mesh.
+ * - The faces are at the vertices of the input mesh.
+ *
+ * Some special cases are needed for boundaries and non-manifold geometry.
+ */
+static void calc_dual_mesh(GeometrySet &geometry_set,
+ const MeshComponent &in_component,
+ const bool keep_boundaries)
+{
+ const Mesh &mesh_in = *in_component.get_for_read();
+
+ Map<AttributeIDRef, AttributeKind> attributes;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_MESH, false, attributes);
+
+ Array<VertexType> vertex_types(mesh_in.totvert);
+ Array<EdgeType> edge_types(mesh_in.totedge);
+ calc_boundaries(mesh_in, vertex_types, edge_types);
+ Array<Vector<int>> vertex_poly_indices(mesh_in.totvert);
+ Array<Array<int>> vertex_shared_edges(mesh_in.totvert);
+ Array<Array<int>> vertex_corners(mesh_in.totvert);
+ create_vertex_poly_map(mesh_in, vertex_poly_indices);
+ threading::parallel_for(vertex_poly_indices.index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
+ (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
+ /* Bad vertex that we can't work with. */
+ continue;
+ }
+ MutableSpan<int> loop_indices = vertex_poly_indices[i];
+ Array<int> sorted_corners(loop_indices.size());
+ if (vertex_types[i] == VertexType::Normal) {
+ Array<int> shared_edges(loop_indices.size());
+ sort_vertex_polys(
+ mesh_in, i, false, edge_types, loop_indices, shared_edges, sorted_corners);
+ vertex_shared_edges[i] = shared_edges;
+ }
+ else {
+ Array<int> shared_edges(loop_indices.size() - 1);
+ sort_vertex_polys(
+ mesh_in, i, true, edge_types, loop_indices, shared_edges, sorted_corners);
+ vertex_shared_edges[i] = shared_edges;
+ }
+ vertex_corners[i] = sorted_corners;
+ }
+ });
+
+ Vector<float3> vertex_positions(mesh_in.totpoly);
+ for (const int i : IndexRange(mesh_in.totpoly)) {
+ const MPoly poly = mesh_in.mpoly[i];
+ BKE_mesh_calc_poly_center(
+ &poly, &mesh_in.mloop[poly.loopstart], mesh_in.mvert, vertex_positions[i]);
+ }
+
+ Array<int> boundary_edge_midpoint_index;
+ if (keep_boundaries) {
+ /* Only initialize when we actually need it. */
+ boundary_edge_midpoint_index.reinitialize(mesh_in.totedge);
+ /* We need to add vertices at the centers of boundary edges. */
+ for (const int i : IndexRange(mesh_in.totedge)) {
+ if (edge_types[i] == EdgeType::Boundary) {
+ float3 mid;
+ const MEdge &edge = mesh_in.medge[i];
+ mid_v3_v3v3(mid, mesh_in.mvert[edge.v1].co, mesh_in.mvert[edge.v2].co);
+ boundary_edge_midpoint_index[i] = vertex_positions.size();
+ vertex_positions.append(mid);
+ }
+ }
+ }
+
+ Vector<int> loop_lengths;
+ Vector<int> loops;
+ Vector<int> loop_edges;
+ Vector<MEdge> new_edges;
+ /* These are used to transfer attributes. */
+ Vector<int> new_to_old_face_corners_map;
+ Vector<int> new_to_old_edges_map;
+ /* Stores the index of the vertex in the dual and the face it should get the attribute from. */
+ Vector<std::pair<int, int>> boundary_vertex_to_relevant_face_map;
+ /* Since each edge in the dual (except the ones created with keep boundaries) comes from
+ * exactly one edge in the original, we can use this array to keep track of whether it still
+ * needs to be created or not. If it's not -1 it gives the index in `new_edges` of the dual
+ * edge. The edges coming from preserving the boundaries only get added once anyway, so we
+ * don't need a hashmap for that. */
+ Array<int> old_to_new_edges_map(mesh_in.totedge);
+ old_to_new_edges_map.fill(-1);
+ for (const int i : IndexRange(mesh_in.totvert)) {
+ if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
+ (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
+ /* Bad vertex that we can't work with. */
+ continue;
+ }
+
+ Vector<int> loop_indices = vertex_poly_indices[i];
+ Span<int> shared_edges = vertex_shared_edges[i];
+ Span<int> sorted_corners = vertex_corners[i];
+ if (vertex_types[i] == VertexType::Normal) {
+ if (loop_indices.size() <= 2) {
+ /* We can't make a polygon from 2 vertices. */
+ continue;
+ }
+
+ /* Add edges in the loop. */
+ for (const int i : shared_edges.index_range()) {
+ const int old_edge_i = shared_edges[i];
+ if (old_to_new_edges_map[old_edge_i] == -1) {
+ /* This edge has not been created yet. */
+ MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]);
+ new_edge.v1 = loop_indices[i];
+ new_edge.v2 = loop_indices[(i + 1) % loop_indices.size()];
+ new_to_old_edges_map.append(old_edge_i);
+ old_to_new_edges_map[old_edge_i] = new_edges.size();
+ new_edges.append(new_edge);
+ }
+ loop_edges.append(old_to_new_edges_map[old_edge_i]);
+ }
+
+ new_to_old_face_corners_map.extend(sorted_corners);
+ }
+ else {
+ /**
+ * The code handles boundary vertices like the vertex marked "V" in the diagram below.
+ * The first thing that happens is ordering the faces f1,f2 and f3 (stored in
+ * loop_indices), together with their shared edges e3 and e4 (which get stored in
+ * shared_edges). The ordering could end up being clockwise or counterclockwise, for this
+ * we'll assume that the ordering f1->f2->f3 is chosen. After that we add the edges in
+ * between the polygons, in this case the edges f1--f2, and f2--f3. Now we need to merge
+ * these with the boundary edges e1 and e2. To do this we create an edge from f3 to the
+ * midpoint of e2 (computed in a previous step), from this midpoint to V, from V to the
+ * midpoint of e1 and from the midpoint of e1 to f1.
+ *
+ * \code{.unparsed}
+ * | | | | | |
+ * v2 ---- v3 --------- v4--- v2 ---- v3 -------- v4---
+ * | f3 / ,-' | | / ,-'|
+ * | / f2 ,-' | | / ,-' |
+ * e2 | /e3 ,-' e4 | ====> M1-f3-/--f2-.,-' |
+ * | / ,-' | ====> | / ,-'\ |
+ * | / ,-' f1 | | / ,-' f1 |
+ * | /,-' | | /,-' | |
+ * V-------------------- v5--- V------------M2----- v5---
+ * \endcode
+ */
+
+ /* Add the edges in between the polys. */
+ for (const int i : shared_edges.index_range()) {
+ const int old_edge_i = shared_edges[i];
+ if (old_to_new_edges_map[old_edge_i] == -1) {
+ /* This edge has not been created yet. */
+ MEdge new_edge = MEdge(mesh_in.medge[old_edge_i]);
+ new_edge.v1 = loop_indices[i];
+ new_edge.v2 = loop_indices[i + 1];
+ new_to_old_edges_map.append(old_edge_i);
+ old_to_new_edges_map[old_edge_i] = new_edges.size();
+ new_edges.append(new_edge);
+ }
+ loop_edges.append(old_to_new_edges_map[old_edge_i]);
+ }
+
+ new_to_old_face_corners_map.extend(sorted_corners);
+
+ /* Add the vertex and the midpoints of the two boundary edges to the loop. */
+
+ /* Get the boundary edges. */
+ int edge1;
+ int edge2;
+ if (loop_indices.size() >= 2) {
+ /* The first boundary edge is at the end of the chain of polygons. */
+ boundary_edge_on_poly(mesh_in.mpoly[loop_indices.last()], mesh_in, i, edge_types, edge1);
+ boundary_edge_on_poly(mesh_in.mpoly[loop_indices.first()], mesh_in, i, edge_types, edge2);
+ }
+ else {
+ /* If there is only one polygon both edges are in that polygon. */
+ boundary_edges_on_poly(
+ mesh_in.mpoly[loop_indices[0]], mesh_in, i, edge_types, edge1, edge2);
+ }
+
+ const int last_face_center = loop_indices.last();
+ loop_indices.append(boundary_edge_midpoint_index[edge1]);
+ new_to_old_face_corners_map.append(sorted_corners.last());
+ const int first_midpoint = loop_indices.last();
+ if (old_to_new_edges_map[edge1] == -1) {
+ add_edge(mesh_in,
+ edge1,
+ last_face_center,
+ first_midpoint,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+ old_to_new_edges_map[edge1] = new_edges.size() - 1;
+ boundary_vertex_to_relevant_face_map.append(std::pair(first_midpoint, last_face_center));
+ }
+ else {
+ loop_edges.append(old_to_new_edges_map[edge1]);
+ }
+ loop_indices.append(vertex_positions.size());
+ /* This is sort of arbitrary, but interpolating would be a lot harder to do. */
+ new_to_old_face_corners_map.append(sorted_corners.first());
+ boundary_vertex_to_relevant_face_map.append(
+ std::pair(loop_indices.last(), last_face_center));
+ vertex_positions.append(mesh_in.mvert[i].co);
+ const int boundary_vertex = loop_indices.last();
+ add_edge(mesh_in,
+ edge1,
+ first_midpoint,
+ boundary_vertex,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+
+ loop_indices.append(boundary_edge_midpoint_index[edge2]);
+ new_to_old_face_corners_map.append(sorted_corners.first());
+ const int second_midpoint = loop_indices.last();
+ add_edge(mesh_in,
+ edge2,
+ boundary_vertex,
+ second_midpoint,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+
+ if (old_to_new_edges_map[edge2] == -1) {
+ const int first_face_center = loop_indices.first();
+ add_edge(mesh_in,
+ edge2,
+ second_midpoint,
+ first_face_center,
+ new_to_old_edges_map,
+ new_edges,
+ loop_edges);
+ old_to_new_edges_map[edge2] = new_edges.size() - 1;
+ boundary_vertex_to_relevant_face_map.append(std::pair(second_midpoint, first_face_center));
+ }
+ else {
+ loop_edges.append(old_to_new_edges_map[edge2]);
+ }
+ }
+
+ loop_lengths.append(loop_indices.size());
+ for (const int j : loop_indices) {
+ loops.append(j);
+ }
+ }
+ Mesh *mesh_out = BKE_mesh_new_nomain(
+ vertex_positions.size(), new_edges.size(), 0, loops.size(), loop_lengths.size());
+ MeshComponent out_component;
+ out_component.replace(mesh_out, GeometryOwnershipType::Editable);
+ transfer_attributes(attributes,
+ vertex_types,
+ keep_boundaries,
+ new_to_old_edges_map,
+ new_to_old_face_corners_map,
+ boundary_vertex_to_relevant_face_map,
+ in_component,
+ out_component);
+
+ int loop_start = 0;
+ for (const int i : IndexRange(mesh_out->totpoly)) {
+ mesh_out->mpoly[i].loopstart = loop_start;
+ mesh_out->mpoly[i].totloop = loop_lengths[i];
+ loop_start += loop_lengths[i];
+ }
+ for (const int i : IndexRange(mesh_out->totloop)) {
+ mesh_out->mloop[i].v = loops[i];
+ mesh_out->mloop[i].e = loop_edges[i];
+ }
+ for (const int i : IndexRange(mesh_out->totvert)) {
+ copy_v3_v3(mesh_out->mvert[i].co, vertex_positions[i]);
+ }
+ memcpy(mesh_out->medge, new_edges.data(), sizeof(MEdge) * new_edges.size());
+ BKE_mesh_normals_tag_dirty(mesh_out);
+ geometry_set.replace_mesh(mesh_out);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ const bool keep_boundaries = params.extract_input<bool>("Keep Boundaries");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+ calc_dual_mesh(geometry_set, component, keep_boundaries);
+ }
+ });
+ params.set_output("Dual Mesh", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_dual_mesh_cc
+
+void register_node_type_geo_dual_mesh()
+{
+ namespace file_ns = blender::nodes::node_geo_dual_mesh_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index ca6254be182..d23a18ba37b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -22,9 +22,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_edge_split_cc {
-static void geo_node_edge_split_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -57,7 +57,7 @@ static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection)
return result;
}
-static void geo_node_edge_split_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
@@ -82,14 +82,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_edge_split_cc
void register_node_type_geo_edge_split()
{
+ namespace file_ns = blender::nodes::node_geo_edge_split_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec;
- ntype.declare = blender::nodes::geo_node_edge_split_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
new file mode 100644
index 00000000000..7faf104737f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_geometry_to_instance_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry")).multi_input();
+ b.add_output<decl::Geometry>(N_("Instances"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Vector<GeometrySet> geometries = params.extract_multi_input<GeometrySet>("Geometry");
+ GeometrySet instances_geometry;
+ InstancesComponent &instances_component =
+ instances_geometry.get_component_for_write<InstancesComponent>();
+ for (GeometrySet &geometry : geometries) {
+ geometry.ensure_owns_direct_data();
+ const int handle = instances_component.add_reference(std::move(geometry));
+ instances_component.add_instance(handle, float4x4::identity());
+ }
+ params.set_output("Instances", std::move(instances_geometry));
+}
+
+} // namespace blender::nodes::node_geo_geometry_to_instance_cc
+
+void register_node_type_geo_geometry_to_instance()
+{
+ namespace file_ns = blender::nodes::node_geo_geometry_to_instance_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY, 0);
+ node_type_size(&ntype, 160, 100, 300);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
index 7bbe0716f78..0003f15854d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -32,9 +32,11 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_image_texture_cc {
-static void geo_node_image_texture_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryImageTexture)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Image>(N_("Image")).hide_label();
b.add_input<decl::Vector>(N_("Vector"))
@@ -45,13 +47,13 @@ static void geo_node_image_texture_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field();
}
-static void geo_node_image_texture_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
}
-static void geo_node_image_texture_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN(
sizeof(NodeGeometryImageTexture), __func__);
@@ -370,20 +372,15 @@ class ImageFieldsFunction : public fn::MultiFunction {
}
};
-static void geo_node_image_texture_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- auto return_default = [&]() {
- params.set_output("Color", ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
- params.set_output("Alpha", 1.0f);
- };
-
Image *image = params.get_input<Image *>("Image");
if (image == nullptr) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
- const bNode &node = params.node();
- NodeGeometryImageTexture *data = (NodeGeometryImageTexture *)node.storage;
+ const NodeGeometryImageTexture &storage = node_storage(params.node());
ImageUser image_user;
BKE_imageuser_default(&image_user);
@@ -395,10 +392,11 @@ static void geo_node_image_texture_exec(GeoNodeExecParams params)
std::unique_ptr<ImageFieldsFunction> image_fn;
try {
image_fn = std::make_unique<ImageFieldsFunction>(
- data->interpolation, data->extension, *image, image_user);
+ storage.interpolation, storage.extension, *image, image_user);
}
catch (const std::runtime_error &) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
Field<float3> vector_field = params.extract_input<Field<float3>>("Vector");
@@ -410,20 +408,22 @@ static void geo_node_image_texture_exec(GeoNodeExecParams params)
params.set_output("Alpha", Field<float>(image_op, 1));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_image_texture_cc
-void register_node_type_geo_image_texture(void)
+void register_node_type_geo_image_texture()
{
+ namespace file_ns = blender::nodes::node_geo_image_texture_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::geo_node_image_texture_declare;
- ntype.draw_buttons = blender::nodes::geo_node_image_texture_layout;
- node_type_init(&ntype, blender::nodes::geo_node_image_texture_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryImageTexture", node_free_standard_storage, node_copy_standard_storage);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- ntype.geometry_node_execute = blender::nodes::geo_node_image_texture_exec;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
index b8df545d073..dae8fda2099 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -16,15 +16,15 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_curve_handles_cc {
-static void geo_node_input_curve_handles_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Left")).field_source();
b.add_output<decl::Vector>(N_("Right")).field_source();
}
-static void geo_node_input_curve_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> left_field = AttributeFieldInput::Create<float3>("handle_left");
Field<float3> right_field = AttributeFieldInput::Create<float3>("handle_right");
@@ -32,15 +32,17 @@ static void geo_node_input_curve_handles_exec(GeoNodeExecParams params)
params.set_output("Right", std::move(right_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_curve_handles_cc
void register_node_type_geo_input_curve_handles()
{
+ namespace file_ns = blender::nodes::node_geo_input_curve_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT, 0);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_handles_exec;
- ntype.declare = blender::nodes::geo_node_input_curve_handles_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
index f32db3842db..5ba85b6f34e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_curve_tilt_cc {
-static void geo_node_input_curve_tilt_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Tilt")).field_source();
}
-static void geo_node_input_curve_tilt_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float> tilt_field = AttributeFieldInput::Create<float>("tilt");
params.set_output("Tilt", std::move(tilt_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_curve_tilt_cc
void register_node_type_geo_input_curve_tilt()
{
+ namespace file_ns = blender::nodes::node_geo_input_curve_tilt_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_tilt_exec;
- ntype.declare = blender::nodes::geo_node_input_curve_tilt_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
index 37d5bac0325..d2e103a093a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_id_cc {
-static void geo_node_input_id_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("ID")).field_source();
}
-static void geo_node_input_id_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> position_field{std::make_shared<bke::IDAttributeFieldInput>()};
params.set_output("ID", std::move(position_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_id_cc
void register_node_type_geo_input_id()
{
+ namespace file_ns = blender::nodes::node_geo_input_id_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_id_exec;
- ntype.declare = blender::nodes::geo_node_input_id_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
index 6200ac5e7a8..74cddfc6a4a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_index_cc {
-static void geo_node_input_index_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("Index")).field_source();
}
-static void geo_node_input_index_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> index_field{std::make_shared<fn::IndexFieldInput>()};
params.set_output("Index", std::move(index_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_index_cc
void register_node_type_geo_input_index()
{
+ namespace file_ns = blender::nodes::node_geo_input_index_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_index_exec;
- ntype.declare = blender::nodes::geo_node_input_index_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index fc41188dee5..1b6e3c8fc68 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -19,33 +19,35 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_material_cc {
-static void geo_node_input_material_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Material>(N_("Material"));
}
-static void geo_node_input_material_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "material", 0, "", ICON_NONE);
}
-static void geo_node_input_material_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = (Material *)params.node().id;
params.set_output("Material", material);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_material_cc
void register_node_type_geo_input_material()
{
+ namespace file_ns = blender::nodes::node_geo_input_material_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0);
- ntype.draw_buttons = blender::nodes::geo_node_input_material_layout;
- ntype.declare = blender::nodes::geo_node_input_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_input_material_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
index 5d5d9e40032..4df218eb669 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_material_index_cc {
-static void geo_node_input_material_index_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("Material Index")).field_source();
}
-static void geo_node_input_material_index_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> material_index_field = AttributeFieldInput::Create<int>("material_index");
params.set_output("Material Index", std::move(material_index_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_material_index_cc
void register_node_type_geo_input_material_index()
{
+ namespace file_ns = blender::nodes::node_geo_input_material_index_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_material_index_exec;
- ntype.declare = blender::nodes::geo_node_input_material_index_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
new file mode 100644
index 00000000000..ede87252312
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
@@ -0,0 +1,93 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces that contain the edge"));
+}
+
+class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
+ public:
+ EdgeNeighborCountFieldInput()
+ : GeometryFieldInput(CPPType::get<int>(), "Edge Neighbor Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Array<int> face_count(mesh->totedge, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ face_count[mesh->mloop[i].e]++;
+ }
+
+ return mesh_component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 985671075;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const EdgeNeighborCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> neighbor_count_field{std::make_shared<EdgeNeighborCountFieldInput>()};
+ params.set_output("Face Count", std::move(neighbor_count_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_neighbors_cc
+
+void register_node_type_geo_input_mesh_edge_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
new file mode 100644
index 00000000000..473bef63e92
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -0,0 +1,188 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_vertices_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Index 1"))
+ .field_source()
+ .description(N_("The index of the first vertex in the edge"));
+ b.add_output<decl::Int>(N_("Vertex Index 2"))
+ .field_source()
+ .description(N_("The index of the second vertex in the edge"));
+ b.add_output<decl::Vector>(N_("Position 1"))
+ .field_source()
+ .description(N_("The position of the first vertex in the edge"));
+ b.add_output<decl::Vector>(N_("Position 2"))
+ .field_source()
+ .description(N_("The position of the second vertex in the edge"));
+}
+
+enum VertexNumber { VERTEX_ONE, VERTEX_TWO };
+
+static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component,
+ const VertexNumber vertex,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+ if (domain == ATTR_DOMAIN_EDGE) {
+
+ if (vertex == VERTEX_ONE) {
+ return VArray<int>::ForFunc(mesh->totpoly,
+ [mesh](const int i) -> int { return mesh->medge[i].v1; });
+ }
+ return VArray<int>::ForFunc(mesh->totpoly,
+ [mesh](const int i) -> int { return mesh->medge[i].v2; });
+ }
+ return {};
+}
+
+class EdgeVerticesFieldInput final : public GeometryFieldInput {
+ private:
+ VertexNumber vertex_;
+
+ public:
+ EdgeVerticesFieldInput(VertexNumber vertex)
+ : GeometryFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_edge_vertices_gvarray(mesh_component, vertex_, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ return vertex_ == VERTEX_ONE ? 23847562893465 : 92384598734567;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const EdgeVerticesFieldInput *other_field = dynamic_cast<const EdgeVerticesFieldInput *>(
+ &other)) {
+ return vertex_ == other_field->vertex_;
+ }
+ return false;
+ }
+};
+
+static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component,
+ const VertexNumber vertex,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (vertex == VERTEX_ONE) {
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForFunc(
+ mesh->totedge,
+ [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v1].co); }),
+ ATTR_DOMAIN_EDGE,
+ domain);
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForFunc(
+ mesh->totedge,
+ [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }),
+ ATTR_DOMAIN_EDGE,
+ domain);
+}
+
+class EdgePositionFieldInput final : public GeometryFieldInput {
+ private:
+ VertexNumber vertex_;
+
+ public:
+ EdgePositionFieldInput(VertexNumber vertex)
+ : GeometryFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_edge_positions_gvarray(mesh_component, vertex_, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ return vertex_ == VERTEX_ONE ? 987456978362 : 374587679866;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const EdgePositionFieldInput *other_field = dynamic_cast<const EdgePositionFieldInput *>(
+ &other)) {
+ return vertex_ == other_field->vertex_;
+ }
+ return false;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_field_1{std::make_shared<EdgeVerticesFieldInput>(VERTEX_ONE)};
+ Field<int> vertex_field_2{std::make_shared<EdgeVerticesFieldInput>(VERTEX_TWO)};
+ Field<float3> position_field_1{std::make_shared<EdgePositionFieldInput>(VERTEX_ONE)};
+ Field<float3> position_field_2{std::make_shared<EdgePositionFieldInput>(VERTEX_TWO)};
+
+ params.set_output("Vertex Index 1", std::move(vertex_field_1));
+ params.set_output("Vertex Index 2", std::move(vertex_field_2));
+ params.set_output("Position 1", std::move(position_field_1));
+ params.set_output("Position 2", std::move(position_field_2));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_vertices_cc
+
+void register_node_type_geo_input_mesh_edge_vertices()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_vertices_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
new file mode 100644
index 00000000000..538b9e9682d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
@@ -0,0 +1,96 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_face_area_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Area"))
+ .field_source()
+ .description(N_("The surface area of each of the mesh's faces"));
+}
+
+static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ auto area_fn = [mesh](const int i) -> float {
+ const MPoly *mp = &mesh->mpoly[i];
+ return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert);
+ };
+
+ return component.attribute_try_adapt_domain<float>(
+ VArray<float>::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain);
+}
+
+class FaceAreaFieldInput final : public GeometryFieldInput {
+ public:
+ FaceAreaFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Face Area Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_face_area_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 1346334523;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceAreaFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.set_output("Area", Field<float>(std::make_shared<FaceAreaFieldInput>()));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_face_area_cc
+
+void register_node_type_geo_input_mesh_face_area()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_face_area_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
new file mode 100644
index 00000000000..80bb25dc7ca
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
@@ -0,0 +1,158 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Count"))
+ .field_source()
+ .description(N_("Number of edges or points in the face"));
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces which share an edge with the face"));
+}
+
+static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Array<int> edge_count(mesh->totedge, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ edge_count[mesh->mloop[i].e]++;
+ }
+
+ Array<int> poly_count(mesh->totpoly, 0);
+ for (const int poly_num : IndexRange(mesh->totpoly)) {
+ MPoly &poly = mesh->mpoly[poly_num];
+ for (const int loop_num : IndexRange(poly.loopstart, poly.totloop)) {
+ poly_count[poly_num] += edge_count[mesh->mloop[loop_num].e] - 1;
+ }
+ }
+
+ return component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain);
+}
+
+class FaceNeighborCountFieldInput final : public GeometryFieldInput {
+ public:
+ FaceNeighborCountFieldInput()
+ : GeometryFieldInput(CPPType::get<int>(), "Face Neighbor Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_neighbor_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 823543774;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceNeighborCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ return component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForFunc(mesh->totpoly,
+ [mesh](const int i) -> float { return mesh->mpoly[i].totloop; }),
+ ATTR_DOMAIN_FACE,
+ domain);
+}
+
+class FaceVertexCountFieldInput final : public GeometryFieldInput {
+ public:
+ FaceVertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_vertex_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 236235463634;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const FaceVertexCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_count_field{std::make_shared<FaceVertexCountFieldInput>()};
+ Field<int> neighbor_count_field{std::make_shared<FaceNeighborCountFieldInput>()};
+ params.set_output("Vertex Count", std::move(vertex_count_field));
+ params.set_output("Face Count", std::move(neighbor_count_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_face_neighbors_cc
+
+void register_node_type_geo_input_mesh_face_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_face_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT, 0);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
new file mode 100644
index 00000000000..3c713ef6ca9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -0,0 +1,101 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "BLI_disjoint_set.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_island_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Index"))
+ .field_source()
+ .description(N_("Island indices are based on the order of the lowest-numbered vertex "
+ "contained in each island"));
+}
+
+class IslandFieldInput final : public GeometryFieldInput {
+ public:
+ IslandFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Index")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ DisjointSet islands(mesh->totvert);
+ for (const int i : IndexRange(mesh->totedge)) {
+ islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
+ }
+
+ Array<int> output(mesh->totvert);
+ VectorSet<int> ordered_roots;
+ for (const int i : IndexRange(mesh->totvert)) {
+ const int64_t root = islands.find_root(i);
+ output[i] = ordered_roots.index_of_or_add(root);
+ }
+
+ return mesh_component.attribute_try_adapt_domain<int>(
+ VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 635467354;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const IslandFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> island_field{std::make_shared<IslandFieldInput>()};
+ params.set_output("Index", std::move(island_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_island_cc
+
+void register_node_type_geo_input_mesh_island()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_island_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
new file mode 100644
index 00000000000..05140c92205
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
@@ -0,0 +1,155 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_vertex_neighbors_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>(N_("Vertex Count"))
+ .field_source()
+ .description(N_("Vertex count and edge count are equal"));
+ b.add_output<decl::Int>(N_("Face Count"))
+ .field_source()
+ .description(N_("Number of faces that contain the vertex"));
+}
+
+static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> vertices(mesh->totvert, 0);
+ for (const int i : IndexRange(mesh->totedge)) {
+ vertices[mesh->medge[i].v1]++;
+ vertices[mesh->medge[i].v2]++;
+ }
+ return VArray<int>::ForContainer(std::move(vertices));
+ }
+ return {};
+}
+
+class VertexCountFieldInput final : public GeometryFieldInput {
+ public:
+ VertexCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_vertex_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 23574528465;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VertexCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
+ const AttributeDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<int> vertices(mesh->totvert, 0);
+ for (const int i : IndexRange(mesh->totloop)) {
+ int vertex = mesh->mloop[i].v;
+ vertices[vertex]++;
+ }
+ return VArray<int>::ForContainer(std::move(vertices));
+ }
+ return {};
+}
+
+class VertexFaceCountFieldInput final : public GeometryFieldInput {
+ public:
+ VertexFaceCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Vertex Face Count Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_face_count_gvarray(mesh_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 3462374322;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VertexFaceCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<int> vertex_field{std::make_shared<VertexCountFieldInput>()};
+ Field<int> face_field{std::make_shared<VertexFaceCountFieldInput>()};
+
+ params.set_output("Vertex Count", std::move(vertex_field));
+ params.set_output("Face Count", std::move(face_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_vertex_neighbors_cc
+
+void register_node_type_geo_input_mesh_vertex_neighbors()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_vertex_neighbors_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT, 0);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
index 6c95ad73bf7..1cc508d9d9d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_normal_cc {
-static void geo_node_input_normal_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Normal")).field_source();
}
@@ -93,8 +93,7 @@ static VArray<float3> mesh_vertex_normals(const Mesh &mesh,
static VArray<float3> construct_mesh_normals_gvarray(const MeshComponent &mesh_component,
const Mesh &mesh,
const IndexMask mask,
- const AttributeDomain domain,
- ResourceScope &UNUSED(scope))
+ const AttributeDomain domain)
{
Span<MVert> verts{mesh.mvert, mesh.totvert};
Span<MEdge> edges{mesh.medge, mesh.totedge};
@@ -199,8 +198,7 @@ static Array<float3> curve_normal_point_domain(const CurveEval &curve)
}
static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &component,
- const AttributeDomain domain,
- ResourceScope &UNUSED(scope))
+ const AttributeDomain domain)
{
const CurveEval *curve = component.get_for_read();
if (curve == nullptr) {
@@ -231,36 +229,29 @@ static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &compo
return nullptr;
}
-class NormalFieldInput final : public fn::FieldInput {
+class NormalFieldInput final : public GeometryFieldInput {
public:
- NormalFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Normal node")
+ NormalFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Normal node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope);
- }
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_normal_gvarray(curve_component, domain, scope);
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
}
+
+ return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain);
+ }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_curve_normal_gvarray(curve_component, domain);
}
return {};
}
@@ -277,20 +268,22 @@ class NormalFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_input_normal_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> normal_field{std::make_shared<NormalFieldInput>()};
params.set_output("Normal", std::move(normal_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_normal_cc
void register_node_type_geo_input_normal()
{
+ namespace file_ns = blender::nodes::node_geo_input_normal_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_normal_exec;
- ntype.declare = blender::nodes::geo_node_input_normal_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
index a8477d4bc4f..8322831a871 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_position_cc {
-static void geo_node_input_position_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Position")).field_source();
}
-static void geo_node_input_position_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> position_field{AttributeFieldInput::Create<float3>("position")};
params.set_output("Position", std::move(position_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_position_cc
void register_node_type_geo_input_position()
{
+ namespace file_ns = blender::nodes::node_geo_input_position_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_position_exec;
- ntype.declare = blender::nodes::geo_node_input_position_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
index 6d2c4c38cbe..26fb74f5a5b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_radius_cc {
-static void geo_node_input_radius_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).field_source();
}
-static void geo_node_input_radius_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float> radius_field = AttributeFieldInput::Create<float>("radius");
params.set_output("Radius", std::move(radius_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_radius_cc
void register_node_type_geo_input_radius()
{
+ namespace file_ns = blender::nodes::node_geo_input_radius_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_radius_exec;
- ntype.declare = blender::nodes::geo_node_input_radius_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
new file mode 100644
index 00000000000..cfc1a81f7b9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_scene_time_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Seconds"));
+ b.add_output<decl::Float>(N_("Frame"));
+}
+
+static void node_exec(GeoNodeExecParams params)
+{
+ const Scene *scene = DEG_get_input_scene(params.depsgraph());
+ const float scene_ctime = BKE_scene_ctime_get(scene);
+ const double frame_rate = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
+ params.set_output("Seconds", float(scene_ctime / frame_rate));
+ params.set_output("Frame", scene_ctime);
+}
+
+} // namespace blender::nodes::node_geo_input_scene_time_cc
+
+void register_node_type_geo_input_scene_time()
+{
+ static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_geo_input_scene_time_cc;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT, 0);
+ ntype.geometry_node_execute = file_ns::node_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
index dcd14b1c054..3efe8577e51 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
@@ -16,27 +16,29 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_shade_smooth_cc {
-static void geo_node_input_shade_smooth_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Smooth")).field_source();
}
-static void geo_node_input_shade_smooth_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("shade_smooth");
params.set_output("Smooth", std::move(shade_smooth_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_shade_smooth_cc
void register_node_type_geo_input_shade_smooth()
{
+ namespace file_ns = blender::nodes::node_geo_input_shade_smooth_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_shade_smooth_exec;
- ntype.declare = blender::nodes::geo_node_input_shade_smooth_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
index a8ee6dd8b12..5f833445a76 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
@@ -16,28 +16,30 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_spline_cyclic_cc {
-static void geo_node_input_spline_cyclic_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Cyclic")).field_source();
}
-static void geo_node_input_spline_cyclic_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<bool> cyclic_field = AttributeFieldInput::Create<bool>("cyclic");
params.set_output("Cyclic", std::move(cyclic_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_spline_cyclic_cc
void register_node_type_geo_input_spline_cyclic()
{
+ namespace file_ns = blender::nodes::node_geo_input_spline_cyclic_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_cyclic_exec;
- ntype.declare = blender::nodes::geo_node_input_spline_cyclic_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index a976e0b193f..810d6e2fddd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -18,16 +18,20 @@
#include "BKE_spline.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_spline_length_cc {
-static void geo_node_input_spline_length_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Length")).field_source();
+ b.add_output<decl::Int>(N_("Point Count")).field_source();
}
+/* --------------------------------------------------------------------
+ * Spline Length
+ */
+
static VArray<float> construct_spline_length_gvarray(const CurveComponent &component,
- const AttributeDomain domain,
- ResourceScope &UNUSED(scope))
+ const AttributeDomain domain)
{
const CurveEval *curve = component.get_for_read();
if (curve == nullptr) {
@@ -46,29 +50,23 @@ static VArray<float> construct_spline_length_gvarray(const CurveComponent &compo
std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
- return nullptr;
+ return {};
}
-class SplineLengthFieldInput final : public fn::FieldInput {
+class SplineLengthFieldInput final : public GeometryFieldInput {
public:
- SplineLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Spline Length node")
+ SplineLengthFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_spline_length_gvarray(curve_component, domain, scope);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_spline_length_gvarray(curve_component, domain);
}
return {};
}
@@ -85,20 +83,81 @@ class SplineLengthFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_input_spline_length_exec(GeoNodeExecParams params)
+/* --------------------------------------------------------------------
+ * Spline Count
+ */
+
+static VArray<int> construct_spline_count_gvarray(const CurveComponent &component,
+ const AttributeDomain domain)
+{
+ const CurveEval *curve = component.get_for_read();
+ if (curve == nullptr) {
+ return {};
+ }
+
+ Span<SplinePtr> splines = curve->splines();
+ auto count_fn = [splines](int i) { return splines[i]->size(); };
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ return VArray<int>::ForFunc(splines.size(), count_fn);
+ }
+ if (domain == ATTR_DOMAIN_POINT) {
+ VArray<int> count = VArray<int>::ForFunc(splines.size(), count_fn);
+ return component.attribute_try_adapt_domain<int>(
+ std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ }
+
+ return {};
+}
+
+class SplineCountFieldInput final : public GeometryFieldInput {
+ public:
+ SplineCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Spline Point Count")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_spline_count_gvarray(curve_component, domain);
+ }
+ return {};
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 456364322625;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const SplineCountFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
{
- Field<float> length_field{std::make_shared<SplineLengthFieldInput>()};
- params.set_output("Length", std::move(length_field));
+ Field<float> spline_length_field{std::make_shared<SplineLengthFieldInput>()};
+ Field<int> spline_count_field{std::make_shared<SplineCountFieldInput>()};
+
+ params.set_output("Length", std::move(spline_length_field));
+ params.set_output("Point Count", std::move(spline_count_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_spline_length_cc
void register_node_type_geo_input_spline_length()
{
- static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_geo_input_spline_length_cc;
+ static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_length_exec;
- ntype.declare = blender::nodes::geo_node_input_spline_length_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
index 75fb8a13d38..77b6e27e6a2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
@@ -16,28 +16,30 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_spline_resolution_cc {
-static void geo_node_input_spline_resolution_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("Resolution")).field_source();
}
-static void geo_node_input_spline_resolution_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<int> resolution_field = AttributeFieldInput::Create<int>("resolution");
params.set_output("Resolution", std::move(resolution_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_spline_resolution_cc
void register_node_type_geo_input_spline_resolution()
{
+ namespace file_ns = blender::nodes::node_geo_input_spline_resolution_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_resolution_exec;
- ntype.declare = blender::nodes::geo_node_input_spline_resolution_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index 49885f29d44..86f882df3cd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -20,9 +20,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_input_tangent_cc {
-static void geo_node_input_tangent_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Tangent")).field_source();
}
@@ -85,8 +85,7 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve)
}
static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
- const AttributeDomain domain,
- ResourceScope &UNUSED(scope))
+ const AttributeDomain domain)
{
const CurveEval *curve = component.get_for_read();
if (curve == nullptr) {
@@ -118,27 +117,20 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp
return nullptr;
}
-class TangentFieldInput final : public fn::FieldInput {
+class TangentFieldInput final : public GeometryFieldInput {
public:
- TangentFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Tangent node")
+ TangentFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Tangent node")
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask UNUSED(mask),
- ResourceScope &scope) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
-
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
-
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_tangent_gvarray(curve_component, domain, scope);
- }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return construct_curve_tangent_gvarray(curve_component, domain);
}
return {};
}
@@ -155,20 +147,22 @@ class TangentFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_input_tangent_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Field<float3> tangent_field{std::make_shared<TangentFieldInput>()};
params.set_output("Tangent", std::move(tangent_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_input_tangent_cc
void register_node_type_geo_input_tangent()
{
+ namespace file_ns = blender::nodes::node_geo_input_tangent_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_input_tangent_exec;
- ntype.declare = blender::nodes::geo_node_input_tangent_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index 2a68030aba7..486f90760f5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -22,11 +22,13 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "BKE_attribute_math.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_instance_on_points_cc {
-static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Points")).description(N_("Points to instance on"));
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
@@ -53,20 +55,34 @@ static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void add_instances_from_component(InstancesComponent &dst_component,
- const GeometryComponent &src_component,
- const GeometrySet &instance,
- const GeoNodeExecParams &params)
+static void add_instances_from_component(
+ InstancesComponent &dst_component,
+ const GeometryComponent &src_component,
+ const GeometrySet &instance,
+ const GeoNodeExecParams &params,
+ const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate)
{
const AttributeDomain domain = ATTR_DOMAIN_POINT;
const int domain_size = src_component.attribute_domain_size(domain);
+ VArray<bool> pick_instance;
+ VArray<int> indices;
+ VArray<float3> rotations;
+ VArray<float3> scales;
+
GeometryComponentFieldContext field_context{src_component, domain};
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ /* The evaluator could use the component's stable IDs as a destination directly, but only the
+ * selected indices should be copied. */
+ evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
+ evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
+ evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
+ evaluator.add(params.get_input<Field<float3>>("Scale"), &scales);
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
/* The initial size of the component might be non-zero when this function is called for multiple
* component types. */
@@ -79,19 +95,6 @@ static void add_instances_from_component(InstancesComponent &dst_component,
MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
select_len);
- FieldEvaluator field_evaluator{field_context, domain_size};
- VArray<bool> pick_instance;
- VArray<int> indices;
- VArray<float3> rotations;
- VArray<float3> scales;
- /* The evaluator could use the component's stable IDs as a destination directly, but only the
- * selected indices should be copied. */
- field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
- field_evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
- field_evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
- field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales);
- field_evaluator.evaluate();
-
VArray<float3> positions = src_component.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
@@ -154,17 +157,6 @@ static void add_instances_from_component(InstancesComponent &dst_component,
}
});
- VArray<int> ids = src_component
- .attribute_try_get_for_read("id", ATTR_DOMAIN_POINT, CD_PROP_INT32)
- .typed<int>();
- if (ids) {
- VArray_Span<int> ids_span{ids};
- MutableSpan<int> dst_ids = dst_component.instance_ids_ensure();
- for (const int64_t i : selection.index_range()) {
- dst_ids[i] = ids_span[selection[i]];
- }
- }
-
if (pick_instance.is_single()) {
if (pick_instance.get_internal_single()) {
if (instance.has_realized_data()) {
@@ -174,9 +166,40 @@ static void add_instances_from_component(InstancesComponent &dst_component,
}
}
}
+
+ bke::CustomDataAttributes &instance_attributes = dst_component.attributes();
+ for (const auto item : attributes_to_propagate.items()) {
+ const AttributeIDRef &attribute_id = item.key;
+ const AttributeKind attribute_kind = item.value;
+
+ const GVArray src_attribute = src_component.attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
+ BLI_assert(src_attribute);
+ std::optional<GMutableSpan> dst_attribute_opt = instance_attributes.get_for_write(
+ attribute_id);
+ if (!dst_attribute_opt) {
+ if (!instance_attributes.create(attribute_id, attribute_kind.data_type)) {
+ continue;
+ }
+ dst_attribute_opt = instance_attributes.get_for_write(attribute_id);
+ }
+ BLI_assert(dst_attribute_opt);
+ const GMutableSpan dst_attribute = dst_attribute_opt->slice(start_len, select_len);
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) {
+ attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray<T> src = src_attribute.typed<T>();
+ MutableSpan<T> dst = dst_attribute.typed<T>();
+ for (const int range_i : selection_range) {
+ const int i = selection[range_i];
+ dst[range_i] = src[i];
+ }
+ });
+ });
+ }
}
-static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
GeometrySet instance = params.get_input<GeometrySet>("Instance");
@@ -185,23 +208,36 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ geometry_set.gather_attributes_for_propagation(
+ {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE},
+ GEO_COMPONENT_TYPE_INSTANCES,
+ false,
+ attributes_to_propagate);
+ attributes_to_propagate.remove("position");
+
if (geometry_set.has<MeshComponent>()) {
- add_instances_from_component(
- instances, *geometry_set.get_component_for_read<MeshComponent>(), instance, params);
- geometry_set.remove(GEO_COMPONENT_TYPE_MESH);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<MeshComponent>(),
+ instance,
+ params,
+ attributes_to_propagate);
}
if (geometry_set.has<PointCloudComponent>()) {
add_instances_from_component(instances,
*geometry_set.get_component_for_read<PointCloudComponent>(),
instance,
- params);
- geometry_set.remove(GEO_COMPONENT_TYPE_POINT_CLOUD);
+ params,
+ attributes_to_propagate);
}
if (geometry_set.has<CurveComponent>()) {
- add_instances_from_component(
- instances, *geometry_set.get_component_for_read<CurveComponent>(), instance, params);
- geometry_set.remove(GEO_COMPONENT_TYPE_CURVE);
+ add_instances_from_component(instances,
+ *geometry_set.get_component_for_read<CurveComponent>(),
+ instance,
+ params,
+ attributes_to_propagate);
}
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
});
/* Unused references may have been added above. Remove those now so that other nodes don't
@@ -214,15 +250,17 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params)
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_instance_on_points_cc
void register_node_type_geo_instance_on_points()
{
+ namespace file_ns = blender::nodes::node_geo_instance_on_points_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_instance_on_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_instance_on_points_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index c3955426e69..9942e388ba5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -14,14 +14,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "BKE_pointcloud.h"
#include "DNA_pointcloud_types.h"
+#include "BKE_attribute_math.hh"
+#include "BKE_pointcloud.h"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_instances_to_points_cc {
-static void geo_node_instances_to_points_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -51,14 +53,15 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
{
const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
- const AttributeDomain attribute_domain = ATTR_DOMAIN_POINT;
- GeometryComponentFieldContext field_context{instances, attribute_domain};
- const int domain_size = instances.attribute_domain_size(attribute_domain);
+ GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
+ const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(std::move(selection_field));
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(std::move(selection_field));
+ evaluator.add(std::move(position_field));
+ evaluator.add(std::move(radius_field));
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
if (selection.is_empty()) {
return;
}
@@ -68,27 +71,40 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
- fn::FieldEvaluator evaluator{field_context, &selection};
- evaluator.add(std::move(position_field));
- evaluator.add(std::move(radius_field));
- evaluator.evaluate();
const VArray<float3> &positions = evaluator.get_evaluated<float3>(0);
copy_attribute_to_points(positions, selection, {(float3 *)pointcloud->co, pointcloud->totpoint});
const VArray<float> &radii = evaluator.get_evaluated<float>(1);
copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint});
- if (!instances.instance_ids().is_empty()) {
- OutputAttribute_Typed<int> id_attribute = points.attribute_try_get_for_output<int>(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- MutableSpan<int> ids = id_attribute.as_span();
- for (const int i : selection.index_range()) {
- ids[i] = instances.instance_ids()[selection[i]];
- }
- id_attribute.save();
+ Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
+ geometry_set.gather_attributes_for_propagation({GEO_COMPONENT_TYPE_INSTANCES},
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ false,
+ attributes_to_propagate);
+ /* These two attributes are added by the implicit inputs above. */
+ attributes_to_propagate.remove("position");
+ attributes_to_propagate.remove("radius");
+
+ for (const auto item : attributes_to_propagate.items()) {
+ const AttributeIDRef &attribute_id = item.key;
+ const AttributeKind attribute_kind = item.value;
+
+ const GVArray src = instances.attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type);
+ BLI_assert(src);
+ OutputAttribute dst = points.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
+ BLI_assert(dst);
+
+ attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_attribute_to_points(src.typed<T>(), selection, dst.as_span().typed<T>());
+ });
+ dst.save();
}
}
-static void geo_node_instances_to_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
@@ -101,19 +117,21 @@ static void geo_node_instances_to_points_exec(GeoNodeExecParams params)
params.set_output("Points", std::move(geometry_set));
}
else {
- params.set_output("Points", GeometrySet());
+ params.set_default_remaining_outputs();
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_instances_to_points_cc
void register_node_type_geo_instances_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_instances_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_instances_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_instances_to_points_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
index 8e0e98f7bd5..5925d440317 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
@@ -18,14 +18,14 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_is_viewport_cc {
-static void geo_node_is_viewport_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Is Viewport"));
}
-static void geo_node_is_viewport_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const Depsgraph *depsgraph = params.depsgraph();
const eEvaluationMode mode = DEG_get_mode(depsgraph);
@@ -34,14 +34,16 @@ static void geo_node_is_viewport_exec(GeoNodeExecParams params)
params.set_output("Is Viewport", is_viewport);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_is_viewport_cc
void register_node_type_geo_is_viewport()
{
+ namespace file_ns = blender::nodes::node_geo_is_viewport_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_is_viewport_exec;
- ntype.declare = blender::nodes::geo_node_is_viewport_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index fcdf7c2da01..bf7a9f49829 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -19,127 +19,23 @@
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
#include "BKE_spline.hh"
+#include "BKE_type_conversions.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "NOD_type_conversions.hh"
+#include "GEO_realize_instances.hh"
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_join_geometry_cc {
-static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).multi_input();
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static Mesh *join_mesh_topology_and_builtin_attributes(Span<const MeshComponent *> src_components)
-{
- int totverts = 0;
- int totloops = 0;
- int totedges = 0;
- int totpolys = 0;
-
- int64_t cd_dirty_vert = 0;
- int64_t cd_dirty_poly = 0;
- int64_t cd_dirty_edge = 0;
- int64_t cd_dirty_loop = 0;
-
- VectorSet<Material *> materials;
-
- for (const MeshComponent *mesh_component : src_components) {
- const Mesh *mesh = mesh_component->get_for_read();
- totverts += mesh->totvert;
- totloops += mesh->totloop;
- totedges += mesh->totedge;
- totpolys += mesh->totpoly;
- cd_dirty_vert |= mesh->runtime.cd_dirty_vert;
- cd_dirty_poly |= mesh->runtime.cd_dirty_poly;
- cd_dirty_edge |= mesh->runtime.cd_dirty_edge;
- cd_dirty_loop |= mesh->runtime.cd_dirty_loop;
-
- for (const int slot_index : IndexRange(mesh->totcol)) {
- Material *material = mesh->mat[slot_index];
- materials.add(material);
- }
- }
-
- const Mesh *first_input_mesh = src_components[0]->get_for_read();
- Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
- BKE_mesh_copy_parameters_for_eval(new_mesh, first_input_mesh);
-
- for (const int i : IndexRange(materials.size())) {
- Material *material = materials[i];
- BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
- }
-
- new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
- new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
- new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
- new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
-
- int vert_offset = 0;
- int loop_offset = 0;
- int edge_offset = 0;
- int poly_offset = 0;
- for (const MeshComponent *mesh_component : src_components) {
- const Mesh *mesh = mesh_component->get_for_read();
- if (mesh == nullptr) {
- continue;
- }
-
- Array<int> material_index_map(mesh->totcol);
- for (const int i : IndexRange(mesh->totcol)) {
- Material *material = mesh->mat[i];
- const int new_material_index = materials.index_of(material);
- material_index_map[i] = new_material_index;
- }
-
- for (const int i : IndexRange(mesh->totvert)) {
- const MVert &old_vert = mesh->mvert[i];
- MVert &new_vert = new_mesh->mvert[vert_offset + i];
- new_vert = old_vert;
- }
-
- for (const int i : IndexRange(mesh->totedge)) {
- const MEdge &old_edge = mesh->medge[i];
- MEdge &new_edge = new_mesh->medge[edge_offset + i];
- new_edge = old_edge;
- new_edge.v1 += vert_offset;
- new_edge.v2 += vert_offset;
- }
- for (const int i : IndexRange(mesh->totloop)) {
- const MLoop &old_loop = mesh->mloop[i];
- MLoop &new_loop = new_mesh->mloop[loop_offset + i];
- new_loop = old_loop;
- new_loop.v += vert_offset;
- new_loop.e += edge_offset;
- }
- for (const int i : IndexRange(mesh->totpoly)) {
- const MPoly &old_poly = mesh->mpoly[i];
- MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
- new_poly = old_poly;
- new_poly.loopstart += loop_offset;
- if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh->totcol) {
- new_poly.mat_nr = material_index_map[new_poly.mat_nr];
- }
- else {
- /* The material index was invalid before. */
- new_poly.mat_nr = 0;
- }
- }
-
- vert_offset += mesh->totvert;
- loop_offset += mesh->totloop;
- edge_offset += mesh->totedge;
- poly_offset += mesh->totpoly;
- }
-
- return new_mesh;
-}
-
template<typename Component>
static Array<const GeometryComponent *> to_base_components(Span<const Component *> components)
{
@@ -223,33 +119,6 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
}
}
-static void join_components(Span<const MeshComponent *> src_components, GeometrySet &result)
-{
- Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(src_components);
-
- MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
- dst_component.replace(new_mesh);
-
- /* Don't copy attributes that are stored directly in the mesh data structs. */
- join_attributes(to_base_components(src_components),
- dst_component,
- {"position", "material_index", "normal", "shade_smooth", "crease"});
-}
-
-static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result)
-{
- int totpoints = 0;
- for (const PointCloudComponent *pointcloud_component : src_components) {
- totpoints += pointcloud_component->attribute_domain_size(ATTR_DOMAIN_POINT);
- }
-
- PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
- PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoints);
- dst_component.replace(pointcloud);
-
- join_attributes(to_base_components(src_components), dst_component);
-}
-
static void join_components(Span<const InstancesComponent *> src_components, GeometrySet &result)
{
InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>();
@@ -288,192 +157,6 @@ static void join_components(Span<const VolumeComponent *> src_components, Geomet
UNUSED_VARS(src_components, dst_component);
}
-/**
- * \note This takes advantage of the fact that creating attributes on joined curves never
- * changes a point attribute into a spline attribute; it is always the other way around.
- */
-static void ensure_control_point_attribute(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- MutableSpan<SplinePtr> splines = result.splines();
- const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
-
- /* In order to fill point attributes with spline domain attribute values where necessary, keep
- * track of the curve each spline came from while iterating over the splines in the result. */
- int src_component_index = 0;
- int spline_index_in_component = 0;
- const CurveEval *current_curve = src_components[src_component_index]->get_for_read();
-
- for (SplinePtr &spline : splines) {
- std::optional<GSpan> attribute = spline->attributes.get_for_read(attribute_id);
-
- if (attribute) {
- if (attribute->type() != type) {
- /* In this case, the attribute exists, but it has the wrong type. So create a buffer
- * for the converted values, do the conversion, and then replace the attribute. */
- void *converted_buffer = MEM_mallocN_aligned(
- spline->size() * type.size(), type.alignment(), __func__);
-
- const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions();
- conversions.try_convert(GVArray::ForSpan(*attribute), type).materialize(converted_buffer);
-
- spline->attributes.remove(attribute_id);
- spline->attributes.create_by_move(attribute_id, data_type, converted_buffer);
- }
- }
- else {
- spline->attributes.create(attribute_id, data_type);
-
- if (current_curve->attributes.get_for_read(attribute_id)) {
- /* In this case the attribute did not exist, but there is a spline domain attribute
- * we can retrieve a value from, as a spline to point domain conversion. So fill the
- * new attribute with the value for this spline. */
- GVArray current_curve_attribute = current_curve->attributes.get_for_read(
- attribute_id, data_type, nullptr);
-
- BLI_assert(spline->attributes.get_for_read(attribute_id));
- std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id);
-
- BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
- current_curve_attribute.get(spline_index_in_component, buffer);
- type.fill_assign_n(buffer, new_attribute->data(), new_attribute->size());
- }
- }
-
- /* Move to the next spline and maybe the next input component. */
- spline_index_in_component++;
- if (spline != splines.last() && spline_index_in_component >= current_curve->splines().size()) {
- src_component_index++;
- spline_index_in_component = 0;
-
- current_curve = src_components[src_component_index]->get_for_read();
- }
- }
-}
-
-/**
- * Curve point domain attributes must be in the same order on every spline. The order might have
- * been different on separate instances, so ensure that all splines have the same order. Note that
- * because #Map is used, the order is not necessarily consistent every time, but it is the same for
- * every spline, and that's what matters.
- */
-static void sort_curve_point_attributes(const Map<AttributeIDRef, AttributeMetaData> &info,
- MutableSpan<SplinePtr> splines)
-{
- Vector<AttributeIDRef> new_order;
- for (Map<AttributeIDRef, AttributeMetaData>::Item item : info.items()) {
- if (item.value.domain == ATTR_DOMAIN_POINT) {
- /* Only sort attributes stored on splines. */
- new_order.append(item.key);
- }
- }
- for (SplinePtr &spline : splines) {
- spline->attributes.reorder(new_order);
- }
-}
-
-/**
- * Fill data for an attribute on the new curve based on all source curves.
- */
-static void ensure_spline_attribute(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
-
- result.attributes.create(attribute_id, data_type);
- GMutableSpan result_attribute = *result.attributes.get_for_write(attribute_id);
-
- int offset = 0;
- for (const CurveComponent *component : src_components) {
- const CurveEval &curve = *component->get_for_read();
- const int size = curve.splines().size();
- if (size == 0) {
- continue;
- }
- GVArray read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr);
- GVArray_GSpan src_span{read_attribute};
-
- const void *src_buffer = src_span.data();
- type.copy_assign_n(src_buffer, result_attribute[offset], size);
-
- offset += size;
- }
-}
-
-/**
- * Special handling for copying spline attributes. This is necessary because we move the splines
- * out of the source components instead of copying them, meaning we can no longer access point
- * domain attributes on the source components.
- *
- * \warning Splines have been moved out of the source components at this point, so it
- * is important to only read curve-level data (spline domain attributes) from them.
- */
-static void join_curve_attributes(const Map<AttributeIDRef, AttributeMetaData> &info,
- Span<CurveComponent *> src_components,
- CurveEval &result)
-{
- for (const Map<AttributeIDRef, AttributeMetaData>::Item item : info.items()) {
- const AttributeIDRef attribute_id = item.key;
- const AttributeMetaData meta_data = item.value;
-
- if (meta_data.domain == ATTR_DOMAIN_CURVE) {
- ensure_spline_attribute(attribute_id, meta_data.data_type, src_components, result);
- }
- else {
- ensure_control_point_attribute(attribute_id, meta_data.data_type, src_components, result);
- }
- }
-
- sort_curve_point_attributes(info, result.splines());
-}
-
-static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, GeometrySet &result)
-{
- Vector<CurveComponent *> src_components;
- for (GeometrySet &geometry_set : src_geometry_sets) {
- if (geometry_set.has_curve()) {
- /* Retrieving with write access seems counterintuitive, but it can allow avoiding a copy
- * in the case where the input spline has no other users, because the splines can be
- * moved from the source curve rather than copied from a read-only source. Retrieving
- * the curve for write will make a copy only when it has a user elsewhere. */
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
- src_components.append(&component);
- }
- }
-
- if (src_components.size() == 0) {
- return;
- }
- if (src_components.size() == 1) {
- result.add(*src_components[0]);
- return;
- }
-
- /* Retrieve attribute info before moving the splines out of the input components. */
- const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(
- {(const GeometryComponent **)src_components.data(), src_components.size()},
- {"position", "radius", "tilt", "handle_left", "handle_right", "cyclic", "resolution"});
-
- CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
- CurveEval *dst_curve = new CurveEval();
- for (CurveComponent *component : src_components) {
- CurveEval *src_curve = component->get_for_write();
- for (SplinePtr &spline : src_curve->splines()) {
- dst_curve->add_spline(std::move(spline));
- }
- }
- dst_curve->attributes.reallocate(dst_curve->splines().size());
-
- join_curve_attributes(info, src_components, *dst_curve);
- dst_curve->assert_valid_point_attributes();
-
- dst_component.replace(dst_curve);
-}
-
template<typename Component>
static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet &result)
{
@@ -492,10 +175,32 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet
result.add(*components[0]);
return;
}
- join_components(components, result);
+
+ GeometrySet instances_geometry_set;
+ InstancesComponent &instances =
+ instances_geometry_set.get_component_for_write<InstancesComponent>();
+
+ if constexpr (std::is_same_v<Component, InstancesComponent> ||
+ std::is_same_v<Component, VolumeComponent>) {
+ join_components(components, result);
+ }
+ else {
+ for (const Component *component : components) {
+ GeometrySet tmp_geo;
+ tmp_geo.add(*component);
+ const int handle = instances.add_reference(InstanceReference{tmp_geo});
+ instances.add_instance(handle, float4x4::identity());
+ }
+
+ geometry::RealizeInstancesOptions options;
+ options.keep_original_ids = true;
+ options.realize_instance_attributes = false;
+ GeometrySet joined_components = geometry::realize_instances(instances_geometry_set, options);
+ result.add(joined_components.get_component_for_write<Component>());
+ }
}
-static void geo_node_join_geometry_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry");
@@ -504,18 +209,20 @@ static void geo_node_join_geometry_exec(GeoNodeExecParams params)
join_component_type<PointCloudComponent>(geometry_sets, geometry_set_result);
join_component_type<InstancesComponent>(geometry_sets, geometry_set_result);
join_component_type<VolumeComponent>(geometry_sets, geometry_set_result);
- join_curve_components(geometry_sets, geometry_set_result);
+ join_component_type<CurveComponent>(geometry_sets, geometry_set_result);
params.set_output("Geometry", std::move(geometry_set_result));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_join_geometry_cc
void register_node_type_geo_join_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_join_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_join_geometry_exec;
- ntype.declare = blender::nodes::geo_node_join_geometry_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
index e4a62bd5267..5a334126350 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
@@ -24,9 +24,9 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_material_replace_cc {
-static void geo_node_material_replace_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Material>(N_("Old"));
@@ -34,7 +34,7 @@ static void geo_node_material_replace_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_material_replace_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *old_material = params.extract_input<Material *>("Old");
Material *new_material = params.extract_input<Material *>("New");
@@ -55,15 +55,17 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_material_replace_cc
void register_node_type_geo_material_replace()
{
+ namespace file_ns = blender::nodes::node_geo_material_replace_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_material_replace_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_material_replace_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index 12ffa21762e..2aad68e7c25 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -26,9 +26,9 @@
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_material_selection_cc {
-static void geo_node_material_selection_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Material>(N_("Material")).hide_label(true);
b.add_output<decl::Bool>(N_("Selection")).field_source();
@@ -54,45 +54,40 @@ static void select_mesh_by_material(const Mesh &mesh,
});
}
-class MaterialSelectionFieldInput final : public fn::FieldInput {
+class MaterialSelectionFieldInput final : public GeometryFieldInput {
Material *material_;
public:
MaterialSelectionFieldInput(Material *material)
- : fn::FieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material)
+ : GeometryFieldInput(CPPType::get<bool>(), "Material Selection node"), material_(material)
{
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const final
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
- if (component.type() != GEO_COMPONENT_TYPE_MESH) {
- return {};
- }
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
- return {};
- }
-
- if (domain == ATTR_DOMAIN_FACE) {
- Array<bool> selection(mask.min_array_size());
- select_mesh_by_material(*mesh, material_, mask, selection);
- return VArray<bool>::ForContainer(std::move(selection));
- }
-
- Array<bool> selection(mesh->totpoly);
- select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
- return mesh_component.attribute_try_adapt_domain<bool>(
- VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ if (domain == ATTR_DOMAIN_FACE) {
+ Array<bool> selection(mask.min_array_size());
+ select_mesh_by_material(*mesh, material_, mask, selection);
+ return VArray<bool>::ForContainer(std::move(selection));
}
+ Array<bool> selection(mesh->totpoly);
+ select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
+ return mesh_component.attribute_try_adapt_domain<bool>(
+ VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
+
return nullptr;
}
@@ -111,22 +106,24 @@ class MaterialSelectionFieldInput final : public fn::FieldInput {
}
};
-static void geo_node_material_selection_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
Field<bool> material_field{std::make_shared<MaterialSelectionFieldInput>(material)};
params.set_output("Selection", std::move(material_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_material_selection_cc
void register_node_type_geo_material_selection()
{
+ namespace file_ns = blender::nodes::node_geo_material_selection_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_material_selection_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_material_selection_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index f1f95be107a..7a1cb8a62a3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -25,9 +25,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_circle_cc {
-static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshCircle)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Vertices"))
.default_value(32)
@@ -41,16 +43,14 @@ static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_mesh_primitive_circle_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN(
sizeof(NodeGeometryMeshCircle), __func__);
@@ -199,42 +199,41 @@ static Mesh *create_circle_mesh(const float radius,
return mesh;
}
-static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCircle &storage = *(const NodeGeometryMeshCircle *)node.storage;
-
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
+ const NodeGeometryMeshCircle &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
const float radius = params.extract_input<float>("Radius");
const int verts_num = params.extract_input<int>("Vertices");
if (verts_num < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- params.set_output("Mesh", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
- Mesh *mesh = create_circle_mesh(radius, verts_num, fill_type);
+ Mesh *mesh = create_circle_mesh(radius, verts_num, fill);
BLI_assert(BKE_mesh_is_valid(mesh));
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_circle_cc
void register_node_type_geo_mesh_primitive_circle()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_circle_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_circle_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_circle_layout;
- ntype.declare = blender::nodes::geo_node_mesh_primitive_circle_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index fc93f6e72b5..70b093798f8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -29,75 +29,6 @@
namespace blender::nodes {
-static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Int>(N_("Vertices"))
- .default_value(32)
- .min(3)
- .max(512)
- .description(N_("Number of points on the circle at the top and bottom"));
- b.add_input<decl::Int>(N_("Side Segments"))
- .default_value(1)
- .min(1)
- .max(512)
- .description(N_("The number of edges running vertically along the side of the cone"));
- b.add_input<decl::Int>(N_("Fill Segments"))
- .default_value(1)
- .min(1)
- .max(512)
- .description(N_("Number of concentric rings used to fill the round face"));
- b.add_input<decl::Float>(N_("Radius Top"))
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Radius of the top circle of the cone"));
- b.add_input<decl::Float>(N_("Radius Bottom"))
- .default_value(1.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Radius of the bottom circle of the cone"));
- b.add_input<decl::Float>(N_("Depth"))
- .default_value(2.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Height of the generated cone"));
- b.add_output<decl::Geometry>(N_("Mesh"));
- b.add_output<decl::Bool>(N_("Top")).field_source();
- b.add_output<decl::Bool>(N_("Bottom")).field_source();
- b.add_output<decl::Bool>(N_("Side")).field_source();
-}
-
-static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
- sizeof(NodeGeometryMeshCone), __func__);
-
- node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
-
- node->storage = node_storage;
-}
-
-static void geo_node_mesh_primitive_cone_update(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
- bNodeSocket *rings_socket = vertices_socket->next;
- bNodeSocket *fill_subdiv_socket = rings_socket->next;
-
- const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage;
- const GeometryNodeMeshCircleFillType fill_type =
- static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type);
- const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
- nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
-}
-
-static void geo_node_mesh_primitive_cone_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
-}
-
struct ConeConfig {
float radius_top;
float radius_bottom;
@@ -794,37 +725,103 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
return mesh;
}
-static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_cone_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryMeshCone)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Vertices"))
+ .default_value(32)
+ .min(3)
+ .max(512)
+ .description(N_("Number of points on the circle at the top and bottom"));
+ b.add_input<decl::Int>(N_("Side Segments"))
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description(N_("The number of edges running vertically along the side of the cone"));
+ b.add_input<decl::Int>(N_("Fill Segments"))
+ .default_value(1)
+ .min(1)
+ .max(512)
+ .description(N_("Number of concentric rings used to fill the round face"));
+ b.add_input<decl::Float>(N_("Radius Top"))
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Radius of the top circle of the cone"));
+ b.add_input<decl::Float>(N_("Radius Bottom"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Radius of the bottom circle of the cone"));
+ b.add_input<decl::Float>(N_("Depth"))
+ .default_value(2.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Height of the generated cone"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Bool>(N_("Top")).field_source();
+ b.add_output<decl::Bool>(N_("Bottom")).field_source();
+ b.add_output<decl::Bool>(N_("Side")).field_source();
+}
+
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage;
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
-
- auto return_default = [&]() {
- params.set_output("Top", fn::make_constant_field<bool>(false));
- params.set_output("Bottom", fn::make_constant_field<bool>(false));
- params.set_output("Side", fn::make_constant_field<bool>(false));
- params.set_output("Mesh", GeometrySet());
- };
+ NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
+ sizeof(NodeGeometryMeshCone), __func__);
+
+ node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
+
+ node->storage = node_storage;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *rings_socket = vertices_socket->next;
+ bNodeSocket *fill_subdiv_socket = rings_socket->next;
+
+ const NodeGeometryMeshCone &storage = node_storage(*node);
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
+ const bool has_fill = fill != GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryMeshCone &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
const int circle_segments = params.extract_input<int>("Vertices");
if (circle_segments < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const int side_segments = params.extract_input<int>("Side Segments");
if (side_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
- const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ const bool no_fill = fill == GEO_NODE_MESH_CIRCLE_FILL_NONE;
const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments");
if (fill_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const float radius_top = params.extract_input<float>("Radius Top");
@@ -848,7 +845,7 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
circle_segments,
side_segments,
fill_segments,
- fill_type,
+ fill,
attribute_outputs);
/* Transform the mesh so that the base of the cone is at the origin. */
@@ -874,19 +871,21 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cone_cc
void register_node_type_geo_mesh_primitive_cone()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cone_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cone_init);
- node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cone_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cone_layout;
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cone_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index b5903f7b71e..2542542c919 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -24,31 +24,6 @@
namespace blender::nodes {
-static void geo_node_mesh_primitive_cube_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Vector>(N_("Size"))
- .default_value(float3(1))
- .min(0.0f)
- .subtype(PROP_TRANSLATION)
- .description(N_("Side length along each axis"));
- b.add_input<decl::Int>(N_("Vertices X"))
- .default_value(2)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices for the X side of the shape"));
- b.add_input<decl::Int>(N_("Vertices Y"))
- .default_value(2)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices for the Y side of the shape"));
- b.add_input<decl::Int>(N_("Vertices Z"))
- .default_value(2)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices for the Z side of the shape"));
- b.add_output<decl::Geometry>(N_("Mesh"));
-}
-
struct CuboidConfig {
float3 size;
int verts_x;
@@ -102,23 +77,37 @@ static void calculate_vertices(const CuboidConfig &config, MutableSpan<MVert> ve
int vert_index = 0;
- /* Though looping over all possible coordinates inside the cube only to skip them may be slow,
- * the alternative is similar complexity to below in the poly index calculation. If this loop
- * becomes a problem in the future it could be optimized, though only after proper performance
- * testing. */
for (const int z : IndexRange(config.verts_z)) {
- for (const int y : IndexRange(config.verts_y)) {
- for (const int x : IndexRange(config.verts_x)) {
- /* Only plot vertices on the surface of the cuboid. */
- if (ELEM(z, 0, config.edges_z) || ELEM(x, 0, config.edges_x) ||
- ELEM(y, 0, config.edges_y)) {
-
+ if (ELEM(z, 0, config.edges_z)) {
+ /* Fill bottom and top. */
+ const float z_pos = z_bottom + z_delta * z;
+ for (const int y : IndexRange(config.verts_y)) {
+ const float y_pos = y_front + y_delta * y;
+ for (const int x : IndexRange(config.verts_x)) {
const float x_pos = x_left + x_delta * x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ }
+ }
+ }
+ else {
+ for (const int y : IndexRange(config.verts_y)) {
+ if (ELEM(y, 0, config.edges_y)) {
+ /* Fill y-sides. */
const float y_pos = y_front + y_delta * y;
const float z_pos = z_bottom + z_delta * z;
- copy_v3_v3(verts[vert_index].co, float3(x_pos, y_pos, z_pos));
-
- vert_index++;
+ for (const int x : IndexRange(config.verts_x)) {
+ const float x_pos = x_left + x_delta * x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ }
+ }
+ else {
+ /* Fill x-sides. */
+ const float x_pos = x_left;
+ const float y_pos = y_front + y_delta * y;
+ const float z_pos = z_bottom + z_delta * z;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos, y_pos, z_pos));
+ const float x_pos2 = x_left + x_delta * config.edges_x;
+ copy_v3_v3(verts[vert_index++].co, float3(x_pos2, y_pos, z_pos));
}
}
}
@@ -439,6 +428,35 @@ Mesh *create_cuboid_mesh(const float3 size,
return mesh;
}
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_cube_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Size"))
+ .default_value(float3(1))
+ .min(0.0f)
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Side length along each axis"));
+ b.add_input<decl::Int>(N_("Vertices X"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the X side of the shape"));
+ b.add_input<decl::Int>(N_("Vertices Y"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the Y side of the shape"));
+ b.add_input<decl::Int>(N_("Vertices Z"))
+ .default_value(2)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices for the Z side of the shape"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
static Mesh *create_cube_mesh(const float3 size,
const int verts_x,
const int verts_y,
@@ -484,7 +502,7 @@ static Mesh *create_cube_mesh(const float3 size,
return create_cuboid_mesh(size, verts_x, verts_y, verts_z);
}
-static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const float3 size = params.extract_input<float3>("Size");
const int verts_x = params.extract_input<int>("Vertices X");
@@ -492,7 +510,7 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
const int verts_z = params.extract_input<int>("Vertices Z");
if (verts_x < 1 || verts_y < 1 || verts_z < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 1"));
- params.set_output("Mesh", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -501,14 +519,16 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cube_cc
void register_node_type_geo_mesh_primitive_cube()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cube_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cube_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cube_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
index a2ac46190b3..b8d2ed3be92 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -25,9 +25,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc {
-static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshCylinder)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Vertices"))
.default_value(32)
@@ -60,16 +62,14 @@ static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Bottom")).field_source();
}
-static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
-static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN(
sizeof(NodeGeometryMeshCylinder), __func__);
@@ -79,53 +79,45 @@ static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNod
node->storage = node_storage;
}
-static void geo_node_mesh_primitive_cylinder_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first;
bNodeSocket *rings_socket = vertices_socket->next;
bNodeSocket *fill_subdiv_socket = rings_socket->next;
- const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage;
- const GeometryNodeMeshCircleFillType fill_type =
- static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type);
- const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ const NodeGeometryMeshCylinder &storage = node_storage(*node);
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
+ const bool has_fill = fill != GEO_NODE_MESH_CIRCLE_FILL_NONE;
nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill);
}
-static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const bNode &node = params.node();
- const NodeGeometryMeshCylinder &storage = *(const NodeGeometryMeshCylinder *)node.storage;
-
- const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
- storage.fill_type;
-
- auto return_default = [&]() {
- params.set_output("Top", fn::make_constant_field<bool>(false));
- params.set_output("Bottom", fn::make_constant_field<bool>(false));
- params.set_output("Side", fn::make_constant_field<bool>(false));
- params.set_output("Mesh", GeometrySet());
- };
+ const NodeGeometryMeshCylinder &storage = node_storage(params.node());
+ const GeometryNodeMeshCircleFillType fill = (GeometryNodeMeshCircleFillType)storage.fill_type;
const float radius = params.extract_input<float>("Radius");
const float depth = params.extract_input<float>("Depth");
const int circle_segments = params.extract_input<int>("Vertices");
if (circle_segments < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
const int side_segments = params.extract_input<int>("Side Segments");
if (side_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
- const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE;
+ const bool no_fill = fill == GEO_NODE_MESH_CIRCLE_FILL_NONE;
const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments");
if (fill_segments < 1) {
params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
ConeAttributeOutputs attribute_outputs;
@@ -146,7 +138,7 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
circle_segments,
side_segments,
fill_segments,
- fill_type,
+ fill,
attribute_outputs);
if (attribute_outputs.top_id) {
@@ -169,18 +161,20 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc
void register_node_type_geo_mesh_primitive_cylinder()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_init);
- node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_cylinder_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cylinder_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cylinder_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 73c679e18f8..77634a03af6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -27,31 +27,6 @@
namespace blender::nodes {
-static void geo_node_mesh_primitive_grid_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Float>(N_("Size X"))
- .default_value(1.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Side length of the plane in the X direction"));
- b.add_input<decl::Float>(N_("Size Y"))
- .default_value(1.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE)
- .description(N_("Side length of the plane in the Y direction"));
- b.add_input<decl::Int>(N_("Vertices X"))
- .default_value(3)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices in the X direction"));
- b.add_input<decl::Int>(N_("Vertices Y"))
- .default_value(3)
- .min(2)
- .max(1000)
- .description(N_("Number of vertices in the Y direction"));
- b.add_output<decl::Geometry>(N_("Mesh"));
-}
-
static void calculate_uvs(
Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y)
{
@@ -169,14 +144,43 @@ Mesh *create_grid_mesh(const int verts_x,
return mesh;
}
-static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params)
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_mesh_primitive_grid_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Size X"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Side length of the plane in the X direction"));
+ b.add_input<decl::Float>(N_("Size Y"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Side length of the plane in the Y direction"));
+ b.add_input<decl::Int>(N_("Vertices X"))
+ .default_value(3)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices in the X direction"));
+ b.add_input<decl::Int>(N_("Vertices Y"))
+ .default_value(3)
+ .min(2)
+ .max(1000)
+ .description(N_("Number of vertices in the Y direction"));
+ b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
const float size_x = params.extract_input<float>("Size X");
const float size_y = params.extract_input<float>("Size Y");
const int verts_x = params.extract_input<int>("Vertices X");
const int verts_y = params.extract_input<int>("Vertices Y");
if (verts_x < 1 || verts_y < 1) {
- params.set_output("Mesh", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -187,14 +191,16 @@ static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_grid_cc
void register_node_type_geo_mesh_primitive_grid()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_grid_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_grid_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_grid_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index e4bf5e31dbf..5f483a95063 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -24,9 +24,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc {
-static void geo_node_mesh_primitive_ico_sphere_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>(N_("Radius"))
.default_value(1.0f)
@@ -69,7 +69,7 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius)
return mesh;
}
-static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10);
const float radius = params.extract_input<float>("Radius");
@@ -78,15 +78,17 @@ static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc
void register_node_type_geo_mesh_primitive_ico_sphere()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_ico_sphere_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_ico_sphere_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_ico_sphere_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 1a92be1c05d..9a87c040bdf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -23,11 +23,15 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_line_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryMeshLine)
-static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Count"))
.default_value(10)
@@ -51,9 +55,7 @@ static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -63,7 +65,7 @@ static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
}
}
-static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN(
sizeof(NodeGeometryMeshLine), __func__);
@@ -74,16 +76,16 @@ static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = node_storage;
}
-static void geo_node_mesh_primitive_line_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first;
bNodeSocket *resolution_socket = count_socket->next;
bNodeSocket *start_socket = resolution_socket->next;
bNodeSocket *end_and_offset_socket = start_socket->next;
- const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)node->storage;
- const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
- const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
+ const NodeGeometryMeshLine &storage = node_storage(*node);
+ const GeometryNodeMeshLineMode mode = (GeometryNodeMeshLineMode)storage.mode;
+ const GeometryNodeMeshLineCountMode count_mode = (GeometryNodeMeshLineCountMode)
storage.count_mode;
node_sock_label(end_and_offset_socket,
@@ -100,44 +102,48 @@ static void geo_node_mesh_primitive_line_update(bNodeTree *ntree, bNode *node)
count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL);
}
-static void fill_edge_data(MutableSpan<MEdge> edges)
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
- for (const int i : edges.index_range()) {
- edges[i].v1 = i;
- edges[i].v2 = i + 1;
- edges[i].flag |= ME_LOOSEEDGE;
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ return;
}
-}
-
-Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
-{
- if (count < 1) {
- return nullptr;
- }
-
- Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
- MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
-
- short normal[3];
- normal_float_to_short_v3(normal, delta.normalized());
-
- for (const int i : verts.index_range()) {
- copy_v3_v3(verts[i].co, start + delta * i);
- copy_v3_v3_short(verts[i].no, normal);
+ else if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Count"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
+ params.connect_available_socket(node, "Count");
+ });
+ params.add_item(IFACE_("Resolution"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
+ node_storage(node).count_mode = GEO_NODE_MESH_LINE_COUNT_RESOLUTION;
+ params.connect_available_socket(node, "Resolution");
+ });
+ params.add_item(IFACE_("Start Location"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ params.connect_available_socket(node, "Start Location");
+ });
+ params.add_item(IFACE_("Offset"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ params.connect_available_socket(node, "Offset");
+ });
+ /* The last socket is reused in end points mode. */
+ params.add_item(IFACE_("End Location"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeMeshLine");
+ node_storage(node).mode = GEO_NODE_MESH_LINE_MODE_END_POINTS;
+ params.connect_available_socket(node, "Offset");
+ });
}
-
- fill_edge_data(edges);
-
- return mesh;
}
-static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)params.node().storage;
- const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
- const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
+ const NodeGeometryMeshLine &storage = node_storage(params.node());
+ const GeometryNodeMeshLineMode mode = (GeometryNodeMeshLineMode)storage.mode;
+ const GeometryNodeMeshLineCountMode count_mode = (GeometryNodeMeshLineCountMode)
storage.count_mode;
Mesh *mesh = nullptr;
@@ -174,19 +180,59 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
+} // namespace blender::nodes::node_geo_mesh_primitive_line_cc
+
+namespace blender::nodes {
+
+static void fill_edge_data(MutableSpan<MEdge> edges)
+{
+ for (const int i : edges.index_range()) {
+ edges[i].v1 = i;
+ edges[i].v2 = i + 1;
+ edges[i].flag |= ME_LOOSEEDGE;
+ }
+}
+
+Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
+{
+ if (count < 1) {
+ return nullptr;
+ }
+
+ Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
+
+ short normal[3];
+ normal_float_to_short_v3(normal, delta.normalized());
+
+ for (const int i : verts.index_range()) {
+ copy_v3_v3(verts[i].co, start + delta * i);
+ copy_v3_v3_short(verts[i].no, normal);
+ }
+
+ fill_edge_data(edges);
+
+ return mesh;
+}
+
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_line()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_line_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_line_declare;
- node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_line_init);
- node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_line_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_line_exec;
- ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_line_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index 3197a94c27b..ce2e0923a30 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -25,9 +25,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc {
-static void geo_node_mesh_primitive_uv_shpere_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Int>(N_("Segments"))
.default_value(32)
@@ -292,7 +292,7 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
return mesh;
}
-static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
const int segments_num = params.extract_input<int>("Segments");
const int rings_num = params.extract_input<int>("Rings");
@@ -303,7 +303,7 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
if (rings_num < 3) {
params.error_message_add(NodeWarningType::Info, TIP_("Rings must be at least 3"));
}
- params.set_output("Mesh", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
@@ -313,15 +313,17 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc
void register_node_type_geo_mesh_primitive_uv_sphere()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_primitive_uv_sphere_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_primitive_uv_shpere_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_uv_sphere_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index d99c0c851a8..1ec9808044f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -23,9 +23,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_subdivide_cc {
-static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
@@ -72,14 +72,14 @@ static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int lev
BKE_subdiv_free(subdiv);
}
-static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
#ifndef WITH_OPENSUBDIV
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenSubdiv"));
- params.set_output("Mesh", std::move(geometry_set));
+ params.set_default_remaining_outputs();
return;
#endif
@@ -97,14 +97,16 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_subdivide_cc
void register_node_type_geo_mesh_subdivide()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_subdivide_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_subdivide_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_subdivide_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 11865c635b8..90f0af75788 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -18,16 +18,16 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_to_curve_cc {
-static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
@@ -56,14 +56,16 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_to_curve_cc
void register_node_type_geo_mesh_to_curve()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_to_curve_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index a37e3e34777..77314341fec 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -26,9 +26,11 @@
using blender::Array;
-namespace blender::nodes {
+namespace blender::nodes::node_geo_mesh_to_points_cc {
-static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryMeshToPoints)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
@@ -41,12 +43,12 @@ static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Points"));
}
-static void geo_node_mesh_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
-static void geo_node_mesh_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN(
sizeof(NodeGeometryMeshToPoints), __func__);
@@ -81,10 +83,15 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ /* Evaluating directly into the point cloud doesn't work because we are not using the full
+ * "min_array_size" array but compressing the selected elements into the final array with no
+ * gaps. */
+ evaluator.add(position_field);
+ evaluator.add(radius_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
@@ -92,13 +99,6 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
PointCloudComponent &point_component =
geometry_set.get_component_for_write<PointCloudComponent>();
- /* Evaluating directly into the point cloud doesn't work because we are not using the full
- * "min_array_size" array but compressing the selected elements into the final array with no
- * gaps. */
- fn::FieldEvaluator evaluator{field_context, &selection};
- evaluator.add(position_field);
- evaluator.add(radius_field);
- evaluator.evaluate();
copy_attribute_to_points(evaluator.get_evaluated<float3>(0),
selection,
{(float3 *)pointcloud->co, pointcloud->totpoint});
@@ -129,7 +129,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES});
}
-static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
Field<float3> position = params.extract_input<Field<float3>>("Position");
@@ -144,8 +144,7 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
FieldOperation(max_zero_fn, {std::move(radius)}));
Field<float> positive_radius(std::move(max_zero_op), 0);
- const NodeGeometryMeshToPoints &storage =
- *(const NodeGeometryMeshToPoints *)params.node().storage;
+ const NodeGeometryMeshToPoints &storage = node_storage(params.node());
const GeometryNodeMeshToPointsMode mode = (GeometryNodeMeshToPointsMode)storage.mode;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
@@ -172,17 +171,19 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
params.set_output("Points", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_mesh_to_points_cc
void register_node_type_geo_mesh_to_points()
{
+ namespace file_ns = blender::nodes::node_geo_mesh_to_points_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_mesh_to_points_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_points_exec;
- node_type_init(&ntype, blender::nodes::geo_node_mesh_to_points_init);
- ntype.draw_buttons = blender::nodes::geo_node_mesh_to_points_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryMeshToPoints", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index bb8e5f7e29b..38c3b9cbcd9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_object_info_cc {
-static void geo_node_object_info_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryObjectInfo)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Object>(N_("Object")).hide_label();
b.add_input<decl::Bool>(N_("As Instance"))
@@ -35,31 +37,22 @@ static void geo_node_object_info_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_object_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_object_info_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const bNode &bnode = params.node();
- NodeGeometryObjectInfo *node_storage = (NodeGeometryObjectInfo *)bnode.storage;
- const bool transform_space_relative = (node_storage->transform_space ==
+ const NodeGeometryObjectInfo &storage = node_storage(params.node());
+ const bool transform_space_relative = (storage.transform_space ==
GEO_NODE_TRANSFORM_SPACE_RELATIVE);
- auto default_transform = [&]() {
- params.set_output("Location", float3(0));
- params.set_output("Rotation", float3(0));
- params.set_output("Scale", float3(0));
- };
- auto default_geometry = [&]() { params.set_output("Geometry", GeometrySet()); };
-
Object *object = params.get_input<Object *>("Object");
const Object *self_object = params.self_object();
if (object == nullptr) {
- default_transform();
- default_geometry();
+ params.set_default_remaining_outputs();
return;
}
@@ -81,7 +74,7 @@ static void geo_node_object_info_exec(GeoNodeExecParams params)
if (object == self_object) {
params.error_message_add(NodeWarningType::Error,
TIP_("Geometry cannot be retrieved from the modifier object"));
- default_geometry();
+ params.set_default_remaining_outputs();
return;
}
@@ -107,7 +100,7 @@ static void geo_node_object_info_exec(GeoNodeExecParams params)
}
}
-static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN(
sizeof(NodeGeometryObjectInfo), __func__);
@@ -115,18 +108,20 @@ static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_object_info_cc
void register_node_type_geo_object_info()
{
+ namespace file_ns = blender::nodes::node_geo_object_info_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
- node_type_init(&ntype, blender::nodes::geo_node_object_info_node_init);
+ node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(
&ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_object_info_exec;
- ntype.draw_buttons = blender::nodes::geo_node_object_info_layout;
- ntype.declare = blender::nodes::geo_node_object_info_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
index 5a6a3b25a45..5510773eabd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
@@ -21,11 +21,11 @@
#include "node_geometry_util.hh"
-using blender::Array;
+namespace blender::nodes::node_geo_points_to_vertices_cc {
-namespace blender::nodes {
+using blender::Array;
-static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
@@ -92,7 +92,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
}
-static void geo_node_points_to_vertices_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -104,15 +104,17 @@ static void geo_node_points_to_vertices_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_points_to_vertices_cc
void register_node_type_geo_points_to_vertices()
{
+ namespace file_ns = blender::nodes::node_geo_points_to_vertices_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_points_to_vertices_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_points_to_vertices_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index 31c16cb95e0..744cce6d445 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -28,14 +28,27 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_points_to_volume_cc {
-static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryPointsToVolume)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Points"));
b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
- b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Voxel Size"))
+ .default_value(0.3f)
+ .min(0.01f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE;
+ });
+ b.add_input<decl::Float>(N_("Voxel Amount"))
+ .default_value(64.0f)
+ .min(0.0f)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
+ });
b.add_input<decl::Float>(N_("Radius"))
.default_value(0.5f)
.min(0.0f)
@@ -44,16 +57,14 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Volume"));
}
-static void geo_node_points_to_volume_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
sizeof(NodeGeometryPointsToVolume), __func__);
@@ -61,18 +72,18 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node
node->storage = data;
}
-static void geo_node_points_to_volume_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage;
+ const NodeGeometryPointsToVolume &storage = node_storage(*node);
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
nodeSetSocketAvailability(ntree,
voxel_amount_socket,
- data->resolution_mode ==
+ storage.resolution_mode ==
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
nodeSetSocketAvailability(ntree,
voxel_size_socket,
- data->resolution_mode ==
+ storage.resolution_mode ==
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
}
@@ -136,8 +147,7 @@ static float compute_voxel_size(const GeoNodeExecParams &params,
Span<float3> positions,
const float radius)
{
- const NodeGeometryPointsToVolume &storage =
- *(const NodeGeometryPointsToVolume *)params.node().storage;
+ const NodeGeometryPointsToVolume &storage = node_storage(params.node());
if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) {
return params.get_input<float>("Voxel Size");
@@ -236,7 +246,7 @@ static void initialize_volume_component_from_points(GeoNodeExecParams &params,
}
#endif
-static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
@@ -248,14 +258,16 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
- params.set_output("Volume", GeometrySet());
+ params.set_default_remaining_outputs();
#endif
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_points_to_volume_cc
void register_node_type_geo_points_to_volume()
{
+ namespace file_ns = blender::nodes::node_geo_points_to_volume_cc;
+
static bNodeType ntype;
geo_node_type_base(
@@ -265,10 +277,10 @@ void register_node_type_geo_points_to_volume()
node_free_standard_storage,
node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init);
- node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update);
- ntype.declare = blender::nodes::geo_node_points_to_volume_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec;
- ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
index c05476b982b..aa3383e68be 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -27,9 +27,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_proximity_cc {
-static void geo_node_proximity_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryProximity)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Target"))
.only_realized_data()
@@ -39,7 +41,7 @@ static void geo_node_proximity_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Distance")).dependent_field();
}
-static void geo_node_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE);
}
@@ -206,21 +208,17 @@ class ProximityFunction : public fn::MultiFunction {
}
};
-static void geo_node_proximity_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
geometry_set_target.ensure_owns_direct_data();
- auto return_default = [&]() {
- params.set_output("Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Distance", fn::make_constant_field<float>(0.0f));
- };
-
if (!geometry_set_target.has_mesh() && !geometry_set_target.has_pointcloud()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
- const NodeGeometryProximity &storage = *(const NodeGeometryProximity *)params.node().storage;
+ const NodeGeometryProximity &storage = node_storage(params.node());
Field<float3> position_field = params.extract_input<Field<float3>>("Source Position");
auto proximity_fn = std::make_unique<ProximityFunction>(
@@ -233,18 +231,20 @@ static void geo_node_proximity_exec(GeoNodeExecParams params)
params.set_output("Distance", Field<float>(proximity_op, 1));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_proximity_cc
void register_node_type_geo_proximity()
{
+ namespace file_ns = blender::nodes::node_geo_proximity_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0);
- node_type_init(&ntype, blender::nodes::geo_proximity_init);
+ node_type_init(&ntype, file_ns::geo_proximity_init);
node_type_storage(
&ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_proximity_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_proximity_exec;
- ntype.draw_buttons = blender::nodes::geo_node_proximity_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index d422bf5a00a..d255fe482f6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -23,13 +23,17 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
+namespace blender::nodes::node_geo_raycast_cc {
+
using namespace blender::bke::mesh_surface_sample;
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeGeometryRaycast)
-static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Target Geometry"))
.only_realized_data()
@@ -63,13 +67,13 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6});
}
-static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
}
-static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
__func__);
@@ -78,10 +82,10 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_raycast_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)node->storage;
- const CustomDataType data_type = static_cast<CustomDataType>(data.data_type);
+ const NodeGeometryRaycast &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
bNodeSocket *socket_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *socket_float = socket_vector->next;
@@ -108,6 +112,25 @@ static void geo_node_raycast_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(3));
+ search_link_ops_for_declarations(params, declaration.outputs().take_front(4));
+
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeRaycast");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+}
+
static eAttributeMapMode get_map_mode(GeometryNodeRaycastMapMode map_mode)
{
switch (map_mode) {
@@ -205,10 +228,10 @@ class RaycastFunction : public fn::MultiFunction {
std::unique_ptr<FieldEvaluator> target_evaluator_;
const GVArray *target_data_ = nullptr;
- /* Always evaluate the target domain data on the point domain. Eventually this could be
- * exposed as an option or determined automatically from the field inputs in order to avoid
- * losing information if the target field is on a different domain. */
- const AttributeDomain domain_ = ATTR_DOMAIN_POINT;
+ /* Always evaluate the target domain data on the face corner domain because it contains the most
+ * information. Eventually this could be exposed as an option or determined automatically from
+ * the field inputs for better performance. */
+ const AttributeDomain domain_ = ATTR_DOMAIN_CORNER;
fn::MFSignature signature_;
@@ -375,35 +398,27 @@ static void output_attribute_field(GeoNodeExecParams &params, GField field)
}
}
-static void geo_node_raycast_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet target = params.extract_input<GeometrySet>("Target Geometry");
- const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)params.node().storage;
- const GeometryNodeRaycastMapMode mapping = static_cast<GeometryNodeRaycastMapMode>(data.mapping);
- const CustomDataType data_type = static_cast<CustomDataType>(data.data_type);
-
- auto return_default = [&]() {
- params.set_output("Is Hit", fn::make_constant_field<bool>(false));
- params.set_output("Hit Position", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Hit Normal", fn::make_constant_field<float3>({0.0f, 0.0f, 0.0f}));
- params.set_output("Hit Distance", fn::make_constant_field<float>(0.0f));
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- output_attribute_field(params, fn::make_constant_field<T>(T()));
- });
- };
+ const NodeGeometryRaycast &storage = node_storage(params.node());
+ const GeometryNodeRaycastMapMode mapping = (GeometryNodeRaycastMapMode)storage.mapping;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
if (target.is_empty()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
if (!target.has_mesh()) {
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
if (target.get_mesh_for_read()->totpoly == 0) {
params.error_message_add(NodeWarningType::Error, TIP_("The target mesh must have faces"));
- return return_default();
+ params.set_default_remaining_outputs();
+ return;
}
GField field = get_input_attribute_field(params, data_type);
@@ -426,20 +441,23 @@ static void geo_node_raycast_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_raycast_cc
void register_node_type_geo_raycast()
{
+ namespace file_ns = blender::nodes::node_geo_raycast_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, blender::nodes::geo_node_raycast_init);
- node_type_update(&ntype, blender::nodes::geo_node_raycast_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(
&ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_raycast_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec;
- ntype.draw_buttons = blender::nodes::geo_node_raycast_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
index 6c51c1f738f..fad35389823 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
@@ -16,33 +16,48 @@
#include "node_geometry_util.hh"
+#include "GEO_realize_instances.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_realize_instances_cc {
-static void geo_node_realize_instances_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Geometry"));
}
-static void geo_node_realize_instances_exec(GeoNodeExecParams params)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "legacy_behavior", 0, nullptr, ICON_NONE);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
+ const bool legacy_behavior = params.node().custom1 & GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR;
+
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
+ geometry::RealizeInstancesOptions options;
+ options.keep_original_ids = legacy_behavior;
+ options.realize_instance_attributes = !legacy_behavior;
+ geometry_set = geometry::realize_instances(geometry_set, options);
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_realize_instances_cc
void register_node_type_geo_realize_instances()
{
+ namespace file_ns = blender::nodes::node_geo_realize_instances_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_realize_instances_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_realize_instances_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons_ex = file_ns::node_layout;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
index c53eaa2ded9..335484c62b0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_rotate_instances_cc {
-static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -35,19 +35,17 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
const int domain_size = instances_component.instances_amount();
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(params.extract_input<Field<bool>>("Selection"));
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Rotation"));
+ evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
- fn::FieldEvaluator transforms_evaluator{field_context, &selection};
- transforms_evaluator.add(params.extract_input<Field<float3>>("Rotation"));
- transforms_evaluator.add(params.extract_input<Field<float3>>("Pivot Point"));
- transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space"));
- transforms_evaluator.evaluate();
- const VArray<float3> &rotations = transforms_evaluator.get_evaluated<float3>(0);
- const VArray<float3> &pivots = transforms_evaluator.get_evaluated<float3>(1);
- const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(2);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &rotations = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &pivots = evaluator.get_evaluated<float3>(1);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(2);
MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
@@ -96,7 +94,7 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
});
}
-static void geo_node_rotate_instances_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
@@ -106,15 +104,17 @@ static void geo_node_rotate_instances_exec(GeoNodeExecParams params)
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_rotate_instances_cc
void register_node_type_geo_rotate_instances()
{
+ namespace file_ns = blender::nodes::node_geo_rotate_instances_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_rotate_instances_exec;
- ntype.declare = blender::nodes::geo_node_rotate_instances_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
index fa2501515a9..1779ac8bff7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_scale_instances_cc {
-static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -37,19 +37,17 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
{
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
- fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()};
- selection_evaluator.add(params.extract_input<Field<bool>>("Selection"));
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Scale"));
+ evaluator.add(params.extract_input<Field<float3>>("Center"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
- fn::FieldEvaluator transforms_evaluator{field_context, &selection};
- transforms_evaluator.add(params.extract_input<Field<float3>>("Scale"));
- transforms_evaluator.add(params.extract_input<Field<float3>>("Center"));
- transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space"));
- transforms_evaluator.evaluate();
- const VArray<float3> &scales = transforms_evaluator.get_evaluated<float3>(0);
- const VArray<float3> &pivots = transforms_evaluator.get_evaluated<float3>(1);
- const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(2);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &scales = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &pivots = evaluator.get_evaluated<float3>(1);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(2);
MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
@@ -75,7 +73,7 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
});
}
-static void geo_node_scale_instances_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
@@ -85,14 +83,16 @@ static void geo_node_scale_instances_exec(GeoNodeExecParams params)
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_scale_instances_cc
void register_node_type_geo_scale_instances()
{
+ namespace file_ns = blender::nodes::node_geo_scale_instances_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_scale_instances_exec;
- ntype.declare = blender::nodes::geo_node_scale_instances_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
index a16fb712b13..e4adfe6587d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_separate_components_cc {
-static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Mesh"));
@@ -28,7 +28,7 @@ static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Instances"));
}
-static void geo_node_separate_components_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -61,15 +61,17 @@ static void geo_node_separate_components_exec(GeoNodeExecParams params)
params.set_output("Instances", instances);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_separate_components_cc
void register_node_type_geo_separate_components()
{
+ namespace file_ns = blender::nodes::node_geo_separate_components_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_join_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_separate_components_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index 28e214c0ccc..7f1cc1be421 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -19,9 +19,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_separate_geometry_cc {
-static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometrySeparateGeometry)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Bool>(N_("Selection"))
@@ -35,14 +37,12 @@ static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b)
.description(N_("The parts of the geometry not in the selection"));
}
-static void geo_node_separate_geometry_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
-static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN(
sizeof(NodeGeometrySeparateGeometry), __func__);
@@ -51,14 +51,13 @@ static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node
node->storage = data;
}
-static void geo_node_separate_geometry_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- const bNode &node = params.node();
- const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node.storage;
+ const NodeGeometrySeparateGeometry &storage = node_storage(params.node());
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
bool all_is_error = false;
@@ -95,10 +94,12 @@ static void geo_node_separate_geometry_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_separate_geometry_cc
void register_node_type_geo_separate_geometry()
{
+ namespace file_ns = blender::nodes::node_geo_separate_geometry_cc;
+
static bNodeType ntype;
geo_node_type_base(
@@ -109,10 +110,10 @@ void register_node_type_geo_separate_geometry()
node_free_standard_storage,
node_copy_standard_storage);
- node_type_init(&ntype, blender::nodes::geo_node_separate_geometry_init);
+ node_type_init(&ntype, file_ns::node_init);
- ntype.declare = blender::nodes::geo_node_separate_geometry_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_separate_geometry_exec;
- ntype.draw_buttons = blender::nodes::geo_node_separate_geometry_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index 30b445da58c..f98b4116526 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -21,9 +21,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_curve_handles_cc {
-static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometrySetCurveHandlePositions)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -32,14 +34,12 @@ static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
}
-static void geo_node_set_curve_handles_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_set_curve_handles_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN(
sizeof(NodeGeometrySetCurveHandlePositions), __func__);
@@ -60,10 +60,12 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add(position_field);
+ evaluator.add(offset_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
CurveComponent *curve_component = static_cast<CurveComponent *>(&component);
CurveEval *curve = curve_component->get_for_write();
@@ -77,7 +79,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
if (spline->type() == Spline::Type::Bezier) {
BezierSpline &bezier = static_cast<BezierSpline &>(*spline);
for (int i : bezier.positions().index_range()) {
- if (selection[current_mask] == current_point) {
+ if (current_mask < selection.size() && selection[current_mask] == current_point) {
if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
if (bezier.handle_types_left()[i] == BezierSpline::HandleType::Vector) {
bezier.ensure_auto_handles();
@@ -105,7 +107,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
}
else {
for (int UNUSED(i) : spline->positions().index_range()) {
- if (selection[current_mask] == current_point) {
+ if (current_mask < selection.size() && selection[current_mask] == current_point) {
current_mask++;
}
current_point++;
@@ -113,13 +115,8 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
}
}
- fn::FieldEvaluator position_evaluator{field_context, &selection};
- position_evaluator.add(position_field);
- position_evaluator.add(offset_field);
- position_evaluator.evaluate();
-
- const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0);
- const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1);
+ const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1);
OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
side, ATTR_DOMAIN_POINT, {0, 0, 0});
@@ -132,11 +129,10 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
positions.save();
}
-static void geo_node_set_curve_handles_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeGeometrySetCurveHandlePositions *node_storage =
- (NodeGeometrySetCurveHandlePositions *)params.node().storage;
- const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)node_storage->mode;
+ const NodeGeometrySetCurveHandlePositions &storage = node_storage(params.node());
+ const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -162,22 +158,24 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_curve_handles_cc
void register_node_type_geo_set_curve_handles()
{
+ namespace file_ns = blender::nodes::node_geo_set_curve_handles_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_handles_exec;
- ntype.declare = blender::nodes::geo_node_set_curve_handles_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
ntype.minwidth = 100.0f;
- node_type_init(&ntype, blender::nodes::geo_node_set_curve_handles_init);
+ node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometrySetCurveHandlePositions",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_set_curve_handles_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
index e47ce7dea30..7d99f42c487 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_curve_radius_cc {
-static void geo_node_set_curve_radius_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -40,20 +40,18 @@ static void set_radius_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
"radius", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator radii_evaluator{field_context, &selection};
- radii_evaluator.add_with_destination(radius_field, radii.varray());
- radii_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.evaluate();
+
radii.save();
}
-static void geo_node_set_curve_radius_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -69,15 +67,17 @@ static void geo_node_set_curve_radius_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_curve_radius_cc
void register_node_type_geo_set_curve_radius()
{
+ namespace file_ns = blender::nodes::node_geo_set_curve_radius_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_radius_exec;
- ntype.declare = blender::nodes::geo_node_set_curve_radius_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
index a861c35f738..447310e1ad7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_curve_tilt_cc {
-static void geo_node_set_curve_tilt_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,20 +36,18 @@ static void set_tilt_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<float> tilts = component.attribute_try_get_for_output_only<float>(
"tilt", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator tilt_evaluator{field_context, &selection};
- tilt_evaluator.add_with_destination(tilt_field, tilts.varray());
- tilt_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(tilt_field, tilts.varray());
+ evaluator.evaluate();
+
tilts.save();
}
-static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -65,14 +63,16 @@ static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params)
params.set_output("Curve", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_curve_tilt_cc
void register_node_type_geo_set_curve_tilt()
{
+ namespace file_ns = blender::nodes::node_geo_set_curve_tilt_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_tilt_exec;
- ntype.declare = blender::nodes::geo_node_set_curve_tilt_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
index 77d8e786501..db4083acd4b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_id_cc {
-static void geo_node_set_id_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,26 +36,24 @@ static void set_id_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
/* Since adding the ID attribute can change the result of the field evaluation (the random value
* node uses the index if the ID is unavailable), make sure that it isn't added before evaluating
* the field. However, as an optimization, use a faster code path when it already exists. */
- fn::FieldEvaluator id_evaluator{field_context, &selection};
if (component.attribute_exists("id")) {
OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
"id", ATTR_DOMAIN_POINT);
- id_evaluator.add_with_destination(id_field, id_attribute.varray());
- id_evaluator.evaluate();
+ evaluator.add_with_destination(id_field, id_attribute.varray());
+ evaluator.evaluate();
id_attribute.save();
}
else {
- id_evaluator.add(id_field);
- id_evaluator.evaluate();
- const VArray<int> &result_ids = id_evaluator.get_evaluated<int>(0);
+ evaluator.add(id_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<int> &result_ids = evaluator.get_evaluated<int>(0);
OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
"id", ATTR_DOMAIN_POINT);
result_ids.materialize(selection, id_attribute.as_span());
@@ -63,7 +61,7 @@ static void set_id_in_component(GeometryComponent &component,
}
}
-static void geo_node_set_id_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -81,14 +79,16 @@ static void geo_node_set_id_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_id_cc
void register_node_type_geo_set_id()
{
+ namespace file_ns = blender::nodes::node_geo_set_id_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_id_exec;
- ntype.declare = blender::nodes::geo_node_set_id_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
index 3817de02a38..30510c3570c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
@@ -21,16 +21,18 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
#include "DNA_volume_types.h"
#include "BKE_material.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_material_cc {
-static void geo_node_set_material_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"))
- .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME});
+ .supported_type(
+ {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_POINT_CLOUD});
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_input<decl::Material>(N_("Material")).hide_label();
b.add_output<decl::Geometry>(N_("Geometry"));
@@ -59,58 +61,68 @@ static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Mate
}
}
-static void geo_node_set_material_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Material *material = params.extract_input<Material *>("Material");
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ /* Only add the warnings once, even if there are many unique instances. */
+ bool point_selection_warning = false;
bool volume_selection_warning = false;
+
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has<MeshComponent>()) {
+ if (geometry_set.has_mesh()) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh != nullptr) {
- GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ Mesh &mesh = *mesh_component.get_for_write();
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
- fn::FieldEvaluator selection_evaluator{field_context, mesh->totpoly};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator selection_evaluator{field_context, mesh.totpoly};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
- assign_material_to_faces(*mesh, selection, material);
- }
+ assign_material_to_faces(mesh, selection, material);
}
- if (geometry_set.has_volume()) {
- Volume &volume = *geometry_set.get_volume_for_write();
-
+ if (Volume *volume = geometry_set.get_volume_for_write()) {
+ BKE_id_material_eval_assign(&volume->id, 1, material);
if (selection_field.node().depends_on_input()) {
volume_selection_warning = true;
}
-
- BKE_id_material_eval_assign(&volume.id, 1, material);
+ }
+ if (PointCloud *pointcloud = geometry_set.get_pointcloud_for_write()) {
+ BKE_id_material_eval_assign(&pointcloud->id, 1, material);
+ if (selection_field.node().depends_on_input()) {
+ point_selection_warning = true;
+ }
}
});
if (volume_selection_warning) {
- /* Only add the warning once, even if there are many unique volume instances. */
params.error_message_add(
NodeWarningType::Info,
TIP_("Volumes only support a single material; selection input can not be a field"));
}
+ if (point_selection_warning) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("Point clouds only support a single material; selection input can not be a field"));
+ }
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_material_cc
void register_node_type_geo_set_material()
{
+ namespace file_ns = blender::nodes::node_geo_set_material_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_set_material_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_set_material_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
index a8bb1bd8644..4451907132a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_material_index_cc {
-static void geo_node_set_material_index_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,20 +36,17 @@ static void set_material_index_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<int> indices = component.attribute_try_get_for_output_only<int>(
"material_index", ATTR_DOMAIN_FACE);
- fn::FieldEvaluator material_evaluator{field_context, &selection};
- material_evaluator.add_with_destination(index_field, indices.varray());
- material_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(index_field, indices.varray());
+ evaluator.evaluate();
indices.save();
}
-static void geo_node_set_material_index_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -64,15 +61,17 @@ static void geo_node_set_material_index_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_material_index_cc
void register_node_type_geo_set_material_index()
{
+ namespace file_ns = blender::nodes::node_geo_set_material_index_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_material_index_exec;
- ntype.declare = blender::nodes::geo_node_set_material_index_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
index 9ff299542b4..98adff7c939 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_point_radius_cc {
-static void geo_node_set_point_radius_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -40,20 +40,18 @@ static void set_radius_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
"radius", ATTR_DOMAIN_POINT);
- fn::FieldEvaluator radii_evaluator{field_context, &selection};
- radii_evaluator.add_with_destination(radius_field, radii.varray());
- radii_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.evaluate();
+
radii.save();
}
-static void geo_node_set_point_radius_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -70,15 +68,17 @@ static void geo_node_set_point_radius_exec(GeoNodeExecParams params)
params.set_output("Points", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_point_radius_cc
void register_node_type_geo_set_point_radius()
{
+ namespace file_ns = blender::nodes::node_geo_set_point_radius_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_point_radius_exec;
- ntype.declare = blender::nodes::geo_node_set_point_radius_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 5fe9fb1b3d4..93073c2436d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -16,11 +16,16 @@
#include "DEG_depsgraph_query.h"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_position_cc {
-static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -29,6 +34,77 @@ static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Geometry"));
}
+static void set_computed_position_and_offset(GeometryComponent &component,
+ const VArray<float3> &in_positions,
+ const VArray<float3> &in_offsets,
+ const AttributeDomain domain,
+ const IndexMask selection)
+{
+
+ OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
+ "position", domain, {0, 0, 0});
+
+ const int grain_size = 10000;
+
+ switch (component.type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ Mesh *mesh = static_cast<MeshComponent &>(component).get_for_write();
+ MutableSpan<MVert> mverts{mesh->mvert, mesh->totvert};
+ if (in_positions.is_same(positions.varray())) {
+ devirtualize_varray(in_offsets, [&](const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const float3 offset = in_offsets[i];
+ add_v3_v3(mverts[i].co, offset);
+ }
+ });
+ });
+ }
+ else {
+ devirtualize_varray2(
+ in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const float3 new_position = in_positions[i] + in_offsets[i];
+ copy_v3_v3(mverts[i].co, new_position);
+ }
+ });
+ });
+ }
+ break;
+ }
+ default: {
+ MutableSpan<float3> out_positions_span = positions.as_span();
+ if (in_positions.is_same(positions.varray())) {
+ devirtualize_varray(in_offsets, [&](const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ out_positions_span[i] += in_offsets[i];
+ }
+ });
+ });
+ }
+ else {
+ devirtualize_varray2(
+ in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
+ threading::parallel_for(
+ selection.index_range(), grain_size, [&](const IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ out_positions_span[i] = in_positions[i] + in_offsets[i];
+ }
+ });
+ });
+ }
+ break;
+ }
+ }
+
+ positions.save();
+}
+
static void set_position_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<float3> &position_field,
@@ -43,33 +119,19 @@ static void set_position_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
- fn::FieldEvaluator position_evaluator{field_context, &selection};
- position_evaluator.add(position_field);
- position_evaluator.add(offset_field);
- position_evaluator.evaluate();
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add(position_field);
+ evaluator.add(offset_field);
+ evaluator.evaluate();
- /* TODO: We could have different code paths depending on whether the offset input is a single
- * value or not */
-
- const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0);
- const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1);
-
- OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
- "position", domain, {0, 0, 0});
- MutableSpan<float3> position_mutable = positions.as_span();
-
- for (int i : selection) {
- position_mutable[i] = positions_input[i] + offsets_input[i];
- }
- positions.save();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &positions_input = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> &offsets_input = evaluator.get_evaluated<float3>(1);
+ set_computed_position_and_offset(component, positions_input, offsets_input, domain, selection);
}
-static void geo_node_set_position_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -89,14 +151,16 @@ static void geo_node_set_position_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_position_cc
void register_node_type_geo_set_position()
{
+ namespace file_ns = blender::nodes::node_geo_set_position_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_position_exec;
- ntype.declare = blender::nodes::geo_node_set_position_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
index 06e25c2ed55..879a868cc0e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_shade_smooth_cc {
-static void geo_node_set_shade_smooth_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,20 +36,18 @@ static void set_smooth_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<bool> shades = component.attribute_try_get_for_output_only<bool>(
"shade_smooth", ATTR_DOMAIN_FACE);
- fn::FieldEvaluator shade_evaluator{field_context, &selection};
- shade_evaluator.add_with_destination(shade_field, shades.varray());
- shade_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(shade_field, shades.varray());
+ evaluator.evaluate();
+
shades.save();
}
-static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -64,15 +62,17 @@ static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_shade_smooth_cc
void register_node_type_geo_set_shade_smooth()
{
+ namespace file_ns = blender::nodes::node_geo_set_shade_smooth_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_shade_smooth_exec;
- ntype.declare = blender::nodes::geo_node_set_shade_smooth_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
index ec751ae1d2b..694491d7e6d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -16,9 +16,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_spline_cyclic_cc {
-static void geo_node_set_spline_cyclic_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -36,20 +36,18 @@ static void set_cyclic_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<bool> cyclics = component.attribute_try_get_for_output_only<bool>(
"cyclic", ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator cyclic_evaluator{field_context, &selection};
- cyclic_evaluator.add_with_destination(cyclic_field, cyclics.varray());
- cyclic_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(cyclic_field, cyclics.varray());
+ evaluator.evaluate();
+
cyclics.save();
}
-static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -65,15 +63,17 @@ static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_spline_cyclic_cc
void register_node_type_geo_set_spline_cyclic()
{
+ namespace file_ns = blender::nodes::node_geo_set_spline_cyclic_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_cyclic_exec;
- ntype.declare = blender::nodes::geo_node_set_spline_cyclic_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
index ccf419975ca..0f93db5e6f6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -18,13 +18,13 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_set_spline_resolution_cc {
-static void geo_node_set_spline_resolution_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
- b.add_input<decl::Int>(N_("Resolution")).default_value(12).supports_field();
+ b.add_input<decl::Int>(N_("Resolution")).min(1).default_value(12).supports_field();
b.add_output<decl::Geometry>(N_("Geometry"));
}
@@ -38,20 +38,18 @@ static void set_resolution_in_component(GeometryComponent &component,
return;
}
- fn::FieldEvaluator selection_evaluator{field_context, domain_size};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
-
OutputAttribute_Typed<int> resolutions = component.attribute_try_get_for_output_only<int>(
"resolution", ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator resolution_evaluator{field_context, &selection};
- resolution_evaluator.add_with_destination(resolution_field, resolutions.varray());
- resolution_evaluator.evaluate();
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.set_selection(selection_field);
+ evaluator.add_with_destination(resolution_field, resolutions.varray());
+ evaluator.evaluate();
+
resolutions.save();
}
-static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -81,15 +79,17 @@ static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_set_spline_resolution_cc
void register_node_type_geo_set_spline_resolution()
{
+ namespace file_ns = blender::nodes::node_geo_set_spline_resolution_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_resolution_exec;
- ntype.declare = blender::nodes::geo_node_set_spline_resolution_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
index 98d0aca084a..5308b43afb2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
@@ -16,16 +16,16 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_string_join_cc {
-static void geo_node_string_join_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>(N_("Delimiter"));
b.add_input<decl::String>(N_("Strings")).multi_input().hide_value();
b.add_output<decl::String>(N_("String"));
};
-static void geo_node_string_join_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
Vector<std::string> strings = params.extract_multi_input<std::string>("Strings");
const std::string delim = params.extract_input<std::string>("Delimiter");
@@ -40,14 +40,16 @@ static void geo_node_string_join_exec(GeoNodeExecParams params)
params.set_output("String", std::move(output));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_string_join_cc
void register_node_type_geo_string_join()
{
+ namespace file_ns = blender::nodes::node_geo_string_join_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_string_join_exec;
- ntype.declare = blender::nodes::geo_node_string_join_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 9e3ff10a3c5..33614eb3c46 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -30,9 +30,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_string_to_curves_cc {
-static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryStringToCurves)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>(N_("String"));
b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE);
@@ -55,12 +57,17 @@ static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Text Box Height"))
.default_value(0.0f)
.min(0.0f)
- .subtype(PROP_DISTANCE);
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_SCALE_TO_FIT;
+ });
b.add_output<decl::Geometry>(N_("Curves"));
- b.add_output<decl::String>(N_("Remainder"));
+ b.add_output<decl::String>(N_("Remainder")).make_available([](bNode &node) {
+ node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE;
+ });
}
-static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
+static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -79,7 +86,7 @@ static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *
uiItemR(layout, ptr, "align_y", 0, "", ICON_NONE);
}
-static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN(
sizeof(NodeGeometryStringToCurves), __func__);
@@ -91,11 +98,11 @@ static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node
node->id = (ID *)BKE_vfont_builtin_get();
}
-static void geo_node_string_to_curves_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryStringToCurves *storage = (const NodeGeometryStringToCurves *)node->storage;
+ const NodeGeometryStringToCurves &storage = node_storage(*node);
const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
- storage->overflow;
+ storage.overflow;
bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next;
nodeSetSocketAvailability(
ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE);
@@ -131,8 +138,7 @@ static TextLayout get_text_layout(GeoNodeExecParams &params)
return {};
}
- const NodeGeometryStringToCurves &storage =
- *(const NodeGeometryStringToCurves *)params.node().storage;
+ const NodeGeometryStringToCurves &storage = node_storage(params.node());
const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode)
storage.overflow;
const GeometryNodeStringToCurvesAlignXMode align_x = (GeometryNodeStringToCurvesAlignXMode)
@@ -265,7 +271,7 @@ static void add_instances_from_handles(InstancesComponent &instances,
});
}
-static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
TextLayout layout = get_text_layout(params);
@@ -297,23 +303,25 @@ static void geo_node_string_to_curves_exec(GeoNodeExecParams params)
params.set_output("Curves", std::move(geometry_set_out));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_string_to_curves_cc
void register_node_type_geo_string_to_curves()
{
+ namespace file_ns = blender::nodes::node_geo_string_to_curves_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_string_to_curves_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_string_to_curves_exec;
- node_type_init(&ntype, blender::nodes::geo_node_string_to_curves_init);
- node_type_update(&ntype, blender::nodes::geo_node_string_to_curves_update);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_size(&ntype, 190, 120, 700);
node_type_storage(&ntype,
"NodeGeometryStringToCurves",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.draw_buttons = blender::nodes::geo_node_string_to_curves_layout;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 2b3430a5ed0..74e0560b32f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -27,9 +27,11 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_subdivision_surface_cc {
-static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometrySubdivisionSurface)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
@@ -42,15 +44,13 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_subdivision_surface_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE);
uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE);
}
-static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
sizeof(NodeGeometrySubdivisionSurface), __func__);
@@ -59,7 +59,7 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n
node->storage = data;
}
-static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
#ifndef WITH_OPENSUBDIV
@@ -68,8 +68,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
#else
Field<float> crease_field = params.extract_input<Field<float>>("Crease");
- const NodeGeometrySubdivisionSurface &storage =
- *(const NodeGeometrySubdivisionSurface *)params.node().storage;
+ const NodeGeometrySubdivisionSurface &storage = node_storage(params.node());
const int uv_smooth = storage.uv_smooth;
const int boundary_smooth = storage.boundary_smooth;
const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 30);
@@ -145,18 +144,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_subdivision_surface_cc
void register_node_type_geo_subdivision_surface()
{
+ namespace file_ns = blender::nodes::node_geo_subdivision_surface_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_subdivision_surface_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec;
- ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout;
- node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_storage(&ntype,
"NodeGeometrySubdivisionSurface",
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index 8d6f53ae375..d22522fe087 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -24,11 +24,15 @@
#include "BKE_material.h"
+#include "NOD_socket_search_link.hh"
+
#include "FN_multi_function_signature.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_switch_cc {
+
+NODE_STORAGE_FUNCS(NodeSwitch)
-static void geo_node_switch_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Bool>(N_("Switch")).default_value(false).supports_field();
b.add_input<decl::Bool>(N_("Switch"), "Switch_001").default_value(false);
@@ -83,32 +87,27 @@ static void geo_node_switch_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Image>(N_("Output"), "Output_011");
}
-static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE);
}
-static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
data->input_type = SOCK_GEOMETRY;
node->storage = data;
}
-static void geo_node_switch_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeSwitch *node_storage = (NodeSwitch *)node->storage;
+ const NodeSwitch &storage = node_storage(*node);
int index = 0;
bNodeSocket *field_switch = (bNodeSocket *)node->inputs.first;
bNodeSocket *non_field_switch = (bNodeSocket *)field_switch->next;
- const bool fields_type = ELEM((eNodeSocketDatatype)node_storage->input_type,
- SOCK_FLOAT,
- SOCK_INT,
- SOCK_BOOLEAN,
- SOCK_VECTOR,
- SOCK_RGBA,
- SOCK_STRING);
+ const bool fields_type = ELEM(
+ storage.input_type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA, SOCK_STRING);
nodeSetSocketAvailability(ntree, field_switch, fields_type);
nodeSetSocketAvailability(ntree, non_field_switch, !fields_type);
@@ -117,13 +116,40 @@ static void geo_node_switch_update(bNodeTree *ntree, bNode *node)
if (index <= 1) {
continue;
}
- nodeSetSocketAvailability(
- ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type);
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- nodeSetSocketAvailability(
- ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ nodeSetSocketAvailability(ntree, socket, socket->type == storage.input_type);
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(IFACE_("Output"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "Output");
+ });
+ }
+ else {
+ if (params.other_socket().type == SOCK_BOOLEAN) {
+ params.add_item(IFACE_("Switch"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ params.connect_available_socket(node, "Start");
+ });
+ }
+ params.add_item(IFACE_("False"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "False");
+ });
+ params.add_item(IFACE_("True"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeSwitch");
+ node_storage(node).input_type = params.socket.type;
+ params.update_and_connect_available_socket(node, "True");
+ });
}
}
@@ -232,9 +258,9 @@ template<typename T> void switch_no_fields(GeoNodeExecParams &params, const Stri
}
}
-static void geo_node_switch_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
- const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage;
+ const NodeSwitch &storage = node_storage(params.node());
const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type);
switch (data_type) {
@@ -293,19 +319,22 @@ static void geo_node_switch_exec(GeoNodeExecParams params)
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_switch_cc
void register_node_type_geo_switch()
{
+ namespace file_ns = blender::nodes::node_geo_switch_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::geo_node_switch_declare;
- node_type_init(&ntype, blender::nodes::geo_node_switch_init);
- node_type_update(&ntype, blender::nodes::geo_node_switch_update);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage);
- ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.geometry_node_execute_supports_laziness = true;
- ntype.draw_buttons = blender::nodes::geo_node_switch_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
index 3b30806d8ae..1f099dcd04d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -31,19 +31,24 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
+namespace blender::nodes::node_geo_transfer_attribute_cc {
+
using namespace blender::bke::mesh_surface_sample;
using blender::fn::GArray;
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeGeometryTransferAttribute)
-static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Target"))
- .only_realized_data()
- .supported_type(
- {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE});
+ .supported_type({GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES});
b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field();
b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
@@ -51,8 +56,14 @@ static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Attribute"), "Attribute_003").hide_value().supports_field();
b.add_input<decl::Int>(N_("Attribute"), "Attribute_004").hide_value().supports_field();
- b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
- b.add_input<decl::Int>(N_("Index")).implicit_field();
+ b.add_input<decl::Vector>(N_("Source Position"))
+ .implicit_field()
+ .make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
+ });
+ b.add_input<decl::Int>(N_("Index")).implicit_field().make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_ATTRIBUTE_TRANSFER_INDEX;
+ });
b.add_output<decl::Vector>(N_("Attribute")).dependent_field({6, 7});
b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").dependent_field({6, 7});
@@ -61,14 +72,12 @@ static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({6, 7});
}
-static void geo_node_transfer_attribute_layout(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
const bNode &node = *static_cast<const bNode *>(ptr->data);
- const NodeGeometryTransferAttribute &data = *static_cast<const NodeGeometryTransferAttribute *>(
- node.storage);
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode;
+ const NodeGeometryTransferAttribute &storage = node_storage(node);
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
@@ -77,7 +86,7 @@ static void geo_node_transfer_attribute_layout(uiLayout *layout,
}
}
-static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN(
sizeof(NodeGeometryTransferAttribute), __func__);
@@ -86,12 +95,12 @@ static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *nod
node->storage = data;
}
-static void geo_node_transfer_attribute_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *)
- node->storage;
- const CustomDataType data_type = static_cast<CustomDataType>(data.data_type);
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode;
+ const NodeGeometryTransferAttribute &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first;
bNodeSocket *socket_vector = socket_geometry->next;
@@ -125,6 +134,24 @@ static void geo_node_transfer_attribute_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32);
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_back(2));
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
+
+ const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ (eNodeSocketDatatype)params.other_socket().type);
+ if (type && *type != CD_PROP_STRING) {
+ /* The input and output sockets have the same name. */
+ params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAttributeTransfer");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+}
+
static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
const VArray<float3> &positions,
const IndexMask mask,
@@ -132,9 +159,9 @@ static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
const MutableSpan<float> r_distances_sq,
const MutableSpan<float3> r_positions)
{
- BLI_assert(positions.size() == r_indices.size() || r_indices.is_empty());
- BLI_assert(positions.size() == r_distances_sq.size() || r_distances_sq.is_empty());
- BLI_assert(positions.size() == r_positions.size() || r_positions.is_empty());
+ BLI_assert(positions.size() >= r_indices.size());
+ BLI_assert(positions.size() >= r_distances_sq.size());
+ BLI_assert(positions.size() >= r_positions.size());
for (const int i : mask) {
BVHTreeNearest nearest;
@@ -160,7 +187,7 @@ static void get_closest_pointcloud_points(const PointCloud &pointcloud,
const MutableSpan<int> r_indices,
const MutableSpan<float> r_distances_sq)
{
- BLI_assert(positions.size() == r_indices.size());
+ BLI_assert(positions.size() >= r_indices.size());
BLI_assert(pointcloud.totpoint > 0);
BVHTreeFromPointCloud tree_data;
@@ -500,7 +527,7 @@ class NearestTransferFunction : public fn::MultiFunction {
Array<int> mesh_indices;
Array<float> mesh_distances;
- /* If there is a point-cloud, find the closest points. */
+ /* If there is a point cloud, find the closest points. */
if (use_points_) {
point_indices.reinitialize(tot_samples);
if (use_mesh_) {
@@ -593,8 +620,10 @@ static const GeometryComponent *find_target_component(const GeometrySet &geometr
{
/* Choose the other component based on a consistent order, rather than some more complicated
* heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */
- static const Array<GeometryComponentType> supported_types = {
- GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+ static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_INSTANCES};
for (const GeometryComponentType src_type : supported_types) {
if (component_is_available(geometry, src_type, domain)) {
return geometry.get_component_for_read(src_type);
@@ -719,14 +748,14 @@ static void output_attribute_field(GeoNodeExecParams &params, GField field)
}
}
-static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry = params.extract_input<GeometrySet>("Target");
- const bNode &node = params.node();
- const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *)node.storage;
- const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)data.mode;
- const CustomDataType data_type = static_cast<CustomDataType>(data.data_type);
- const AttributeDomain domain = static_cast<AttributeDomain>(data.domain);
+ const NodeGeometryTransferAttribute &storage = node_storage(params.node());
+ const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
+ storage.mode;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
GField field = get_input_attribute_field(params, data_type);
@@ -737,10 +766,6 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
});
};
- /* Since the instances are not used, there is no point in keeping
- * a reference to them while the field is passed around. */
- geometry.remove(GEO_COMPONENT_TYPE_INSTANCES);
-
GField output_field;
switch (mapping) {
case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
@@ -794,22 +819,25 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params)
output_attribute_field(params, std::move(output_field));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_transfer_attribute_cc
void register_node_type_geo_transfer_attribute()
{
+ namespace file_ns = blender::nodes::node_geo_transfer_attribute_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE, 0);
- node_type_init(&ntype, blender::nodes::geo_node_transfer_attribute_init);
- node_type_update(&ntype, blender::nodes::geo_node_transfer_attribute_update);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
"NodeGeometryTransferAttribute",
node_free_standard_storage,
node_copy_standard_storage);
- ntype.declare = blender::nodes::geo_node_transfer_attribute_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_transfer_attribute_exec;
- ntype.draw_buttons = blender::nodes::geo_node_transfer_attribute_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 2c55a255b5d..8322de20d20 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -35,15 +35,6 @@
namespace blender::nodes {
-static void geo_node_transform_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION);
- b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
- b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
static bool use_translate(const float3 rotation, const float3 scale)
{
if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) {
@@ -69,15 +60,6 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform)
BKE_mesh_normals_tag_dirty(&mesh);
}
-void transform_mesh(Mesh &mesh,
- const float3 translation,
- const float3 rotation,
- const float3 scale)
-{
- const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
- transform_mesh(mesh, matrix);
-}
-
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
{
CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint);
@@ -153,49 +135,71 @@ static void translate_volume(Volume &volume, const float3 translation, const Dep
transform_volume(volume, float4x4::from_location(translation), depsgraph);
}
-void transform_geometry_set(GeometrySet &geometry,
- const float4x4 &transform,
- const Depsgraph &depsgraph)
+static void translate_geometry_set(GeometrySet &geometry,
+ const float3 translation,
+ const Depsgraph &depsgraph)
{
if (CurveEval *curve = geometry.get_curve_for_write()) {
- curve->transform(transform);
+ curve->translate(translation);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
- transform_mesh(*mesh, transform);
+ translate_mesh(*mesh, translation);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
- transform_pointcloud(*pointcloud, transform);
+ translate_pointcloud(*pointcloud, translation);
}
if (Volume *volume = geometry.get_volume_for_write()) {
- transform_volume(*volume, transform, depsgraph);
+ translate_volume(*volume, translation, depsgraph);
}
if (geometry.has_instances()) {
- transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform);
+ translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation);
}
}
-static void translate_geometry_set(GeometrySet &geometry,
- const float3 translation,
- const Depsgraph &depsgraph)
+void transform_geometry_set(GeometrySet &geometry,
+ const float4x4 &transform,
+ const Depsgraph &depsgraph)
{
if (CurveEval *curve = geometry.get_curve_for_write()) {
- curve->translate(translation);
+ curve->transform(transform);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
- translate_mesh(*mesh, translation);
+ transform_mesh(*mesh, transform);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
- translate_pointcloud(*pointcloud, translation);
+ transform_pointcloud(*pointcloud, transform);
}
if (Volume *volume = geometry.get_volume_for_write()) {
- translate_volume(*volume, translation, depsgraph);
+ transform_volume(*volume, transform, depsgraph);
}
if (geometry.has_instances()) {
- translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation);
+ transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform);
}
}
-static void geo_node_transform_exec(GeoNodeExecParams params)
+void transform_mesh(Mesh &mesh,
+ const float3 translation,
+ const float3 rotation,
+ const float3 scale)
+{
+ const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
+ transform_mesh(mesh, matrix);
+}
+
+} // namespace blender::nodes
+
+namespace blender::nodes::node_geo_transform_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const float3 translation = params.extract_input<float3>("Translation");
@@ -214,14 +218,16 @@ static void geo_node_transform_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_transform_cc
void register_node_type_geo_transform()
{
+ namespace file_ns = blender::nodes::node_geo_transform_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_transform_declare;
- ntype.geometry_node_execute = blender::nodes::geo_node_transform_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
index 1a5a60fb1b0..59049ecf0ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -18,9 +18,9 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_translate_instances_cc {
-static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Instances")).only_instances();
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
@@ -33,17 +33,15 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
{
GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE};
- fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()};
- selection_evaluator.add(params.extract_input<Field<bool>>("Selection"));
- selection_evaluator.evaluate();
- const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ fn::FieldEvaluator evaluator{field_context, instances_component.instances_amount()};
+ evaluator.set_selection(params.extract_input<Field<bool>>("Selection"));
+ evaluator.add(params.extract_input<Field<float3>>("Translation"));
+ evaluator.add(params.extract_input<Field<bool>>("Local Space"));
+ evaluator.evaluate();
- fn::FieldEvaluator transforms_evaluator{field_context, &selection};
- transforms_evaluator.add(params.extract_input<Field<float3>>("Translation"));
- transforms_evaluator.add(params.extract_input<Field<bool>>("Local Space"));
- transforms_evaluator.evaluate();
- const VArray<float3> &translations = transforms_evaluator.get_evaluated<float3>(0);
- const VArray<bool> &local_spaces = transforms_evaluator.get_evaluated<bool>(1);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &translations = evaluator.get_evaluated<float3>(0);
+ const VArray<bool> &local_spaces = evaluator.get_evaluated<bool>(1);
MutableSpan<float4x4> instance_transforms = instances_component.instance_transforms();
@@ -60,7 +58,7 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
});
}
-static void geo_node_translate_instances_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
if (geometry_set.has_instances()) {
@@ -70,15 +68,17 @@ static void geo_node_translate_instances_exec(GeoNodeExecParams params)
params.set_output("Instances", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_translate_instances_cc
void register_node_type_geo_translate_instances()
{
+ namespace file_ns = blender::nodes::node_geo_translate_instances_cc;
+
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY, 0);
- ntype.geometry_node_execute = blender::nodes::geo_node_translate_instances_exec;
- ntype.declare = blender::nodes::geo_node_translate_instances_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index c869846e1f8..f8deaaa4a14 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -27,16 +27,16 @@ Mesh *triangulate_mesh(Mesh *mesh,
const int flag);
}
-namespace blender::nodes {
+namespace blender::nodes::node_geo_triangulate_cc {
-static void geo_node_triangulate_declare(NodeDeclarationBuilder &b)
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000);
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_triangulate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "quad_method", 0, "", ICON_NONE);
uiItemR(layout, ptr, "ngon_method", 0, "", ICON_NONE);
@@ -48,7 +48,7 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node)
node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY;
}
-static void geo_node_triangulate_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4);
@@ -69,16 +69,18 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_triangulate_cc
void register_node_type_geo_triangulate()
{
+ namespace file_ns = blender::nodes::node_geo_triangulate_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_triangulate_declare;
- node_type_init(&ntype, blender::nodes::geo_triangulate_init);
- ntype.geometry_node_execute = blender::nodes::geo_node_triangulate_exec;
- ntype.draw_buttons = blender::nodes::geo_node_triangulate_layout;
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::geo_triangulate_init);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index a46d7529124..18f2fa4cd36 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -14,13 +14,23 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_context.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
+#include "ED_node.h"
+#include "ED_spreadsheet.h"
+
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
-namespace blender::nodes {
-static void geo_node_viewer_declare(NodeDeclarationBuilder &b)
+namespace blender::nodes::node_geo_viewer_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryViewer)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_input<decl::Float>(N_("Value")).supports_field().hide_value();
@@ -30,7 +40,7 @@ static void geo_node_viewer_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Value"), "Value_004").supports_field().hide_value();
}
-static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node)
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer),
__func__);
@@ -39,7 +49,7 @@ static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_viewer_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
@@ -63,9 +73,9 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType
}
}
-static void geo_node_viewer_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- const NodeGeometryViewer &storage = *(const NodeGeometryViewer *)node->storage;
+ const NodeGeometryViewer &storage = node_storage(*node);
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type);
@@ -77,18 +87,67 @@ static void geo_node_viewer_update(bNodeTree *ntree, bNode *node)
}
}
-} // namespace blender::nodes
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ auto set_active_fn = [](LinkSearchOpParams &params, bNode &viewer_node) {
+ /* Set this new viewer node active in spreadsheet editors. */
+ SpaceNode *snode = CTX_wm_space_node(&params.C);
+ Main *bmain = CTX_data_main(&params.C);
+ ED_node_set_active(bmain, snode, &params.node_tree, &viewer_node, nullptr);
+ ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node);
+ };
+
+ const std::optional<CustomDataType> type = node_socket_to_custom_data_type(
+ params.other_socket());
+ if (params.in_out() == SOCK_OUT) {
+ /* The viewer node only has inputs. */
+ return;
+ }
+ if (params.other_socket().type == SOCK_GEOMETRY) {
+ params.add_item(IFACE_("Geometry"), [set_active_fn](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeViewer");
+ params.connect_available_socket(node, "Geometry");
+ set_active_fn(params, node);
+ });
+ }
+ if (type &&
+ ELEM(type, CD_PROP_FLOAT, CD_PROP_BOOL, CD_PROP_INT32, CD_PROP_FLOAT3, CD_PROP_COLOR)) {
+ params.add_item(IFACE_("Value"), [type, set_active_fn](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeViewer");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+
+ /* If the source node has a geometry socket, connect it to the new viewer node as well. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &params.node.outputs) {
+ if (socket->type == SOCK_GEOMETRY && !(socket->flag & (SOCK_UNAVAIL | SOCK_HIDDEN))) {
+ nodeAddLink(&params.node_tree,
+ &params.node,
+ socket,
+ &node,
+ static_cast<bNodeSocket *>(node.inputs.first));
+ }
+ }
+
+ set_active_fn(params, node);
+ });
+ }
+}
+
+} // namespace blender::nodes::node_geo_viewer_cc
void register_node_type_geo_viewer()
{
+ namespace file_ns = blender::nodes::node_geo_viewer_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0);
node_type_storage(
&ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage);
- node_type_update(&ntype, blender::nodes::geo_node_viewer_update);
- node_type_init(&ntype, blender::nodes::geo_node_viewer_init);
- ntype.declare = blender::nodes::geo_node_viewer_declare;
- ntype.draw_buttons_ex = blender::nodes::geo_node_viewer_layout;
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_init(&ntype, file_ns::node_init);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons_ex = file_ns::node_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index 99eeae370fe..0819b401941 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -35,26 +35,39 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_volume_to_mesh_cc {
-static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
+NODE_STORAGE_FUNCS(NodeGeometryVolumeToMesh)
+
+static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME);
- b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>(N_("Voxel Size"))
+ .default_value(0.3f)
+ .min(0.01f)
+ .subtype(PROP_DISTANCE)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE;
+ });
+ b.add_input<decl::Float>(N_("Voxel Amount"))
+ .default_value(64.0f)
+ .min(0.0f)
+ .make_available([](bNode &node) {
+ node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT;
+ });
b.add_input<decl::Float>(N_("Threshold")).default_value(0.1f).min(0.0f);
b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
b.add_output<decl::Geometry>(N_("Mesh"));
}
-static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
}
-static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
sizeof(NodeGeometryVolumeToMesh), __func__);
@@ -62,26 +75,26 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-static void geo_node_volume_to_mesh_update(bNodeTree *ntree, bNode *node)
+static void node_update(bNodeTree *ntree, bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
+ const NodeGeometryVolumeToMesh &storage = node_storage(*node);
bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
nodeSetSocketAvailability(ntree,
voxel_amount_socket,
- data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
+ storage.resolution_mode ==
+ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
nodeSetSocketAvailability(ntree,
voxel_size_socket,
- data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
+ storage.resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
}
#ifdef WITH_OPENVDB
static bke::VolumeToMeshResolution get_resolution_param(const GeoNodeExecParams &params)
{
- const NodeGeometryVolumeToMesh &storage =
- *(const NodeGeometryVolumeToMesh *)params.node().storage;
+ const NodeGeometryVolumeToMesh &storage = node_storage(params.node());
bke::VolumeToMeshResolution resolution;
resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
@@ -176,7 +189,7 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam
#endif /* WITH_OPENVDB */
-static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
+static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
@@ -194,20 +207,22 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
params.set_output("Mesh", std::move(geometry_set));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_geo_volume_to_mesh_cc
void register_node_type_geo_volume_to_mesh()
{
+ namespace file_ns = blender::nodes::node_geo_volume_to_mesh_cc;
+
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
- ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare;
+ ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
node_type_size(&ntype, 170, 120, 700);
- node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init);
- node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec;
- ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index 8a9386c1137..dc223f07a26 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -20,10 +20,6 @@
namespace blender::nodes {
-/* Construct a new derived node tree for a given root node tree. The generated derived node tree
- * does not own the used node tree refs (so that those can be used by others as well). The caller
- * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the
- * derived node tree. */
DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs)
{
/* Construct all possible contexts immediately. This is significantly cheaper than inlining all
@@ -73,9 +69,6 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context)
context->~DTreeContext();
}
-/**
- * \return True when there is a link cycle. Unavailable sockets are ignored.
- */
bool DerivedNodeTree::has_link_cycles() const
{
for (const NodeTreeRef *tree_ref : used_node_tree_refs_) {
@@ -96,7 +89,6 @@ bool DerivedNodeTree::has_undefined_nodes_or_sockets() const
return false;
}
-/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */
void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const
{
this->foreach_node_in_context_recursive(*root_context_, callback);
@@ -168,7 +160,7 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
const DTreeContext *child_context = context_->child_context(socket_ref_->node());
if (child_context == nullptr) {
- /* Can happen when the group node references a non-existant group (e.g. when the group is
+ /* Can happen when the group node references a non-existent group (e.g. when the group is
* linked but the original file is not found). */
return {};
}
@@ -184,9 +176,6 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
return {};
}
-/* Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes
- * and node groups are handled by this function. Origin sockets are ones where a node gets its
- * inputs from. */
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const
{
BLI_assert(*this);
@@ -233,9 +222,6 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c
}
}
-/* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
- * and node groups are handled by this function. Target sockets are on the nodes that use the value
- * from this socket. */
void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const
{
TargetSocketPathInfo path_info;
@@ -281,7 +267,6 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
mute_output.foreach_target_socket(target_fn, path_info);
path_info.sockets.pop_last();
path_info.sockets.pop_last();
- break;
}
}
else if (linked_node->is_group_output_node()) {
@@ -343,7 +328,6 @@ static dot::Cluster *get_dot_cluster_for_context(
});
}
-/* Generates a graph in dot format. The generated graph has all node groups inlined. */
std::string DerivedNodeTree::to_dot() const
{
dot::DirectedGraph digraph;
diff --git a/source/blender/nodes/intern/extern_implementations.cc b/source/blender/nodes/intern/extern_implementations.cc
deleted file mode 100644
index 35de319f20b..00000000000
--- a/source/blender/nodes/intern/extern_implementations.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "NOD_socket_declarations.hh"
-#include "NOD_socket_declarations_geometry.hh"
-
-namespace blender::nodes {
-#define MAKE_EXTERN_SOCKET_IMPLEMENTATION(TYPE) \
- template class SocketDeclarationBuilder<TYPE>; \
- template TYPE::Builder &NodeDeclarationBuilder::add_input<TYPE>(StringRef, StringRef); \
- template TYPE::Builder &NodeDeclarationBuilder::add_output<TYPE>(StringRef, StringRef);
-
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Float)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Int)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Vector)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Bool)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Color)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::String)
-MAKE_EXTERN_SOCKET_IMPLEMENTATION(decl::Geometry)
-
-#undef MAKE_EXTERN_SOCKET_IMPLEMENTATION
-} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index ddd3c991518..e33f6cf345d 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -25,12 +25,15 @@
#include "BLT_translation.h"
+#include <chrono>
+
namespace blender::nodes::geometry_nodes_eval_log {
using fn::CPPType;
using fn::FieldCPPType;
using fn::FieldInput;
using fn::GField;
+using fn::ValueOrFieldCPPType;
ModifierLog::ModifierLog(GeoLogger &logger)
: input_geometry_log_(std::move(logger.input_geometry_log_)),
@@ -63,6 +66,17 @@ ModifierLog::ModifierLog(GeoLogger &logger)
node_with_warning.node);
node_log.warnings_.append(node_with_warning.warning);
}
+
+ for (NodeWithExecutionTime &node_with_exec_time : local_logger.node_exec_times_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context,
+ node_with_exec_time.node);
+ node_log.exec_time_ = node_with_exec_time.exec_time;
+ }
+
+ for (NodeWithDebugMessage &debug_message : local_logger.node_debug_messages_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, debug_message.node);
+ node_log.debug_messages_.append(debug_message.message);
+ }
}
}
@@ -177,12 +191,14 @@ const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket
GFieldValueLog::GFieldValueLog(fn::GField field, bool log_full_field) : type_(field.cpp_type())
{
- Set<std::reference_wrapper<const FieldInput>> field_inputs_set;
- field.node().foreach_field_input(
- [&](const FieldInput &field_input) { field_inputs_set.add(field_input); });
+ const std::shared_ptr<const fn::FieldInputs> &field_input_nodes = field.node().field_inputs();
+ /* Put the deduplicated field inputs into a vector so that they can be sorted below. */
Vector<std::reference_wrapper<const FieldInput>> field_inputs;
- field_inputs.extend(field_inputs_set.begin(), field_inputs_set.end());
+ if (field_input_nodes) {
+ field_inputs.extend(field_input_nodes->deduplicated_nodes.begin(),
+ field_input_nodes->deduplicated_nodes.end());
+ }
std::sort(
field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) {
@@ -417,25 +433,38 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value
geometry_set, log_full_geometry);
values_.append({copied_sockets, std::move(value_log)});
}
- else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
- GField field = field_type->get_gfield(value.get());
- bool log_full_field = false;
- if (!field.node().depends_on_input()) {
- /* Always log constant fields so that their value can be shown in socket inspection.
- * In the future we can also evaluate the field here and only store the value. */
- log_full_field = true;
- }
- if (!log_full_field) {
- for (const DSocket &socket : sockets) {
- if (main_logger_->log_full_sockets_.contains(socket)) {
- log_full_field = true;
- break;
+ else if (const ValueOrFieldCPPType *value_or_field_type =
+ dynamic_cast<const ValueOrFieldCPPType *>(&type)) {
+ const void *value_or_field = value.get();
+ if (value_or_field_type->is_field(value_or_field)) {
+ GField field = *value_or_field_type->get_field_ptr(value_or_field);
+ bool log_full_field = false;
+ if (!field.node().depends_on_input()) {
+ /* Always log constant fields so that their value can be shown in socket inspection.
+ * In the future we can also evaluate the field here and only store the value. */
+ log_full_field = true;
+ }
+ if (!log_full_field) {
+ for (const DSocket &socket : sockets) {
+ if (main_logger_->log_full_sockets_.contains(socket)) {
+ log_full_field = true;
+ break;
+ }
}
}
+ destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>(
+ std::move(field), log_full_field);
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+ else {
+ const CPPType &base_type = value_or_field_type->base_type();
+ const void *value = value_or_field_type->get_value_ptr(value_or_field);
+ void *buffer = allocator_->allocate(base_type.size(), base_type.alignment());
+ base_type.copy_construct(value, buffer);
+ destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>(
+ GMutablePointer{base_type, buffer});
+ values_.append({copied_sockets, std::move(value_log)});
}
- destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>(
- std::move(field), log_full_field);
- values_.append({copied_sockets, std::move(value_log)});
}
else {
void *buffer = allocator_->allocate(type.size(), type.alignment());
@@ -457,4 +486,14 @@ void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::str
node_warnings_.append({node, {type, std::move(message)}});
}
+void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds exec_time)
+{
+ node_exec_times_.append({node, exec_time});
+}
+
+void LocalGeoLogger::log_debug_message(DNode node, std::string message)
+{
+ node_debug_messages_.append({node, std::move(message)});
+}
+
} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/intern/math_functions.cc b/source/blender/nodes/intern/math_functions.cc
index aa23777b664..00f4f2a3405 100644
--- a/source/blender/nodes/intern/math_functions.cc
+++ b/source/blender/nodes/intern/math_functions.cc
@@ -127,17 +127,17 @@ const FloatMathOperationInfo *get_float_compare_operation_info(const int operati
((void)0)
switch (operation) {
- case NODE_FLOAT_COMPARE_LESS_THAN:
+ case NODE_COMPARE_LESS_THAN:
RETURN_OPERATION_INFO("Less Than", "math_less_than");
- case NODE_FLOAT_COMPARE_LESS_EQUAL:
+ case NODE_COMPARE_LESS_EQUAL:
RETURN_OPERATION_INFO("Less Than or Equal", "math_less_equal");
- case NODE_FLOAT_COMPARE_GREATER_THAN:
+ case NODE_COMPARE_GREATER_THAN:
RETURN_OPERATION_INFO("Greater Than", "math_greater_than");
- case NODE_FLOAT_COMPARE_GREATER_EQUAL:
+ case NODE_COMPARE_GREATER_EQUAL:
RETURN_OPERATION_INFO("Greater Than or Equal", "math_greater_equal");
- case NODE_FLOAT_COMPARE_EQUAL:
+ case NODE_COMPARE_EQUAL:
RETURN_OPERATION_INFO("Equal", "math_equal");
- case NODE_FLOAT_COMPARE_NOT_EQUAL:
+ case NODE_COMPARE_NOT_EQUAL:
RETURN_OPERATION_INFO("Not Equal", "math_not_equal");
}
diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc
index b80cedc9352..c302b1081af 100644
--- a/source/blender/nodes/intern/node_common.cc
+++ b/source/blender/nodes/intern/node_common.cc
@@ -32,6 +32,7 @@
#include "BLI_set.hh"
#include "BLI_stack.hh"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -50,33 +51,33 @@ using blender::Map;
using blender::MultiValueMap;
using blender::Set;
using blender::Stack;
+using blender::StringRef;
/* -------------------------------------------------------------------- */
/** \name Node Group
* \{ */
-bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier)
+static bNodeSocket *find_matching_socket(ListBase &sockets, StringRef identifier)
{
- LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->inputs) {
- if (STREQ(sock->identifier, identifier)) {
- return sock;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &sockets) {
+ if (socket->identifier == identifier) {
+ return socket;
}
}
return nullptr;
}
+bNodeSocket *node_group_find_input_socket(bNode *groupnode, const char *identifier)
+{
+ return find_matching_socket(groupnode->inputs, identifier);
+}
+
bNodeSocket *node_group_find_output_socket(bNode *groupnode, const char *identifier)
{
- LISTBASE_FOREACH (bNodeSocket *, sock, &groupnode->outputs) {
- if (STREQ(sock->identifier, identifier)) {
- return sock;
- }
- }
- return nullptr;
+ return find_matching_socket(groupnode->outputs, identifier);
}
-/* groups display their internal tree name as label */
-void node_group_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_group_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
BLI_strncpy(label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), maxlen);
}
@@ -107,7 +108,7 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis
}
if (nodetree == grouptree) {
- *r_disabled_hint = "Nesting a node group inside of itself is not allowed";
+ *r_disabled_hint = TIP_("Nesting a node group inside of itself is not allowed");
return false;
}
@@ -121,83 +122,84 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis
return valid;
}
-/* used for both group nodes and interface nodes */
-static bNodeSocket *group_verify_socket(bNodeTree *ntree,
- bNode *gnode,
- bNodeSocket *iosock,
- ListBase *verify_lb,
- eNodeSocketInOut in_out)
+static void add_new_socket_from_interface(bNodeTree &node_tree,
+ bNode &node,
+ const bNodeSocket &interface_socket,
+ const eNodeSocketInOut in_out)
{
- bNodeSocket *sock;
+ bNodeSocket *socket = nodeAddSocket(&node_tree,
+ &node,
+ in_out,
+ interface_socket.idname,
+ interface_socket.identifier,
+ interface_socket.name);
- for (sock = (bNodeSocket *)verify_lb->first; sock; sock = sock->next) {
- if (STREQ(sock->identifier, iosock->identifier)) {
- break;
- }
+ if (interface_socket.typeinfo->interface_init_socket) {
+ interface_socket.typeinfo->interface_init_socket(
+ &node_tree, &interface_socket, &node, socket, "interface");
}
- if (sock) {
- strcpy(sock->name, iosock->name);
+}
- const int mask = SOCK_HIDE_VALUE;
- sock->flag = (sock->flag & ~mask) | (iosock->flag & mask);
+static void update_socket_to_match_interface(bNodeTree &node_tree,
+ bNode &node,
+ bNodeSocket &socket_to_update,
+ const bNodeSocket &interface_socket)
+{
+ strcpy(socket_to_update.name, interface_socket.name);
- /* Update socket type if necessary */
- if (sock->typeinfo != iosock->typeinfo) {
- nodeModifySocketType(ntree, gnode, sock, iosock->idname);
- /* Flag the tree to make sure link validity is updated after type changes. */
- ntree->update |= NTREE_UPDATE_LINKS;
- }
+ const int mask = SOCK_HIDE_VALUE;
+ socket_to_update.flag = (socket_to_update.flag & ~mask) | (interface_socket.flag & mask);
- if (iosock->typeinfo->interface_verify_socket) {
- iosock->typeinfo->interface_verify_socket(ntree, iosock, gnode, sock, "interface");
- }
+ /* Update socket type if necessary */
+ if (socket_to_update.typeinfo != interface_socket.typeinfo) {
+ nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname);
+ /* Flag the tree to make sure link validity is updated after type changes. */
+ node_tree.update |= NTREE_UPDATE_LINKS;
}
- else {
- sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name);
- if (iosock->typeinfo->interface_init_socket) {
- iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface");
- }
+ if (interface_socket.typeinfo->interface_verify_socket) {
+ interface_socket.typeinfo->interface_verify_socket(
+ &node_tree, &interface_socket, &node, &socket_to_update, "interface");
}
-
- /* remove from list temporarily, to distinguish from orphaned sockets */
- BLI_remlink(verify_lb, sock);
-
- return sock;
}
-/* used for both group nodes and interface nodes */
-static void group_verify_socket_list(bNodeTree *ntree,
- bNode *gnode,
- ListBase *iosock_lb,
- ListBase *verify_lb,
- eNodeSocketInOut in_out)
+/**
+ * Used for group nodes and group input/output nodes to update the list of input or output sockets
+ * on a node to match the provided interface. Assumes that \a verify_lb is the node's matching
+ * input or output socket list, depending on whether the node is a group input/output or a group
+ * node.
+ */
+static void group_verify_socket_list(bNodeTree &node_tree,
+ bNode &node,
+ const ListBase &interface_sockets,
+ ListBase &verify_lb,
+ const eNodeSocketInOut in_out)
{
- bNodeSocket *sock, *nextsock;
-
- /* step by step compare */
-
- bNodeSocket *iosock = (bNodeSocket *)iosock_lb->first;
- for (; iosock; iosock = iosock->next) {
- /* abusing new_sock pointer for verification here! only used inside this function */
- iosock->new_sock = group_verify_socket(ntree, gnode, iosock, verify_lb, in_out);
- }
- /* leftovers are removed */
- for (sock = (bNodeSocket *)verify_lb->first; sock; sock = nextsock) {
- nextsock = sock->next;
- nodeRemoveSocket(ntree, gnode, sock);
- }
- /* and we put back the verified sockets */
- iosock = (bNodeSocket *)iosock_lb->first;
- for (; iosock; iosock = iosock->next) {
- if (iosock->new_sock) {
- BLI_addtail(verify_lb, iosock->new_sock);
- iosock->new_sock = nullptr;
+ ListBase old_sockets = verify_lb;
+ BLI_listbase_clear(&verify_lb);
+
+ LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &interface_sockets) {
+ bNodeSocket *matching_socket = find_matching_socket(old_sockets, interface_socket->identifier);
+ if (matching_socket) {
+ /* If a socket with the same identifier exists in the previous socket list, update it
+ * with the correct name, type, etc. Then move it from the old list to the new one. */
+ update_socket_to_match_interface(node_tree, node, *matching_socket, *interface_socket);
+ BLI_remlink(&old_sockets, matching_socket);
+ BLI_addtail(&verify_lb, matching_socket);
+ }
+ else {
+ /* If there was no socket withe the same identifier already, simply create a new socket
+ * based on the interface socket, which will already add it to the new list. */
+ add_new_socket_from_interface(node_tree, node, *interface_socket, in_out);
}
}
+
+ /* Remove leftover sockets that didn't match the node group's interface. */
+ LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) {
+ nodeRemoveSocket(&node_tree, &node, unused_socket);
+ }
}
-/* make sure all group node in ntree, which use ngroup, are sync'd */
void node_group_update(struct bNodeTree *ntree, struct bNode *node)
{
/* check inputs and outputs, and remove or insert them */
@@ -210,8 +212,8 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
}
else {
bNodeTree *ngroup = (bNodeTree *)node->id;
- group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
- group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT);
+ group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN);
+ group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT);
}
}
@@ -305,9 +307,6 @@ static void propagate_reroute_type_from_start_socket(
}
}
-/* Global update function for Reroute node types.
- * This depends on connected nodes, so must be done as a tree-wide update.
- */
void ntree_update_reroute_nodes(bNodeTree *ntree)
{
/* Contains nodes that are linked to at least one reroute node. */
@@ -497,7 +496,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
/* check inputs and outputs, and remove or insert them */
{
/* value_in_out inverted for interface nodes to get correct socket value_property */
- group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT);
+ group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT);
/* add virtual extension socket */
nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", "");
@@ -595,7 +594,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
/* check inputs and outputs, and remove or insert them */
{
/* value_in_out inverted for interface nodes to get correct socket value_property */
- group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN);
+ group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN);
/* add virtual extension socket */
nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", "");
@@ -613,6 +612,8 @@ void register_node_type_group_output(void)
node_type_init(ntype, node_group_output_init);
node_type_update(ntype, node_group_output_update);
+ ntype->no_muting = true;
+
nodeRegisterType(ntype);
}
diff --git a/source/blender/nodes/intern/node_common.h b/source/blender/nodes/intern/node_common.h
index cdb7b6897b9..0d1b51224e6 100644
--- a/source/blender/nodes/intern/node_common.h
+++ b/source/blender/nodes/intern/node_common.h
@@ -31,11 +31,19 @@ extern "C" {
struct bNodeTree;
-void node_group_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+/** Groups display their internal tree name as label. */
+void node_group_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
bool node_group_poll_instance(struct bNode *node,
struct bNodeTree *nodetree,
const char **r_disabled_hint);
+/**
+ * Global update function for Reroute node types.
+ * This depends on connected nodes, so must be done as a tree-wide update.
+ */
void ntree_update_reroute_nodes(struct bNodeTree *ntree);
#ifdef __cplusplus
diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc
index e804d10ad75..75d47cfd386 100644
--- a/source/blender/nodes/intern/node_declaration.cc
+++ b/source/blender/nodes/intern/node_declaration.cc
@@ -51,11 +51,14 @@ bNodeSocket &SocketDeclaration::update_or_build(bNodeTree &ntree,
bNodeSocket &socket) const
{
/* By default just rebuild. */
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ UNUSED_VARS_NDEBUG(socket);
+ return this->build(ntree, node);
}
void SocketDeclaration::set_common_flags(bNodeSocket &socket) const
{
+ SET_FLAG_FROM_TEST(socket.flag, compact_, SOCK_COMPACT);
SET_FLAG_FROM_TEST(socket.flag, hide_value_, SOCK_HIDE_VALUE);
SET_FLAG_FROM_TEST(socket.flag, hide_label_, SOCK_HIDE_LABEL);
SET_FLAG_FROM_TEST(socket.flag, is_multi_input_, SOCK_MULTI_INPUT);
@@ -70,6 +73,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
if (socket.identifier != identifier_) {
return false;
}
+ if (((socket.flag & SOCK_COMPACT) != 0) != compact_) {
+ return false;
+ }
if (((socket.flag & SOCK_HIDE_VALUE) != 0) != hide_value_) {
return false;
}
diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc
index 18403417af3..95070bf735e 100644
--- a/source/blender/nodes/intern/node_exec.cc
+++ b/source/blender/nodes/intern/node_exec.cc
@@ -34,14 +34,12 @@
#include "node_exec.h"
#include "node_util.h"
-/* supported socket types in old nodes */
int node_exec_socket_use_stack(bNodeSocket *sock)
{
/* NOTE: INT supported as FLOAT. Only for EEVEE. */
return ELEM(sock->type, SOCK_INT, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
}
-/* for a given socket, find the actual stack entry */
bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock)
{
if (stack && sock && sock->stack_index >= 0) {
diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h
index de7cbb8cedb..b2e1c6564b6 100644
--- a/source/blender/nodes/intern/node_exec.h
+++ b/source/blender/nodes/intern/node_exec.h
@@ -71,8 +71,10 @@ typedef struct bNodeThreadStack {
bool used;
} bNodeThreadStack;
+/** Supported socket types in old nodes. */
int node_exec_socket_use_stack(struct bNodeSocket *sock);
+/** For a given socket, find the actual stack entry. */
struct bNodeStack *node_get_socket_stack(struct bNodeStack *stack, struct bNodeSocket *sock);
void node_get_stack(struct bNode *node,
struct bNodeStack *stack,
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index faa4337ba7e..b5c4e71df74 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -18,8 +18,9 @@
#include "DEG_depsgraph_query.h"
+#include "BKE_type_conversions.hh"
+
#include "NOD_geometry_exec.hh"
-#include "NOD_type_conversions.hh"
#include "node_geometry_util.hh"
@@ -149,7 +150,7 @@ GVArray GeoNodeExecParams::get_input_attribute(const StringRef name,
}
return GVArray::ForSingle(*cpp_type, domain_size, default_value);
}
- const DataTypeConversions &conversions = get_implicit_type_conversions();
+ const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
if (found_socket->type == SOCK_FLOAT) {
const float value = this->get_input<float>(found_socket->identifier);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
@@ -215,11 +216,6 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
return default_type;
}
-/**
- * If any of the corresponding input sockets are attributes instead of single values,
- * use the highest priority attribute domain from among them.
- * Otherwise return the default domain.
- */
AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
Span<std::string> names,
const GeometryComponent &component,
@@ -254,6 +250,11 @@ std::string GeoNodeExecParams::attribute_producer_name() const
return provider_->dnode->label_or_name() + TIP_(" node");
}
+void GeoNodeExecParams::set_default_remaining_outputs()
+{
+ provider_->set_default_remaining_outputs();
+}
+
void GeoNodeExecParams::check_input_access(StringRef identifier,
const CPPType *requested_type) const
{
@@ -288,7 +289,7 @@ void GeoNodeExecParams::check_input_access(StringRef identifier,
BLI_assert_unreachable();
}
else if (requested_type != nullptr) {
- const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type;
if (*requested_type != expected_type) {
std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '"
<< expected_type.name() << "'.\n";
@@ -328,7 +329,7 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType
BLI_assert_unreachable();
}
else {
- const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type();
+ const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type;
if (value_type != expected_type) {
std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '"
<< expected_type.name() << "'.\n";
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index dce54d58dce..d83c05b38a1 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -28,7 +28,6 @@
#include "BLI_color.hh"
#include "BLI_float3.hh"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -51,6 +50,7 @@
#include "FN_field.hh"
using namespace blender;
+using blender::fn::ValueOrField;
using blender::nodes::SocketDeclarationPtr;
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
@@ -191,7 +191,6 @@ static void refresh_socket_list(bNodeTree &ntree,
bNode &node,
ListBase &sockets,
Span<SocketDeclarationPtr> socket_decls,
- const eNodeSocketInOut in_out,
const bool do_id_user)
{
Vector<bNodeSocket *> old_sockets = sockets;
@@ -210,7 +209,7 @@ static void refresh_socket_list(bNodeTree &ntree,
bNodeSocket *new_socket = nullptr;
if (old_socket_with_same_identifier == nullptr) {
/* Create a completely new socket. */
- new_socket = &socket_decl->build(ntree, node, in_out);
+ new_socket = &socket_decl->build(ntree, node);
}
else {
STRNCPY(old_socket_with_same_identifier->name, socket_decl->name().c_str());
@@ -258,8 +257,8 @@ static void refresh_node(bNodeTree &ntree,
blender::nodes::NodeDeclaration &node_decl,
bool do_id_user)
{
- refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), SOCK_IN, do_id_user);
- refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), SOCK_OUT, do_id_user);
+ refresh_socket_list(ntree, node, node.inputs, node_decl.inputs(), do_id_user);
+ refresh_socket_list(ntree, node, node.outputs, node_decl.outputs(), do_id_user);
}
void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
@@ -548,7 +547,7 @@ void node_socket_skip_reroutes(
}
static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree),
- bNodeSocket *stemp,
+ const bNodeSocket *interface_socket,
bNode *UNUSED(node),
bNodeSocket *sock,
const char *UNUSED(data_path))
@@ -559,47 +558,50 @@ static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree),
/* XXX socket interface 'type' value is not used really,
* but has to match or the copy function will bail out
*/
- stemp->type = stemp->typeinfo->type;
+ const_cast<bNodeSocket *>(interface_socket)->type = interface_socket->typeinfo->type;
/* copy default_value settings */
- node_socket_copy_default_value(sock, stemp);
+ node_socket_copy_default_value(sock, interface_socket);
}
/* copies settings that are not changed for each socket instance */
static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree),
- bNodeSocket *stemp,
+ const bNodeSocket *interface_socket,
bNode *UNUSED(node),
bNodeSocket *sock,
const char *UNUSED(data_path))
{
/* sanity check */
- if (sock->type != stemp->typeinfo->type) {
+ if (sock->type != interface_socket->typeinfo->type) {
return;
}
/* make sure both exist */
- if (!stemp->default_value) {
+ if (!interface_socket->default_value) {
return;
}
node_socket_init_default_value(sock);
- switch (stemp->typeinfo->type) {
+ switch (interface_socket->typeinfo->type) {
case SOCK_FLOAT: {
bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)sock->default_value;
- bNodeSocketValueFloat *fromval = (bNodeSocketValueFloat *)stemp->default_value;
+ const bNodeSocketValueFloat *fromval = (const bNodeSocketValueFloat *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
case SOCK_INT: {
bNodeSocketValueInt *toval = (bNodeSocketValueInt *)sock->default_value;
- bNodeSocketValueInt *fromval = (bNodeSocketValueInt *)stemp->default_value;
+ const bNodeSocketValueInt *fromval = (const bNodeSocketValueInt *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
case SOCK_VECTOR: {
bNodeSocketValueVector *toval = (bNodeSocketValueVector *)sock->default_value;
- bNodeSocketValueVector *fromval = (bNodeSocketValueVector *)stemp->default_value;
+ const bNodeSocketValueVector *fromval = (const bNodeSocketValueVector *)
+ interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
@@ -697,17 +699,15 @@ static bNodeSocketType *make_socket_type_virtual()
static bNodeSocketType *make_socket_type_bool()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<bool>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<bool>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
bool value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<bool>(value);
};
return socktype;
}
@@ -715,17 +715,15 @@ static bNodeSocketType *make_socket_type_bool()
static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<float>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<float>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<float>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
float value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<float>(value);
};
return socktype;
}
@@ -733,17 +731,15 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<int>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<int>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<int>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
int value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<int>(value);
};
return socktype;
}
@@ -751,17 +747,15 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<blender::float3>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
blender::float3 value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<blender::float3>(value);
};
return socktype;
}
@@ -769,20 +763,16 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
static bNodeSocketType *make_socket_type_rgba()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
- socktype->get_base_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::ColorGeometry4f>();
- };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>();
- };
+ socktype->geometry_nodes_cpp_type =
+ &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
blender::ColorGeometry4f value;
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value)
- blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<blender::ColorGeometry4f>(value);
};
return socktype;
}
@@ -790,18 +780,16 @@ static bNodeSocketType *make_socket_type_rgba()
static bNodeSocketType *make_socket_type_string()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value);
};
- socktype->get_geometry_nodes_cpp_type = []() {
- return &blender::fn::CPPType::get<blender::fn::Field<std::string>>();
- };
+ socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
std::string value;
value.~basic_string();
socket.typeinfo->get_base_cpp_value(socket, &value);
- new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value));
+ new (r_value) ValueOrField<std::string>(value);
};
return socktype;
}
@@ -815,11 +803,11 @@ MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType)
static bNodeSocketType *make_socket_type_object()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -827,11 +815,11 @@ static bNodeSocketType *make_socket_type_object()
static bNodeSocketType *make_socket_type_geometry()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<GeometrySet>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>();
socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) {
new (r_value) GeometrySet();
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -839,11 +827,11 @@ static bNodeSocketType *make_socket_type_geometry()
static bNodeSocketType *make_socket_type_collection()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -851,11 +839,11 @@ static bNodeSocketType *make_socket_type_collection()
static bNodeSocketType *make_socket_type_texture()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -863,11 +851,11 @@ static bNodeSocketType *make_socket_type_texture()
static bNodeSocketType *make_socket_type_image()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Image *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
@@ -875,11 +863,11 @@ static bNodeSocketType *make_socket_type_image()
static bNodeSocketType *make_socket_type_material()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE);
- socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); };
+ socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value;
};
- socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type;
+ socktype->geometry_nodes_cpp_type = socktype->base_cpp_type;
socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value;
return socktype;
}
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
index ed5691ebf7f..4fef5b96e9f 100644
--- a/source/blender/nodes/intern/node_socket_declarations.cc
+++ b/source/blender/nodes/intern/node_socket_declarations.cc
@@ -23,6 +23,52 @@
namespace blender::nodes::decl {
+/**
+ * \note This function only deals with declarations, not the field status of existing nodes. If the
+ * field status of existing nodes was stored on the sockets, an improvement would be to check the
+ * existing socket's current status instead of the declaration.
+ */
+static bool field_types_are_compatible(const SocketDeclaration &input,
+ const SocketDeclaration &output)
+{
+ if (output.output_field_dependency().field_type() == OutputSocketFieldType::FieldSource) {
+ if (input.input_field_type() == InputSocketFieldType::None) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool sockets_can_connect(const SocketDeclaration &socket_decl,
+ const bNodeSocket &other_socket)
+{
+ /* Input sockets cannot connect to input sockets, outputs cannot connect to outputs. */
+ if (socket_decl.in_out() == other_socket.in_out) {
+ return false;
+ }
+
+ if (other_socket.declaration) {
+ if (socket_decl.in_out() == SOCK_IN) {
+ if (!field_types_are_compatible(socket_decl, *other_socket.declaration)) {
+ return false;
+ }
+ }
+ else {
+ if (!field_types_are_compatible(*other_socket.declaration, socket_decl)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool basic_types_can_connect(const SocketDeclaration &UNUSED(socket_decl),
+ const bNodeSocket &other_socket)
+{
+ return ELEM(other_socket.type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subtype)
{
const char *idname = nodeStaticSocketType(socket.type, new_subtype);
@@ -35,10 +81,10 @@ static void modify_subtype_except_for_storage(bNodeSocket &socket, int new_subty
/** \name #Float
* \{ */
-bNodeSocket &Float::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Float::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_FLOAT, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueFloat &value = *(bNodeSocketValueFloat *)socket.default_value;
value.min = soft_min_value_;
@@ -68,10 +114,19 @@ bool Float::matches(const bNodeSocket &socket) const
return true;
}
+bool Float::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_FLOAT) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -90,10 +145,10 @@ bNodeSocket &Float::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &
/** \name #Int
* \{ */
-bNodeSocket &Int::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Int::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_INT, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueInt &value = *(bNodeSocketValueInt *)socket.default_value;
value.min = soft_min_value_;
@@ -123,10 +178,19 @@ bool Int::matches(const bNodeSocket &socket) const
return true;
}
+bool Int::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_INT) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -145,10 +209,10 @@ bNodeSocket &Int::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &so
/** \name #Vector
* \{ */
-bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Vector::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_VECTOR, subtype_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
copy_v3_v3(value.value, default_value_);
@@ -171,10 +235,19 @@ bool Vector::matches(const bNodeSocket &socket) const
return true;
}
+bool Vector::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_VECTOR) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
if (socket.typeinfo->subtype != subtype_) {
modify_subtype_except_for_storage(socket, subtype_);
@@ -192,10 +265,10 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
/** \name #Bool
* \{ */
-bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Bool::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_BOOLEAN, PROP_NONE, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueBoolean &value = *(bNodeSocketValueBoolean *)socket.default_value;
value.value = default_value_;
@@ -213,16 +286,24 @@ bool Bool::matches(const bNodeSocket &socket) const
return true;
}
+bool Bool::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name #Color
* \{ */
-bNodeSocket &Color::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Color::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_RGBA, PROP_NONE, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
bNodeSocketValueRGBA &value = *(bNodeSocketValueRGBA *)socket.default_value;
copy_v4_v4(value.value, default_value_);
@@ -245,16 +326,24 @@ bool Color::matches(const bNodeSocket &socket) const
return true;
}
+bool Color::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ return basic_types_can_connect(*this, socket);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name #String
* \{ */
-bNodeSocket &String::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &String::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
- &ntree, &node, in_out, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, SOCK_STRING, PROP_NONE, identifier_.c_str(), name_.c_str());
STRNCPY(((bNodeSocketValueString *)socket.default_value)->value, default_value_.c_str());
this->set_common_flags(socket);
return socket;
@@ -271,18 +360,21 @@ bool String::matches(const bNodeSocket &socket) const
return true;
}
+bool String::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && socket.type == SOCK_STRING;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name #IDSocketDeclaration
* \{ */
-bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree,
- bNode &node,
- eNodeSocketInOut in_out) const
+bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
- &ntree, &node, in_out, idname_, identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, idname_, identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
return socket;
}
@@ -298,12 +390,18 @@ bool IDSocketDeclaration::matches(const bNodeSocket &socket) const
return true;
}
+bool IDSocketDeclaration::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && STREQ(socket.idname, idname_);
+}
+
bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree,
bNode &node,
bNodeSocket &socket) const
{
if (StringRef(socket.idname) != idname_) {
- return this->build(ntree, node, (eNodeSocketInOut)socket.in_out);
+ BLI_assert(socket.in_out == in_out_);
+ return this->build(ntree, node);
}
this->set_common_flags(socket);
return socket;
@@ -315,10 +413,10 @@ bNodeSocket &IDSocketDeclaration::update_or_build(bNodeTree &ntree,
/** \name #Geometry
* \{ */
-bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Geometry::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
- &ntree, &node, in_out, "NodeSocketGeometry", identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, "NodeSocketGeometry", identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
return socket;
}
@@ -334,6 +432,11 @@ bool Geometry::matches(const bNodeSocket &socket) const
return true;
}
+bool Geometry::can_connect(const bNodeSocket &socket) const
+{
+ return sockets_can_connect(*this, socket) && socket.type == SOCK_GEOMETRY;
+}
+
Span<GeometryComponentType> Geometry::supported_types() const
{
return supported_types_;
@@ -376,4 +479,41 @@ GeometryBuilder &GeometryBuilder::only_instances(bool value)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name #Shader
+ * \{ */
+
+bNodeSocket &Shader::build(bNodeTree &ntree, bNode &node) const
+{
+ bNodeSocket &socket = *nodeAddSocket(
+ &ntree, &node, in_out_, "NodeSocketShader", identifier_.c_str(), name_.c_str());
+ this->set_common_flags(socket);
+ return socket;
+}
+
+bool Shader::matches(const bNodeSocket &socket) const
+{
+ if (!this->matches_common_data(socket)) {
+ return false;
+ }
+ if (socket.type != SOCK_SHADER) {
+ return false;
+ }
+ return true;
+}
+
+bool Shader::can_connect(const bNodeSocket &socket) const
+{
+ if (!sockets_can_connect(*this, socket)) {
+ return false;
+ }
+ /* Basic types can convert to shaders, but not the other way around. */
+ if (in_out_ == SOCK_IN) {
+ return ELEM(socket.type, SOCK_VECTOR, SOCK_RGBA, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN);
+ }
+ return socket.type == SOCK_SHADER;
+}
+
+/** \} */
+
} // namespace blender::nodes::decl
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 5481465aef6..912d5e5322c 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -262,7 +262,6 @@ void InputSocketRef::foreach_logical_origin(
skipped_fn.call_safe(origin);
skipped_fn.call_safe(mute_input);
mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack);
- break;
}
}
}
@@ -442,9 +441,6 @@ static bool has_link_cycles_recursive(const NodeRef &node,
return false;
}
-/**
- * \return True when there is a link cycle. Unavailable sockets are ignored.
- */
bool NodeTreeRef::has_link_cycles() const
{
const int node_amount = nodes_by_id_.size();
@@ -571,10 +567,6 @@ static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direct
}
}
-/**
- * Sort nodes topologically from left to right or right to left.
- * In the future the result if this could be cached on #NodeTreeRef.
- */
NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const
{
ToposortResult result;
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 231030030eb..7620c8fa1a8 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -190,7 +190,7 @@ void node_math_update(bNodeTree *ntree, bNode *node)
/** \name Labels
* \{ */
-void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_blend_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name);
@@ -200,14 +200,14 @@ void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_image_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
/* If there is no loaded image, return an empty string,
* and let nodeLabel() fill in the proper type translation. */
BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen);
}
-void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_math_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_math_items, node->custom1, &name);
@@ -217,7 +217,10 @@ void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int max
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_vector_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
@@ -227,7 +230,7 @@ void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label,
BLI_strncpy(label, IFACE_(name), maxlen);
}
-void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
const char *name;
bool enum_label = RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name);
@@ -301,11 +304,6 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree,
return NULL;
}
-/**
- * The idea behind this is: When a user connects an input to a socket that is
- * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
- * the link that we try to overwrite and connect that previous link to the new socket.
- */
void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
bNodeSocket *socket = link->tosock;
@@ -351,11 +349,11 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
* `< 0`: never connect these types.
* `>= 0`: priority of connection (higher values chosen first).
*/
-static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype to)
+static int node_datatype_priority(const bNodeSocketType *from, const bNodeSocketType *to)
{
- switch (to) {
+ switch (to->type) {
case SOCK_RGBA:
- switch (from) {
+ switch (from->type) {
case SOCK_RGBA:
return 4;
case SOCK_FLOAT:
@@ -364,11 +362,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_BOOLEAN:
return 1;
- default:
- return -1;
}
+ return -1;
case SOCK_VECTOR:
- switch (from) {
+ switch (from->type) {
case SOCK_VECTOR:
return 4;
case SOCK_FLOAT:
@@ -377,11 +374,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_BOOLEAN:
return 1;
- default:
- return -1;
}
+ return -1;
case SOCK_FLOAT:
- switch (from) {
+ switch (from->type) {
case SOCK_FLOAT:
return 5;
case SOCK_INT:
@@ -392,11 +388,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_VECTOR:
return 1;
- default:
- return -1;
}
+ return -1;
case SOCK_INT:
- switch (from) {
+ switch (from->type) {
case SOCK_INT:
return 5;
case SOCK_FLOAT:
@@ -407,11 +402,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_VECTOR:
return 1;
- default:
- return -1;
}
+ return -1;
case SOCK_BOOLEAN:
- switch (from) {
+ switch (from->type) {
case SOCK_BOOLEAN:
return 5;
case SOCK_INT:
@@ -422,74 +416,17 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype
return 2;
case SOCK_VECTOR:
return 1;
- default:
- return -1;
- }
- case SOCK_SHADER:
- switch (from) {
- case SOCK_SHADER:
- return 1;
- default:
- return -1;
}
- case SOCK_STRING:
- switch (from) {
- case SOCK_STRING:
- return 1;
- default:
- return -1;
- }
- case SOCK_OBJECT: {
- switch (from) {
- case SOCK_OBJECT:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_GEOMETRY: {
- switch (from) {
- case SOCK_GEOMETRY:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_COLLECTION: {
- switch (from) {
- case SOCK_COLLECTION:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_TEXTURE: {
- switch (from) {
- case SOCK_TEXTURE:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_IMAGE: {
- switch (from) {
- case SOCK_IMAGE:
- return 1;
- default:
- return -1;
- }
- }
- case SOCK_MATERIAL: {
- switch (from) {
- case SOCK_MATERIAL:
- return 1;
- default:
- return -1;
- }
- }
- default:
return -1;
}
+
+ /* The rest of the socket types only allow an internal link if both the input and output socket
+ * have the same type. If the sockets are custom, we check the idname instead. */
+ if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
+ return 1;
+ }
+
+ return -1;
}
/* select a suitable input socket for an output */
@@ -505,7 +442,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
bool sel_is_linked = false;
for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
- int priority = node_datatype_priority(input->type, output->type);
+ int priority = node_datatype_priority(input->typeinfo, output->typeinfo);
bool is_linked = (input->link != NULL);
bool preferred;
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index c064ef4ab36..d7da2303088 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -23,20 +23,6 @@
#pragma once
-#include "DNA_listBase.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_node.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "NOD_socket.h"
-
-#include "GPU_material.h" /* For Shader muting GPU code... */
-
-#include "RNA_access.h"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -56,18 +42,18 @@ typedef struct bNodeExecData {
/**** Storage Data ****/
-extern void node_free_curves(struct bNode *node);
-extern void node_free_standard_storage(struct bNode *node);
+void node_free_curves(struct bNode *node);
+void node_free_standard_storage(struct bNode *node);
-extern void node_copy_curves(struct bNodeTree *dest_ntree,
- struct bNode *dest_node,
- const struct bNode *src_node);
-extern void node_copy_standard_storage(struct bNodeTree *dest_ntree,
- struct bNode *dest_node,
- const struct bNode *src_node);
-extern void *node_initexec_curves(struct bNodeExecContext *context,
- struct bNode *node,
- bNodeInstanceKey key);
+void node_copy_curves(struct bNodeTree *dest_ntree,
+ struct bNode *dest_node,
+ const struct bNode *src_node);
+void node_copy_standard_storage(struct bNodeTree *dest_ntree,
+ struct bNode *dest_node,
+ const struct bNode *src_node);
+void *node_initexec_curves(struct bNodeExecContext *context,
+ struct bNode *node,
+ bNodeInstanceKey key);
/**** Updates ****/
void node_sock_label(struct bNodeSocket *sock, const char *name);
@@ -75,13 +61,34 @@ void node_sock_label_clear(struct bNodeSocket *sock);
void node_math_update(struct bNodeTree *ntree, struct bNode *node);
/**** Labels ****/
-void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_vector_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+void node_blend_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_image_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_math_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_vector_math_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
+void node_filter_label(const struct bNodeTree *ntree,
+ const struct bNode *node,
+ char *label,
+ int maxlen);
/*** Link Handling */
+
+/**
+ * The idea behind this is: When a user connects an input to a socket that is
+ * already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
+ * the link that we try to overwrite and connect that previous link to the new socket.
+ */
void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
diff --git a/source/blender/nodes/intern/socket_search_link.cc b/source/blender/nodes/intern/socket_search_link.cc
new file mode 100644
index 00000000000..8543efe7f9b
--- /dev/null
+++ b/source/blender/nodes/intern/socket_search_link.cc
@@ -0,0 +1,199 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_set.hh"
+
+#include "BKE_node.h"
+
+#include "UI_interface.h"
+
+#include "NOD_node_declaration.hh"
+#include "NOD_socket_search_link.hh"
+
+namespace blender::nodes {
+
+void GatherLinkSearchOpParams::add_item(std::string socket_name,
+ SocketLinkOperation::LinkSocketFn fn,
+ const int weight)
+{
+
+ std::string name = std::string(node_type_.ui_name) + " " + UI_MENU_ARROW_SEP + socket_name;
+
+ items_.append({std::move(name), std::move(fn), weight});
+}
+
+const bNodeSocket &GatherLinkSearchOpParams::other_socket() const
+{
+ return other_socket_;
+}
+
+const bNodeTree &GatherLinkSearchOpParams::node_tree() const
+{
+ return node_tree_;
+}
+
+const bNodeType &GatherLinkSearchOpParams::node_type() const
+{
+ return node_type_;
+}
+
+eNodeSocketInOut GatherLinkSearchOpParams::in_out() const
+{
+ return other_socket_.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN;
+}
+
+void LinkSearchOpParams::connect_available_socket(bNode &new_node, StringRef socket_name)
+{
+ const eNodeSocketInOut in_out = socket.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN;
+ bNodeSocket *new_node_socket = bke::node_find_enabled_socket(new_node, in_out, socket_name);
+ if (new_node_socket == nullptr) {
+ /* If the socket isn't found, some node's search gather functions probably aren't configured
+ * properly. It's likely enough that it's worth avoiding a crash in a release build though. */
+ BLI_assert_unreachable();
+ return;
+ }
+ nodeAddLink(&node_tree, &new_node, new_node_socket, &node, &socket);
+}
+
+bNode &LinkSearchOpParams::add_node(StringRef idname)
+{
+ std::string idname_str = idname;
+ bNode *node = nodeAddNode(&C, &node_tree, idname_str.c_str());
+ BLI_assert(node != nullptr);
+ added_nodes_.append(node);
+ return *node;
+}
+
+bNode &LinkSearchOpParams::add_node(const bNodeType &node_type)
+{
+ return this->add_node(node_type.idname);
+}
+
+void LinkSearchOpParams::update_and_connect_available_socket(bNode &new_node,
+ StringRef socket_name)
+{
+ if (new_node.typeinfo->updatefunc) {
+ new_node.typeinfo->updatefunc(&node_tree, &new_node);
+ }
+ this->connect_available_socket(new_node, socket_name);
+}
+
+void search_link_ops_for_declarations(GatherLinkSearchOpParams &params,
+ Span<SocketDeclarationPtr> declarations)
+{
+ const bNodeType &node_type = params.node_type();
+
+ const SocketDeclaration *main_socket = nullptr;
+ Vector<const SocketDeclaration *> connectable_sockets;
+
+ Set<StringRef> socket_names;
+ for (const int i : declarations.index_range()) {
+ const SocketDeclaration &socket = *declarations[i];
+ if (!socket_names.add(socket.name())) {
+ /* Don't add sockets with the same name to the search. Needed to support being called from
+ * #search_link_ops_for_basic_node, which should have "okay" behavior for nodes with
+ * duplicate socket names. */
+ continue;
+ }
+ if (!socket.can_connect(params.other_socket())) {
+ continue;
+ }
+ if (socket.is_default_link_socket() || main_socket == nullptr) {
+ /* Either the first connectable or explicitly tagged socket is the main socket. */
+ main_socket = &socket;
+ }
+ connectable_sockets.append(&socket);
+ }
+ for (const int i : connectable_sockets.index_range()) {
+ const SocketDeclaration &socket = *connectable_sockets[i];
+ /* Give non-main sockets a lower weight so that they don't show up at the top of the search
+ * when they are not explicitly searched for. The -1 is used to make sure that the first socket
+ * has a smaller weight than zero so that it does not have the same weight as the main socket.
+ * Negative weights are used to avoid making the highest weight dependent on the number of
+ * sockets. */
+ const int weight = (&socket == main_socket) ? 0 : -1 - i;
+ params.add_item(
+ socket.name(),
+ [&node_type, &socket](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ socket.make_available(node);
+ params.update_and_connect_available_socket(node, socket.name());
+ },
+ weight);
+ }
+}
+
+static void search_link_ops_for_socket_templates(GatherLinkSearchOpParams &params,
+ const bNodeSocketTemplate *templates,
+ const eNodeSocketInOut in_out)
+{
+ const bNodeType &node_type = params.node_type();
+ const bNodeTreeType &node_tree_type = *params.node_tree().typeinfo;
+
+ Set<StringRef> socket_names;
+ for (const bNodeSocketTemplate *socket_template = templates; socket_template->type != -1;
+ socket_template++) {
+ eNodeSocketDatatype from = (eNodeSocketDatatype)socket_template->type;
+ eNodeSocketDatatype to = (eNodeSocketDatatype)params.other_socket().type;
+ if (in_out == SOCK_IN) {
+ std::swap(from, to);
+ }
+ if (node_tree_type.validate_link && !node_tree_type.validate_link(from, to)) {
+ continue;
+ }
+ if (!socket_names.add(socket_template->name)) {
+ /* See comment in #search_link_ops_for_declarations. */
+ continue;
+ }
+
+ params.add_item(
+ socket_template->name, [socket_template, node_type, in_out](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ bNodeSocket *new_node_socket = bke::node_find_enabled_socket(
+ node, in_out, socket_template->name);
+ if (new_node_socket != nullptr) {
+ /* Rely on the way #nodeAddLink switches in/out if necessary. */
+ nodeAddLink(&params.node_tree, &params.node, &params.socket, &node, new_node_socket);
+ }
+ });
+ }
+}
+
+void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params)
+{
+ const bNodeType &node_type = params.node_type();
+
+ if (node_type.declare) {
+ if (node_type.declaration_is_dynamic) {
+ /* Dynamic declarations (whatever they end up being) aren't supported
+ * by this function, but still avoid a crash in release builds. */
+ BLI_assert_unreachable();
+ return;
+ }
+
+ const NodeDeclaration &declaration = *node_type.fixed_declaration;
+
+ search_link_ops_for_declarations(params, declaration.sockets(params.in_out()));
+ }
+ else if (node_type.inputs && params.in_out() == SOCK_IN) {
+ search_link_ops_for_socket_templates(params, node_type.inputs, SOCK_IN);
+ }
+ else if (node_type.outputs && params.in_out() == SOCK_OUT) {
+ search_link_ops_for_socket_templates(params, node_type.outputs, SOCK_OUT);
+ }
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
new file mode 100644
index 00000000000..7d99c233197
--- /dev/null
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -0,0 +1,166 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../
+ ../intern
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../functions
+ ../../gpu
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/sky/include
+)
+
+
+set(SRC
+ nodes/node_shader_add_shader.c
+ nodes/node_shader_ambient_occlusion.c
+ nodes/node_shader_attribute.c
+ nodes/node_shader_background.c
+ nodes/node_shader_bevel.c
+ nodes/node_shader_blackbody.c
+ nodes/node_shader_brightness.c
+ nodes/node_shader_bsdf_anisotropic.c
+ nodes/node_shader_bsdf_diffuse.c
+ nodes/node_shader_bsdf_glass.c
+ nodes/node_shader_bsdf_glossy.c
+ nodes/node_shader_bsdf_hair.c
+ nodes/node_shader_bsdf_hair_principled.c
+ nodes/node_shader_bsdf_principled.c
+ nodes/node_shader_bsdf_refraction.c
+ nodes/node_shader_bsdf_toon.c
+ nodes/node_shader_bsdf_translucent.c
+ nodes/node_shader_bsdf_transparent.c
+ nodes/node_shader_bsdf_velvet.c
+ nodes/node_shader_bump.c
+ nodes/node_shader_camera.c
+ nodes/node_shader_clamp.cc
+ nodes/node_shader_common.c
+ nodes/node_shader_curves.cc
+ nodes/node_shader_displacement.c
+ nodes/node_shader_eevee_specular.c
+ nodes/node_shader_emission.c
+ nodes/node_shader_fresnel.c
+ nodes/node_shader_gamma.c
+ nodes/node_shader_geometry.c
+ nodes/node_shader_hair_info.c
+ nodes/node_shader_holdout.c
+ nodes/node_shader_hueSatVal.c
+ nodes/node_shader_ies_light.c
+ nodes/node_shader_invert.c
+ nodes/node_shader_layer_weight.c
+ nodes/node_shader_light_falloff.c
+ nodes/node_shader_light_path.c
+ nodes/node_shader_map_range.cc
+ nodes/node_shader_mapping.c
+ nodes/node_shader_math.cc
+ nodes/node_shader_mix_rgb.cc
+ nodes/node_shader_mix_shader.c
+ nodes/node_shader_normal.c
+ nodes/node_shader_normal_map.c
+ nodes/node_shader_object_info.c
+ nodes/node_shader_output_aov.c
+ nodes/node_shader_output_light.c
+ nodes/node_shader_output_linestyle.c
+ nodes/node_shader_output_material.c
+ nodes/node_shader_output_world.c
+ nodes/node_shader_particle_info.c
+ nodes/node_shader_rgb_to_bw.cc
+ nodes/node_shader_rgb.c
+ nodes/node_shader_script.c
+ nodes/node_shader_sepcomb_hsv.c
+ nodes/node_shader_sepcomb_rgb.cc
+ nodes/node_shader_sepcomb_xyz.cc
+ nodes/node_shader_shader_to_rgb.c
+ nodes/node_shader_squeeze.c
+ nodes/node_shader_subsurface_scattering.c
+ nodes/node_shader_tangent.c
+ nodes/node_shader_tex_brick.cc
+ nodes/node_shader_tex_checker.cc
+ nodes/node_shader_tex_coord.c
+ nodes/node_shader_tex_environment.c
+ nodes/node_shader_tex_gradient.cc
+ nodes/node_shader_tex_image.cc
+ nodes/node_shader_tex_magic.cc
+ nodes/node_shader_tex_musgrave.cc
+ nodes/node_shader_tex_noise.cc
+ nodes/node_shader_tex_pointdensity.c
+ nodes/node_shader_tex_sky.c
+ nodes/node_shader_tex_voronoi.cc
+ nodes/node_shader_tex_wave.cc
+ nodes/node_shader_tex_white_noise.cc
+ nodes/node_shader_uv_along_stroke.c
+ nodes/node_shader_uvmap.c
+ nodes/node_shader_value.cc
+ nodes/node_shader_vector_displacement.c
+ nodes/node_shader_vector_math.cc
+ nodes/node_shader_vector_rotate.cc
+ nodes/node_shader_vector_transform.c
+ nodes/node_shader_vertex_color.c
+ nodes/node_shader_volume_absorption.c
+ nodes/node_shader_volume_info.c
+ nodes/node_shader_volume_principled.c
+ nodes/node_shader_volume_scatter.c
+ nodes/node_shader_wavelength.c
+ nodes/node_shader_wireframe.c
+
+ node_shader_tree.c
+ node_shader_util.cc
+
+ node_shader_util.h
+)
+
+set(LIB
+ bf_functions
+ bf_intern_sky
+)
+
+if(WITH_PYTHON)
+ list(APPEND INC
+ ../../python
+ )
+ list(APPEND INC_SYS
+ ${PYTHON_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${PYTHON_LINKFLAGS}
+ ${PYTHON_LIBRARIES}
+ )
+ add_definitions(-DWITH_PYTHON)
+endif()
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
+blender_add_lib(bf_nodes_shader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 83ee0c2f411..c3b5236373c 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -139,12 +139,8 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
{
- bNode *node, *node_next;
-
/* replace muted nodes and reroute nodes by internal links */
- for (node = localtree->nodes.first; node; node = node_next) {
- node_next = node->next;
-
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &localtree->nodes) {
if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) {
nodeInternalRelink(localtree, node);
ntreeFreeLocalNode(localtree, node);
@@ -174,12 +170,12 @@ static void update(bNodeTree *ntree)
}
}
-static bool shader_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link)
+static bool shader_validate_link(eNodeSocketDatatype from, eNodeSocketDatatype to)
{
/* Can't connect shader into other socket types, other way around is fine
* since it will be interpreted as emission. */
- if (link->fromsock->type == SOCK_SHADER) {
- return (link->tosock->type == SOCK_SHADER);
+ if (from == SOCK_SHADER) {
+ return to == SOCK_SHADER;
}
return true;
}
@@ -221,13 +217,6 @@ void register_node_tree_type_sh(void)
/* GPU material from shader nodes */
-/* Find an output node of the shader tree.
- *
- * NOTE: it will only return output which is NOT in the group, which isn't how
- * render engines works but it's how the GPU shader compilation works. This we
- * can change in the future and make it a generic function, but for now it stays
- * private here.
- */
bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
{
/* Make sure we only have single node tagged as output. */
@@ -887,7 +876,6 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag
nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0);
}
-/* This one needs to work on a local tree. */
void ntreeGPUMaterialNodes(bNodeTree *localtree,
GPUMaterial *mat,
bool *has_surface_output,
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.cc
index e1f6c135568..f2464d4c1b4 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -25,12 +25,14 @@
#include "node_shader_util.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_exec.h"
bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree, const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "ShaderNodeTree")) {
- *r_disabled_hint = "Not a shader node tree";
+ *r_disabled_hint = TIP_("Not a shader node tree");
return false;
}
return true;
@@ -41,7 +43,7 @@ static bool sh_fn_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STR_ELEM(ntree->idname, "ShaderNodeTree", "GeometryNodeTree")) {
- *r_disabled_hint = "Not a shader or geometry node tree";
+ *r_disabled_hint = TIP_("Not a shader or geometry node tree");
return false;
}
return true;
@@ -54,12 +56,14 @@ void sh_node_type_base(
ntype->poll = sh_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
sh_node_type_base(ntype, type, name, nclass, flag);
ntype->poll = sh_fn_poll_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
/* ****** */
@@ -107,11 +111,11 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
{
memset(gs, 0, sizeof(*gs));
- if (ns == NULL) {
- /* node_get_stack() will generate NULL bNodeStack pointers
+ if (ns == nullptr) {
+ /* node_get_stack() will generate nullptr bNodeStack pointers
* for unknown/unsupported types of sockets. */
zero_v4(gs->vec);
- gs->link = NULL;
+ gs->link = nullptr;
gs->type = GPU_NONE;
gs->hasinput = false;
gs->hasoutput = false;
@@ -119,7 +123,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
}
else {
nodestack_get_vec(gs->vec, type, ns);
- gs->link = ns->data;
+ gs->link = (GPUNodeLink *)ns->data;
if (type == SOCK_FLOAT) {
gs->type = GPU_FLOAT;
@@ -159,11 +163,9 @@ void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
{
- bNodeSocket *sock;
int i;
-
- for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) {
- node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
+ node_gpu_stack_from_data(&gs[i], socket->type, ns[i]);
}
gs[i].end = true;
@@ -171,10 +173,8 @@ static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeS
static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
{
- bNodeSocket *sock;
int i;
-
- for (sock = sockets->first, i = 0; sock; sock = sock->next, i++) {
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, i) {
node_data_from_gpu_stack(ns[i], &gs[i]);
}
}
@@ -182,14 +182,14 @@ static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNode
bNode *nodeGetActiveTexture(bNodeTree *ntree)
{
/* this is the node we texture paint and draw in textured draw */
- bNode *node, *tnode, *inactivenode = NULL, *activetexnode = NULL, *activegroup = NULL;
+ bNode *inactivenode = nullptr, *activetexnode = nullptr, *activegroup = nullptr;
bool hasgroup = false;
if (!ntree) {
- return NULL;
+ return nullptr;
}
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_ACTIVE_TEXTURE) {
activetexnode = node;
/* if active we can return immediately */
@@ -212,7 +212,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
/* first, check active group for textures */
if (activegroup) {
- tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
+ bNode *tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
/* active node takes priority, so ignore any other possible nodes here */
if (tnode) {
return tnode;
@@ -225,9 +225,9 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
if (hasgroup) {
/* node active texture node in this tree, look inside groups */
- for (node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == NODE_GROUP) {
- tnode = nodeGetActiveTexture((bNodeTree *)node->id);
+ bNode *tnode = nodeGetActiveTexture((bNodeTree *)node->id);
if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode)) {
return tnode;
}
@@ -257,7 +257,7 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
do_it = false;
/* for groups, only execute outputs for edited group */
if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
- if ((output_node != NULL) && (node == output_node)) {
+ if ((output_node != nullptr) && (node == output_node)) {
do_it = true;
}
}
@@ -281,11 +281,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
{
if (node->branch_tag == 1) {
- /* Add one time the value fo derivative to the input vector. */
+ /* Add one time the value for derivative to the input vector. */
GPU_link(mat, "dfdx_v3", *link, link);
}
else if (node->branch_tag == 2) {
- /* Add one time the value fo derivative to the input vector. */
+ /* Add one time the value for derivative to the input vector. */
GPU_link(mat, "dfdy_v3", *link, link);
}
else {
@@ -307,7 +307,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *UNUSED(out))
{
- NodeTexBase *base = node->storage;
+ NodeTexBase *base = (NodeTexBase *)node->storage;
TexMapping *texmap = &base->tex_mapping;
float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index 89b7164693f..b9f4106c79a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -169,17 +169,16 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock;
- int distribution = node->custom1;
- int sss_method = node->custom2;
+ const int distribution = node->custom1;
+ const int sss_method = node->custom2;
- for (sock = node->inputs.first; sock; sock = sock->next) {
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
if (STREQ(sock->name, "Transmission Roughness")) {
nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX);
}
if (STR_ELEM(sock->name, "Subsurface IOR", "Subsurface Anisotropy")) {
- nodeSetSocketAvailability(ntree, sock, sss_method == SHD_SUBSURFACE_BURLEY);
+ nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY);
}
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index 57a992a4275..6c3457151e5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -75,7 +75,7 @@ static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunction
}
}
-void register_node_type_sh_clamp(void)
+void register_node_type_sh_clamp()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index a1dac05434e..190e0cfad4c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -232,7 +232,7 @@ void register_node_type_sh_group(void)
/* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type
* to the shared #NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
+ node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, 0);
ntype.type = NODE_GROUP;
ntype.poll = sh_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -243,7 +243,7 @@ void register_node_type_sh_group(void)
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
node_type_gpu(&ntype, gpu_group_execute);
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index 7ce5150bf85..09bbf3d851c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -152,7 +152,7 @@ static void sh_node_curve_vec_build_multi_function(
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
}
-void register_node_type_sh_curve_vec(void)
+void register_node_type_sh_curve_vec()
{
static bNodeType ntype;
@@ -329,7 +329,7 @@ static void sh_node_curve_rgb_build_multi_function(
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
}
-void register_node_type_sh_curve_rgb(void)
+void register_node_type_sh_curve_rgb()
{
static bNodeType ntype;
@@ -473,7 +473,7 @@ static void sh_node_curve_float_build_multi_function(
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
}
-void register_node_type_sh_curve_float(void)
+void register_node_type_sh_curve_float()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index e55963eb500..615ae276eb4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -21,10 +21,14 @@
* \ingroup shdnodes
*/
+#include <algorithm>
+
#include "node_shader_util.h"
#include "BLI_math_base_safe.h"
+NODE_STORAGE_FUNCS(NodeMapRange)
+
namespace blender::nodes {
static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
@@ -36,34 +40,80 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("To Min")).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>(N_("To Max")).min(-10000.0f).max(10000.0f).default_value(1.0f);
b.add_input<decl::Float>(N_("Steps")).min(-10000.0f).max(10000.0f).default_value(4.0f);
+ b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value();
+ b.add_input<decl::Vector>(N_("From Min"), "From_Min_FLOAT3");
+ b.add_input<decl::Vector>(N_("From Max"), "From_Max_FLOAT3").default_value(float3(1.0f));
+ b.add_input<decl::Vector>(N_("To Min"), "To_Min_FLOAT3");
+ b.add_input<decl::Vector>(N_("To Max"), "To_Max_FLOAT3").default_value(float3(1.0f));
+ b.add_input<decl::Vector>(N_("Steps"), "Steps_FLOAT3").default_value(float3(4.0f));
b.add_output<decl::Float>(N_("Result"));
+ b.add_output<decl::Vector>(N_("Vector"));
};
} // namespace blender::nodes
static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps");
- nodeSetSocketAvailability(ntree, sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED);
+ const NodeMapRange &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const int type = (data_type == CD_PROP_FLOAT) ? SOCK_FLOAT : SOCK_VECTOR;
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == type);
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ nodeSetSocketAvailability(ntree, socket, socket->type == type);
+ }
+
+ if (storage.interpolation_type != NODE_MAP_RANGE_STEPPED) {
+ if (type == SOCK_FLOAT) {
+ bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 5);
+ nodeSetSocketAvailability(ntree, sockSteps, false);
+ }
+ else {
+ bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 11);
+ nodeSetSocketAvailability(ntree, sockSteps, false);
+ }
+ }
}
static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
{
+ NodeMapRange *data = (NodeMapRange *)MEM_callocN(sizeof(NodeMapRange), __func__);
+ data->clamp = 1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = NODE_MAP_RANGE_LINEAR;
node->custom1 = true; /* use_clamp */
node->custom2 = NODE_MAP_RANGE_LINEAR; /* interpolation */
+ node->storage = data;
}
-static const char *gpu_shader_get_name(int mode)
+static const char *gpu_shader_get_name(int mode, bool use_vector)
{
- switch (mode) {
- case NODE_MAP_RANGE_LINEAR:
- return "map_range_linear";
- case NODE_MAP_RANGE_STEPPED:
- return "map_range_stepped";
- case NODE_MAP_RANGE_SMOOTHSTEP:
- return "map_range_smoothstep";
- case NODE_MAP_RANGE_SMOOTHERSTEP:
- return "map_range_smootherstep";
+ if (use_vector) {
+ switch (mode) {
+ case NODE_MAP_RANGE_LINEAR:
+ return "vector_map_range_linear";
+ case NODE_MAP_RANGE_STEPPED:
+ return "vector_map_range_stepped";
+ case NODE_MAP_RANGE_SMOOTHSTEP:
+ return "vector_map_range_smoothstep";
+ case NODE_MAP_RANGE_SMOOTHERSTEP:
+ return "vector_map_range_smootherstep";
+ }
+ }
+ else {
+ switch (mode) {
+ case NODE_MAP_RANGE_LINEAR:
+ return "map_range_linear";
+ case NODE_MAP_RANGE_STEPPED:
+ return "map_range_stepped";
+ case NODE_MAP_RANGE_SMOOTHSTEP:
+ return "map_range_smoothstep";
+ case NODE_MAP_RANGE_SMOOTHERSTEP:
+ return "map_range_smootherstep";
+ }
}
return nullptr;
@@ -75,22 +125,207 @@ static int gpu_shader_map_range(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- const char *name = gpu_shader_get_name(node->custom2);
-
+ const NodeMapRange &storage = node_storage(*node);
+ bool use_vector = (storage.data_type == CD_PROP_FLOAT3);
+ const char *name = gpu_shader_get_name(storage.interpolation_type, use_vector);
+ float clamp = storage.clamp ? 1.0f : 0.0f;
int ret = 0;
if (name != nullptr) {
- ret = GPU_stack_link(mat, node, name, in, out);
+ ret = GPU_stack_link(mat, node, name, in, out, GPU_constant(&clamp));
}
else {
- ret = GPU_stack_link(mat, node, "map_range_linear", in, out);
+ ret = GPU_stack_link(mat, node, "map_range_linear", in, out, GPU_constant(&clamp));
}
- if (ret && node->custom1 &&
- !ELEM(node->custom2, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) {
+ if (ret && storage.clamp && !use_vector &&
+ !ELEM(storage.interpolation_type, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) {
GPU_link(mat, "clamp_range", out[0].link, in[3].link, in[4].link, &out[0].link);
}
return ret;
}
+namespace blender::nodes {
+
+static inline float clamp_range(const float value, const float min, const float max)
+{
+ return (min > max) ? std::clamp(value, max, min) : std::clamp(value, min, max);
+}
+
+static float3 clamp_range(const float3 value, const float3 min, const float3 max)
+{
+ return float3(clamp_range(value.x, min.x, max.x),
+ clamp_range(value.y, min.y, max.y),
+ clamp_range(value.z, min.z, max.z));
+}
+
+static void map_range_vector_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
+{
+ signature->single_input<float3>("Vector");
+ signature->single_input<float3>("From Min");
+ signature->single_input<float3>("From Max");
+ signature->single_input<float3>("To Min");
+ signature->single_input<float3>("To Max");
+ if (use_steps) {
+ signature->single_input<float3>("Steps");
+ }
+ signature->single_output<float3>("Vector");
+}
+
+class MapRangeVectorFunction : public blender::fn::MultiFunction {
+ private:
+ bool clamp_;
+
+ public:
+ MapRangeVectorFunction(bool clamp) : clamp_(clamp)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+
+ if (clamp_) {
+ for (int64_t i : mask) {
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
+ }
+ }
+ }
+};
+
+class MapRangeSteppedVectorFunction : public blender::fn::MultiFunction {
+ private:
+ bool clamp_;
+
+ public:
+ MapRangeSteppedVectorFunction(bool clamp) : clamp_(clamp)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Stepped"};
+ map_range_vector_signature(&signature, true);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ const blender::VArray<float3> &steps = params.readonly_single_input<float3>(5, "Steps");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(6, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ factor = float3::safe_divide(float3::floor(factor * (steps[i] + 1.0f)), steps[i]);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+
+ if (clamp_) {
+ for (int64_t i : mask) {
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
+ }
+ }
+ }
+};
+
+class MapRangeSmoothstepVectorFunction : public blender::fn::MultiFunction {
+ public:
+ MapRangeSmoothstepVectorFunction()
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ clamp_v3(factor, 0.0f, 1.0f);
+ factor = (float3(3.0f) - 2.0f * factor) * (factor * factor);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+ }
+};
+
+class MapRangeSmootherstepVectorFunction : public blender::fn::MultiFunction {
+ public:
+ MapRangeSmootherstepVectorFunction()
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"};
+ map_range_vector_signature(&signature, false);
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
+
+ for (int64_t i : mask) {
+ float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ clamp_v3(factor, 0.0f, 1.0f);
+ factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
+ results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
+ }
+ }
+};
+
static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
{
signature->single_input<float>("Value");
@@ -140,8 +375,7 @@ class MapRangeFunction : public blender::fn::MultiFunction {
if (clamp_) {
for (int64_t i : mask) {
- results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
- clamp_f(results[i], to_min[i], to_max[i]);
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
}
}
}
@@ -185,8 +419,7 @@ class MapRangeSteppedFunction : public blender::fn::MultiFunction {
if (clamp_) {
for (int64_t i : mask) {
- results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) :
- clamp_f(results[i], to_min[i], to_max[i]);
+ results[i] = clamp_range(results[i], to_min[i], to_max[i]);
}
}
}
@@ -265,58 +498,104 @@ class MapRangeSmootherstepFunction : public blender::fn::MultiFunction {
static void sh_node_map_range_build_multi_function(
blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.node();
- bool clamp = bnode.custom1 != 0;
- int interpolation_type = bnode.custom2;
-
- switch (interpolation_type) {
- case NODE_MAP_RANGE_LINEAR: {
- if (clamp) {
- static MapRangeFunction fn_with_clamp{true};
- builder.set_matching_fn(fn_with_clamp);
- }
- else {
- static MapRangeFunction fn_without_clamp{false};
- builder.set_matching_fn(fn_without_clamp);
+ const NodeMapRange &storage = node_storage(builder.node());
+ bool clamp = storage.clamp != 0;
+ int interpolation_type = storage.interpolation_type;
+
+ switch (storage.data_type) {
+ case CD_PROP_FLOAT3:
+ switch (interpolation_type) {
+ case NODE_MAP_RANGE_LINEAR: {
+ if (clamp) {
+ static MapRangeVectorFunction fn_with_clamp{true};
+ builder.set_matching_fn(fn_with_clamp);
+ }
+ else {
+ static MapRangeVectorFunction fn_without_clamp{false};
+ builder.set_matching_fn(fn_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_STEPPED: {
+ if (clamp) {
+ static MapRangeSteppedVectorFunction fn_stepped_with_clamp{true};
+ builder.set_matching_fn(fn_stepped_with_clamp);
+ }
+ else {
+ static MapRangeSteppedVectorFunction fn_stepped_without_clamp{false};
+ builder.set_matching_fn(fn_stepped_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ static MapRangeSmoothstepVectorFunction smoothstep;
+ builder.set_matching_fn(smoothstep);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ static MapRangeSmootherstepVectorFunction smootherstep;
+ builder.set_matching_fn(smootherstep);
+ break;
+ }
+ default:
+ break;
}
break;
- }
- case NODE_MAP_RANGE_STEPPED: {
- if (clamp) {
- static MapRangeSteppedFunction fn_stepped_with_clamp{true};
- builder.set_matching_fn(fn_stepped_with_clamp);
- }
- else {
- static MapRangeSteppedFunction fn_stepped_without_clamp{false};
- builder.set_matching_fn(fn_stepped_without_clamp);
+ case CD_PROP_FLOAT:
+ switch (interpolation_type) {
+ case NODE_MAP_RANGE_LINEAR: {
+ if (clamp) {
+ static MapRangeFunction fn_with_clamp{true};
+ builder.set_matching_fn(fn_with_clamp);
+ }
+ else {
+ static MapRangeFunction fn_without_clamp{false};
+ builder.set_matching_fn(fn_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_STEPPED: {
+ if (clamp) {
+ static MapRangeSteppedFunction fn_stepped_with_clamp{true};
+ builder.set_matching_fn(fn_stepped_with_clamp);
+ }
+ else {
+ static MapRangeSteppedFunction fn_stepped_without_clamp{false};
+ builder.set_matching_fn(fn_stepped_without_clamp);
+ }
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHSTEP: {
+ static MapRangeSmoothstepFunction smoothstep;
+ builder.set_matching_fn(smoothstep);
+ break;
+ }
+ case NODE_MAP_RANGE_SMOOTHERSTEP: {
+ static MapRangeSmootherstepFunction smootherstep;
+ builder.set_matching_fn(smootherstep);
+ break;
+ }
+ default:
+ break;
}
break;
- }
- case NODE_MAP_RANGE_SMOOTHSTEP: {
- static MapRangeSmoothstepFunction smoothstep;
- builder.set_matching_fn(smoothstep);
- break;
- }
- case NODE_MAP_RANGE_SMOOTHERSTEP: {
- static MapRangeSmootherstepFunction smootherstep;
- builder.set_matching_fn(smootherstep);
- break;
- }
- default:
- break;
}
}
-void register_node_type_sh_map_range(void)
+} // namespace blender::nodes
+
+void register_node_type_sh_map_range()
{
static bNodeType ntype;
sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::sh_node_map_range_declare;
node_type_init(&ntype, node_shader_init_map_range);
+ node_type_storage(
+ &ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage);
node_type_update(&ntype, node_shader_update_map_range);
node_type_gpu(&ntype, gpu_shader_map_range);
- ntype.build_multi_function = sh_node_map_range_build_multi_function;
+ ntype.build_multi_function = blender::nodes::sh_node_map_range_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index 284a5f1189f..da237be273f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -24,6 +24,7 @@
#include "node_shader_util.h"
#include "NOD_math_functions.hh"
+#include "NOD_socket_search_link.hh"
/* **************** SCALAR MATH ******************** */
@@ -44,6 +45,18 @@ static void sh_node_math_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
};
+static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ /* For now, do something very basic (only exposing "Add", and a single "Value" socket). */
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Value"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeMath");
+ params.update_and_connect_available_socket(node, "Value");
+ });
+ }
+}
+
} // namespace blender::nodes
static const char *gpu_shader_get_name(int mode)
@@ -88,7 +101,8 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(),
+ function};
base_fn = &fn;
});
if (base_fn != nullptr) {
@@ -97,7 +111,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name,
+ static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name.c_str(),
function};
base_fn = &fn;
});
@@ -108,7 +122,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl(
mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
base_fn = &fn;
});
if (base_fn != nullptr) {
@@ -160,16 +174,17 @@ static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionB
}
}
-void register_node_type_sh_math(void)
+void register_node_type_sh_math()
{
static bNodeType ntype;
sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::sh_node_math_declare;
- node_type_label(&ntype, node_math_label);
+ ntype.labelfunc = node_math_label;
node_type_gpu(&ntype, gpu_shader_math);
node_type_update(&ntype, node_math_update);
ntype.build_multi_function = sh_node_math_build_multi_function;
+ ntype.gather_link_search_ops = blender::nodes::sh_node_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
index 06fafff578e..b89e0527eed 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -183,13 +183,13 @@ static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
}
-void register_node_type_sh_mix_rgb(void)
+void register_node_type_sh_mix_rgb()
{
static bNodeType ntype;
sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
ntype.declare = blender::nodes::sh_node_mix_rgb_declare;
- node_type_label(&ntype, node_blend_label);
+ ntype.labelfunc = node_blend_label;
node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb);
node_type_gpu(&ntype, gpu_shader_mix_rgb);
ntype.build_multi_function = sh_node_mix_rgb_build_multi_function;
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
index e4f1b2c76f0..e3808985c0e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
@@ -172,7 +172,7 @@ static void sh_node_valtorgb_build_multi_function(
builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
}
-void register_node_type_sh_valtorgb(void)
+void register_node_type_sh_valtorgb()
{
static bNodeType ntype;
@@ -222,7 +222,7 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat,
return GPU_stack_link(mat, node, "rgbtobw", in, out);
}
-void register_node_type_sh_rgbtobw(void)
+void register_node_type_sh_rgbtobw()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c
index dfecb830b35..dfecb830b35 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 08a9e01786e..4984a530d8b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -103,7 +103,7 @@ static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(fn);
}
-void register_node_type_sh_seprgb(void)
+void register_node_type_sh_seprgb()
{
static bNodeType ntype;
@@ -163,7 +163,7 @@ static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
-void register_node_type_sh_combrgb(void)
+void register_node_type_sh_combrgb()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
index 1bbfa629462..a414630829e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
@@ -88,7 +88,7 @@ static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(separate_fn);
}
-void register_node_type_sh_sepxyz(void)
+void register_node_type_sh_sepxyz()
{
static bNodeType ntype;
@@ -129,7 +129,7 @@ static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
-void register_node_type_sh_combxyz(void)
+void register_node_type_sh_combxyz()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c
index 25c30aa4081..25c30aa4081 100644
--- a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index e917858e0f2..85a4a6aa425 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -67,6 +67,17 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
mat, node, "node_subsurface_scattering", in, out, GPU_constant(&node->sss_id));
}
+static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *node)
+{
+ const int sss_method = node->custom1;
+
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ if (STR_ELEM(sock->name, "IOR", "Anisotropy")) {
+ nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY);
+ }
+ }
+}
+
/* node type definition */
void register_node_type_sh_subsurface_scattering(void)
{
@@ -80,6 +91,7 @@ void register_node_type_sh_subsurface_scattering(void)
node_type_init(&ntype, node_shader_init_subsurface_scattering);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_subsurface_scattering);
+ node_type_update(&ntype, node_shader_update_subsurface_scattering);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
index b840bd75e42..7925c96db3d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
@@ -268,7 +268,7 @@ static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunction
} // namespace blender::nodes
-void register_node_type_sh_tex_brick(void)
+void register_node_type_sh_tex_brick()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
index 7c1223a6a32..6d2d199aec8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
@@ -123,7 +123,7 @@ static void sh_node_tex_checker_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_checker(void)
+void register_node_type_sh_tex_checker()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 26a1db1f3a6..ff08961b3e9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -143,7 +143,7 @@ void register_node_type_sh_tex_environment(void)
node_type_storage(
&ntype, "NodeTexEnvironment", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_environment);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
index 33832c42b3c..48199968547 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
@@ -160,7 +160,7 @@ static void sh_node_gradient_tex_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_gradient(void)
+void register_node_type_sh_tex_gradient()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
index f20fc85cbe0..d139707c6d7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -174,7 +174,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
}
/* node type definition */
-void register_node_type_sh_tex_image(void)
+void register_node_type_sh_tex_image()
{
static bNodeType ntype;
@@ -184,7 +184,7 @@ void register_node_type_sh_tex_image(void)
node_type_storage(
&ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_image);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
index 62e68d53d03..9bd5c335cee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
@@ -181,7 +181,7 @@ static void sh_node_magic_tex_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_magic(void)
+void register_node_type_sh_tex_magic()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
index e426d9cc49c..97ac199bc03 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -21,13 +21,18 @@
#include "BLI_noise.hh"
+NODE_STORAGE_FUNCS(NodeTexMusgrave)
+
namespace blender::nodes {
static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
- b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f);
b.add_input<decl::Float>(N_("Dimension")).min(0.0f).max(1000.0f).default_value(2.0f);
@@ -106,23 +111,23 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat,
static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node)
{
- NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+ const NodeTexMusgrave &storage = node_storage(*node);
bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset");
bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain");
- nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1);
- nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(ntree, inVectorSock, storage.dimensions != 1);
+ nodeSetSocketAvailability(ntree, inWSock, storage.dimensions == 1 || storage.dimensions == 4);
nodeSetSocketAvailability(ntree,
inOffsetSock,
- tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
- tex->musgrave_type != SHD_MUSGRAVE_FBM);
+ storage.musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
+ storage.musgrave_type != SHD_MUSGRAVE_FBM);
nodeSetSocketAvailability(ntree,
inGainSock,
- tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
- tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
+ storage.musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
+ storage.musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
bNodeSocket *outFacSock = nodeFindSocket(node, SOCK_OUT, "Fac");
node_sock_label(outFacSock, "Height");
@@ -531,7 +536,7 @@ static void sh_node_musgrave_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_musgrave(void)
+void register_node_type_sh_tex_musgrave()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
index 7dd2695ecf7..d7f21853a01 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -21,13 +21,18 @@
#include "BLI_noise.hh"
+NODE_STORAGE_FUNCS(NodeTexNoise)
+
namespace blender::nodes {
static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).implicit_field();
- b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>(N_("Detail")).min(0.0f).max(15.0f).default_value(2.0f);
b.add_input<decl::Float>(N_("Roughness"))
@@ -71,8 +76,8 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat,
node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
- NodeTexNoise *tex = (NodeTexNoise *)node->storage;
- const char *name = gpu_shader_get_name(tex->dimensions);
+ const NodeTexNoise &storage = node_storage(*node);
+ const char *name = gpu_shader_get_name(storage.dimensions);
return GPU_stack_link(mat, node, name, in, out);
}
@@ -81,9 +86,9 @@ static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node)
bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W");
- NodeTexNoise *tex = (NodeTexNoise *)node->storage;
- nodeSetSocketAvailability(ntree, sockVector, tex->dimensions != 1);
- nodeSetSocketAvailability(ntree, sockW, tex->dimensions == 1 || tex->dimensions == 4);
+ const NodeTexNoise &storage = node_storage(*node);
+ nodeSetSocketAvailability(ntree, sockVector, storage.dimensions != 1);
+ nodeSetSocketAvailability(ntree, sockW, storage.dimensions == 1 || storage.dimensions == 4);
}
namespace blender::nodes {
@@ -229,19 +234,26 @@ class NoiseFunction : public fn::MultiFunction {
}
}
}
+
+ ExecutionHints get_execution_hints() const override
+ {
+ ExecutionHints hints;
+ hints.allocates_array = false;
+ hints.min_grain_size = 100;
+ return hints;
+ }
};
static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &node = builder.node();
- NodeTexNoise *tex = (NodeTexNoise *)node.storage;
- builder.construct_and_set_matching_fn<NoiseFunction>(tex->dimensions);
+ const NodeTexNoise &storage = node_storage(builder.node());
+ builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions);
}
} // namespace blender::nodes
/* node type definition */
-void register_node_type_sh_tex_noise(void)
+void register_node_type_sh_tex_noise()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
index 1bc3741d27c..8a1170de304 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -21,20 +21,30 @@
#include "BLI_noise.hh"
+NODE_STORAGE_FUNCS(NodeTexVoronoi)
+
namespace blender::nodes {
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
- b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("W")).min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
b.add_input<decl::Float>(N_("Scale")).min(-1000.0f).max(1000.0f).default_value(5.0f);
b.add_input<decl::Float>(N_("Smoothness"))
.min(0.0f)
.max(1.0f)
.default_value(1.0f)
- .subtype(PROP_FACTOR);
- b.add_input<decl::Float>(N_("Exponent")).min(0.0f).max(32.0f).default_value(0.5f);
+ .subtype(PROP_FACTOR)
+ .make_available([](bNode &node) { node_storage(node).feature = SHD_VORONOI_SMOOTH_F1; });
+ b.add_input<decl::Float>(N_("Exponent"))
+ .min(0.0f)
+ .max(32.0f)
+ .default_value(0.5f)
+ .make_available([](bNode &node) { node_storage(node).distance = SHD_VORONOI_MINKOWSKI; });
b.add_input<decl::Float>(N_("Randomness"))
.min(0.0f)
.max(1.0f)
@@ -43,8 +53,13 @@ static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Distance")).no_muted_links();
b.add_output<decl::Color>(N_("Color")).no_muted_links();
b.add_output<decl::Vector>(N_("Position")).no_muted_links();
- b.add_output<decl::Float>(N_("W")).no_muted_links();
- b.add_output<decl::Float>(N_("Radius")).no_muted_links();
+ b.add_output<decl::Float>(N_("W")).no_muted_links().make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is much faster. */
+ node_storage(node).dimensions = 1;
+ });
+ b.add_output<decl::Float>(N_("Radius")).no_muted_links().make_available([](bNode &node) {
+ node_storage(node).feature = SHD_VORONOI_N_SPHERE_RADIUS;
+ });
};
} // namespace blender::nodes
@@ -136,37 +151,40 @@ static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node)
bNodeSocket *outWSock = nodeFindSocket(node, SOCK_OUT, "W");
bNodeSocket *outRadiusSock = nodeFindSocket(node, SOCK_OUT, "Radius");
- NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ const NodeTexVoronoi &storage = node_storage(*node);
- nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4);
- nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(ntree, inWSock, storage.dimensions == 1 || storage.dimensions == 4);
+ nodeSetSocketAvailability(ntree, inVectorSock, storage.dimensions != 1);
nodeSetSocketAvailability(
ntree,
inExponentSock,
- tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
- !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
- nodeSetSocketAvailability(ntree, inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1);
+ storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 &&
+ !ELEM(storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
+ nodeSetSocketAvailability(ntree, inSmoothnessSock, storage.feature == SHD_VORONOI_SMOOTH_F1);
- nodeSetSocketAvailability(ntree, outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(
+ ntree, outDistanceSock, storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
nodeSetSocketAvailability(ntree,
outColorSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
nodeSetSocketAvailability(ntree,
outPositionSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
- tex->dimensions != 1);
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ storage.dimensions != 1);
nodeSetSocketAvailability(ntree,
outWSock,
- tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
- tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
- (ELEM(tex->dimensions, 1, 4)));
- nodeSetSocketAvailability(ntree, outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
+ storage.feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ storage.feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ (ELEM(storage.dimensions, 1, 4)));
+ nodeSetSocketAvailability(ntree, outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
namespace blender::nodes {
+static MultiFunction::ExecutionHints voronoi_execution_hints{50, false};
+
class VoronoiMinowskiFunction : public fn::MultiFunction {
private:
int dimensions_;
@@ -592,6 +610,11 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
}
}
}
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
};
class VoronoiMetricFunction : public fn::MultiFunction {
@@ -1106,6 +1129,11 @@ class VoronoiMetricFunction : public fn::MultiFunction {
}
}
}
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
};
class VoronoiEdgeFunction : public fn::MultiFunction {
@@ -1282,31 +1310,39 @@ class VoronoiEdgeFunction : public fn::MultiFunction {
break;
}
}
- };
+ }
+
+ ExecutionHints get_execution_hints() const override
+ {
+ return voronoi_execution_hints;
+ }
};
static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &node = builder.node();
- NodeTexVoronoi *tex = (NodeTexVoronoi *)node.storage;
- bool minowski = (tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
- !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
- bool dist_radius = ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS);
+ const NodeTexVoronoi &storage = node_storage(builder.node());
+ bool minowski =
+ (storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 &&
+ !ELEM(storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
+ bool dist_radius = ELEM(
+ storage.feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS);
if (dist_radius) {
- builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(tex->dimensions, tex->feature);
+ builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(storage.dimensions,
+ storage.feature);
}
else if (minowski) {
- builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(tex->dimensions, tex->feature);
+ builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(storage.dimensions,
+ storage.feature);
}
else {
builder.construct_and_set_matching_fn<VoronoiMetricFunction>(
- tex->dimensions, tex->feature, tex->distance);
+ storage.dimensions, storage.feature, storage.distance);
}
}
} // namespace blender::nodes
-void register_node_type_sh_tex_voronoi(void)
+void register_node_type_sh_tex_voronoi()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
index fe534c605e9..d3e25b533e5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
@@ -218,7 +218,7 @@ static void sh_node_wave_tex_build_multi_function(
} // namespace blender::nodes
-void register_node_type_sh_tex_wave(void)
+void register_node_type_sh_tex_wave()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
index 7b4ff7fec5c..0e72cee38e7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
@@ -27,7 +27,10 @@ static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).min(-10000.0f).max(10000.0f).implicit_field();
- b.add_input<decl::Float>(N_("W")).min(-10000.0f).max(10000.0f);
+ b.add_input<decl::Float>(N_("W")).min(-10000.0f).max(10000.0f).make_available([](bNode &node) {
+ /* Default to 1 instead of 4, because it is faster. */
+ node.custom1 = 1;
+ });
b.add_output<decl::Float>(N_("Value"));
b.add_output<decl::Color>(N_("Color"));
};
@@ -191,7 +194,7 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction
} // namespace blender::nodes
-void register_node_type_sh_tex_white_noise(void)
+void register_node_type_sh_tex_white_noise()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c
index 05c3248af65..05c3248af65 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index b0f152d8526..f0eb3ea9bee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -49,7 +49,7 @@ static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}
-void register_node_type_sh_value(void)
+void register_node_type_sh_value()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
index fad93962708..5f5969de78c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -24,6 +24,7 @@
#include "node_shader_util.h"
#include "NOD_math_functions.hh"
+#include "NOD_socket_search_link.hh"
namespace blender::nodes {
@@ -38,6 +39,18 @@ static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
};
+static void sh_node_vector_math_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ /* For now, do something very basic (only exposing "Add", and a single "Vector" socket). */
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_VECTOR)) {
+ params.add_item(IFACE_("Vector"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeVectorMath");
+ params.update_and_connect_available_socket(node, "Vector");
+ });
+ }
+}
+
} // namespace blender::nodes
static const char *gpu_shader_get_name(int mode)
@@ -201,8 +214,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -212,7 +225,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -222,7 +235,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
- info.title_case_name, function};
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -231,8 +244,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -241,8 +254,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name,
- function};
+ static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{
+ info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -251,7 +264,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_to_fl3(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(),
+ function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -260,7 +274,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
blender::nodes::try_dispatch_float_math_fl3_to_fl(
operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) {
- static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function};
+ static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(),
+ function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -277,16 +292,17 @@ static void sh_node_vector_math_build_multi_function(
builder.set_matching_fn(fn);
}
-void register_node_type_sh_vect_math(void)
+void register_node_type_sh_vect_math()
{
static bNodeType ntype;
sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
ntype.declare = blender::nodes::sh_node_vector_math_declare;
- node_type_label(&ntype, node_vector_math_label);
+ ntype.labelfunc = node_vector_math_label;
node_type_gpu(&ntype, gpu_shader_vector_math);
node_type_update(&ntype, node_shader_update_vector_math);
ntype.build_multi_function = sh_node_vector_math_build_multi_function;
+ ntype.gather_link_search_ops = blender::nodes::sh_node_vector_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
index 3c1f1ed8d39..a3cb82f3245 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -205,7 +205,7 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node)
ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
}
-void register_node_type_sh_vector_rotate(void)
+void register_node_type_sh_vector_rotate()
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vector_transform.c
index 7b08178f874..7b08178f874 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.c
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index c968d0bae56..fe8e68bfc42 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -44,7 +44,7 @@ bool tex_node_poll_default(bNodeType *UNUSED(ntype),
const char **r_disabled_hint)
{
if (!STREQ(ntree->idname, "TextureNodeTree")) {
- *r_disabled_hint = "Not a texture node tree";
+ *r_disabled_hint = TIP_("Not a texture node tree");
return false;
}
return true;
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 8f63a1ad07d..84d2c5c903a 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -37,8 +37,7 @@
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_rand.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index 868c97e5850..f873ed5e457 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -161,7 +161,7 @@ void register_node_type_tex_group(void)
/* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type
* to the shared #NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
+ node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, 0);
ntype.type = NODE_GROUP;
ntype.poll = tex_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -172,7 +172,7 @@ void register_node_type_tex_group(void)
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
- node_type_label(&ntype, node_group_label);
+ ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c
index f7deac9ff4a..c2241858737 100644
--- a/source/blender/nodes/texture/nodes/node_texture_distance.c
+++ b/source/blender/nodes/texture/nodes/node_texture_distance.c
@@ -21,7 +21,6 @@
* \ingroup texnodes
*/
-#include "BLI_math.h"
#include "NOD_texture.h"
#include "node_texture_util.h"
#include <math.h>
diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c
index a85b963286b..9c61405ea23 100644
--- a/source/blender/nodes/texture/nodes/node_texture_image.c
+++ b/source/blender/nodes/texture/nodes/node_texture_image.c
@@ -113,7 +113,7 @@ void register_node_type_tex_image(void)
node_type_init(&ntype, init);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, NULL, NULL, exec);
- node_type_label(&ntype, node_image_label);
+ ntype.labelfunc = node_image_label;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index ab226a4dd38..9e37f4ee643 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -337,7 +337,7 @@ void register_node_type_tex_math(void)
tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_label(&ntype, node_math_label);
+ ntype.labelfunc = node_math_label;
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
node_type_update(&ntype, node_math_update);
diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
index b1aeb269018..044875cce90 100644
--- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
@@ -71,7 +71,7 @@ void register_node_type_tex_mix_rgb(void)
tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_label(&ntype, node_blend_label);
+ ntype.labelfunc = node_blend_label;
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index 9145df0038b..19e24c9f82a 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -21,6 +21,8 @@
* \ingroup texnodes
*/
+#include "BLI_string.h"
+
#include "NOD_texture.h"
#include "node_texture_util.h"
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 43a73363c98..e233a078ea9 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -55,7 +55,13 @@ int BPY_is_pyconstraint(struct Text *text);
typedef void *BPy_ThreadStatePtr;
+/**
+ * Analogue of #PyEval_SaveThread()
+ */
BPy_ThreadStatePtr BPY_thread_save(void);
+/**
+ * Analogue of #PyEval_RestoreThread()
+ */
void BPY_thread_restore(BPy_ThreadStatePtr tstate);
/* our own wrappers to Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS */
@@ -69,12 +75,26 @@ void BPY_thread_restore(BPy_ThreadStatePtr tstate);
(void)0
void BPY_text_free_code(struct Text *text);
+/**
+ * Needed so the #Main pointer in `bpy.data` doesn't become out of date.
+ */
void BPY_modules_update(void);
void BPY_modules_load_user(struct bContext *C);
void BPY_app_handlers_reset(const short do_all);
+/**
+ * Update function, it gets rid of py-drivers global dictionary, forcing
+ * BPY_driver_exec to recreate it. This function is used to force
+ * reloading the Blender text module "pydrivers.py", if available, so
+ * updates in it reach py-driver evaluation.
+ */
void BPY_driver_reset(void);
+
+/**
+ * This evaluates Python driver expressions, `driver_orig->expression`
+ * is a Python expression that should evaluate to a float number, which is returned.
+ */
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
struct ChannelDriver *driver,
struct ChannelDriver *driver_orig,
@@ -86,6 +106,9 @@ int BPY_context_member_get(struct bContext *C,
const char *member,
struct bContextDataResult *result);
void BPY_context_set(struct bContext *C);
+/**
+ * Use for updating while a python script runs - in case of file load.
+ */
void BPY_context_update(struct bContext *C);
#define BPY_context_dict_clear_members(C, ...) \
@@ -93,6 +116,16 @@ void BPY_context_update(struct bContext *C);
(C)->data.py_context_orig, \
((const char *[]){__VA_ARGS__}), \
VA_NARGS_COUNT(__VA_ARGS__))
+/**
+ * Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
+ * In this case we don't want the Python context to override the values as it causes problems
+ * see T66256.
+ *
+ * \param dict_p: A pointer to #bContext.data.py_context so we can assign a new value.
+ * \param dict_orig: The value of #bContext.data.py_context_orig to check if we need to copy.
+ *
+ * \note Typically accessed via #BPY_context_dict_clear_members macro.
+ */
void BPY_context_dict_clear_members_array(void **dict_p,
void *dict_orig,
const char *context_members[],
@@ -100,6 +133,9 @@ void BPY_context_dict_clear_members_array(void **dict_p,
void BPY_id_release(struct ID *id);
+/**
+ * Avoids duplicating keyword list.
+ */
bool BPY_string_is_keyword(const char *str);
/* bpy_rna_callback.c */
diff --git a/source/blender/python/BPY_extern_python.h b/source/blender/python/BPY_extern_python.h
index c321fd93379..56662ffc040 100644
--- a/source/blender/python/BPY_extern_python.h
+++ b/source/blender/python/BPY_extern_python.h
@@ -32,6 +32,8 @@ extern "C" {
#include <stdio.h>
/* bpy_interface.c */
+
+/** Call #BPY_context_set first. */
void BPY_python_start(struct bContext *C, int argc, const char **argv);
void BPY_python_end(void);
void BPY_python_reset(struct bContext *C);
diff --git a/source/blender/python/BPY_extern_run.h b/source/blender/python/BPY_extern_run.h
index b65b5d61b9d..30740d7fb60 100644
--- a/source/blender/python/BPY_extern_run.h
+++ b/source/blender/python/BPY_extern_run.h
@@ -16,6 +16,20 @@
/** \file
* \ingroup python
+ *
+ * \subsection common_args Common Arguments
+ *
+ * - `C` the #bContext (never NULL).
+ *
+ * - `imports`: This is simply supported for convenience since imports can make constructing
+ * strings more cumbersome as otherwise small expressions become multi-line code-blocks.
+ * Optional (ignored when NULL), otherwise this is a NULL terminated array of module names.
+ *
+ Failure to import any modules prevents any further execution.
+ *
+ * - `err_info` #BPy_RunErrInfo is passed to some functions so errors can be forwarded to the UI.
+ * Option (when NULL errors are printed to the `stdout` and cleared).
+ * However this should be used in any case the error would be useful to show to the user.
*/
#pragma once
@@ -26,22 +40,85 @@ extern "C" {
#include "BLI_sys_types.h"
+#include "BLI_compiler_attrs.h"
+
struct ReportList;
struct Text;
struct bContext;
/* bpy_interface_run.c */
-bool BPY_run_filepath(struct bContext *C, const char *filepath, struct ReportList *reports);
+
+/* -------------------------------------------------------------------- */
+/** \name Run File/Text as a Script
+ *
+ * \note #BPY_run_filepath and #BPY_run_filepath have almost identical behavior
+ * one operates on a file-path, the other on a blender text-block.
+ * \{ */
+
+/**
+ * Execute `filepath` as a Python script.
+ *
+ * Wrapper for `PyRun_File` (similar to calling python with a script argument).
+ * Used for the `--python` command line argument.
+ *
+ * \param C: The context (never NULL).
+ * \param filepath: The file path to execute.
+ * \param reports: Failure to execute the script will report the exception here (may be NULL).
+ * \return true on success, otherwise false with an error reported to `reports`.
+ *
+ * \note Python scripts could consider `bpy.utils.execfile`, which has the advantage of returning
+ * the object as a module for data access & caching `pyc` file for faster re-execution.
+ */
+bool BPY_run_filepath(struct bContext *C, const char *filepath, struct ReportList *reports)
+ ATTR_NONNULL(1, 2);
+/**
+ * Execute a Blender `text` block as a Python script.
+ *
+ * Wrapper for `Py_CompileStringObject` & `PyEval_EvalCode`.
+ * Used for the `--python-text` command line argument.
+ *
+ * \param C: The context (never NULL).
+ * \param text: The text-block to execute.
+ * \param reports: Failure to execute the script will report the exception here (may be NULL).
+ * \param do_jump: When true, any error moves the cursor to the location of that error.
+ * Useful for executing scripts interactively from the text editor.
+ * \return true on success, otherwise false with an error reported to `reports`.
+ *
+ * \note The `__file__` is constructed by joining the blend file-path to the name of the text.
+ * This is done so error messages give useful output however there are rare cases causes problems
+ * with introspection tools which attempt to load `__file__`.
+ */
bool BPY_run_text(struct bContext *C,
struct Text *text,
struct ReportList *reports,
- const bool do_jump);
+ const bool do_jump) ATTR_NONNULL(1, 2);
-/* Use the 'eval' for simple single-line expressions,
- * otherwise 'exec' for full multi-line scripts. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Run a String as a Script
+ *
+ * - Use 'eval' for simple single-line expressions.
+ * - Use 'exec' for full multi-line scripts.
+ * \{ */
+
+/**
+ * Run an entire script, matches: `exec(compile(..., "exec"))`
+ */
bool BPY_run_string_exec(struct bContext *C, const char *imports[], const char *expr);
+/**
+ * Run an expression, matches: `exec(compile(..., "eval"))`.
+ */
bool BPY_run_string_eval(struct bContext *C, const char *imports[], const char *expr);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Run a String as a Script & Return the Result
+ *
+ * Convenience functions for executing a script and returning the result as an expected type.
+ * \{ */
+
/**
* \note When this struct is passed in as NULL,
* print errors to the `stdout` and clear.
@@ -58,28 +135,63 @@ struct BPy_RunErrInfo {
char **r_string;
};
-/* Run, evaluating to fixed type result. */
+/**
+ * Evaluate `expr` as a number (double).
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_number(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- double *r_value);
+ double *r_value) ATTR_NONNULL(1, 3, 5);
+/**
+ * Evaluate `expr` as an integer or pointer.
+ *
+ * \note Support both int and pointers.
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_intptr(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- intptr_t *r_value);
+ intptr_t *r_value) ATTR_NONNULL(1, 3, 5);
+/**
+ * Evaluate `expr` as a string.
+ *
+ * \param C: See \ref common_args.
+ * \param imports: See \ref common_args.
+ * \param expr: The expression to evaluate.
+ * \param err_info: See \ref common_args.
+ * \param r_value: The resulting value.
+ * \return Success.
+ */
bool BPY_run_string_as_string_and_size(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
char **r_value,
- size_t *r_value_size);
+ size_t *r_value_size) ATTR_NONNULL(1, 3, 5, 6);
+
+/** See #BPY_run_string_as_string_and_size */
bool BPY_run_string_as_string(struct bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
- char **r_value);
+ char **r_value) ATTR_NONNULL(1, 3, 5);
+
+/** \} */
#ifdef __cplusplus
} /* extern "C" */
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 24887b24eb6..f1423c20b3b 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -745,9 +745,6 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
return item;
}
-/**
- * This is the __call__ for bmesh.ops.xxx()
- */
PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
{
PyObject *ret;
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.h b/source/blender/python/bmesh/bmesh_py_ops_call.h
index 1c7a35788d2..c567375c568 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.h
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.h
@@ -28,4 +28,7 @@ typedef struct {
const char *opname;
} BPy_BMeshOpFunc;
+/**
+ * This is the `__call__` for `bmesh.ops.xxx()`.
+ */
PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw);
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index cbebe4746e9..38ec242fa49 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -3349,8 +3349,8 @@ static PyObject *bpy_bmiter_next(BPy_BMIter *self)
return (PyObject *)BPy_BMElem_CreatePyObject(self->bm, ele);
}
-/* Dealloc Functions
- * ================= */
+/* Deallocate Functions
+ * ==================== */
static void bpy_bmesh_dealloc(BPy_BMesh *self)
{
@@ -3954,7 +3954,6 @@ PyObject *BPy_BMIter_CreatePyObject(BMesh *bm)
return (PyObject *)self;
}
-/* this is just a helper func */
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele)
{
switch (ele->htype) {
@@ -4036,11 +4035,6 @@ void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
self->bm = NULL;
}
-/* generic python seq as BMVert/Edge/Face array,
- * return value must be freed with PyMem_FREE(...);
- *
- * The 'bm_r' value is assigned when empty, and used when set.
- */
void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm,
PyObject *seq_fast,
Py_ssize_t min,
@@ -4233,11 +4227,6 @@ int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype)
((htype & BM_LOOP) && (type == &BPy_BMLoop_Type)));
}
-/**
- * Use for error strings only, not thread safe,
- *
- * \return a string like '(BMVert/BMEdge/BMFace/BMLoop)'
- */
char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32])
{
/* zero to ensure string is always NULL terminated */
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 043c5322735..42d1fee31c3 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -148,9 +148,15 @@ PyObject *BPy_BMFaceSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMLoopSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMIter_CreatePyObject(BMesh *bm);
-/* Just checks type and creates v/e/f/l. */
+/** Just checks type and creates vert/edge/face/loop. */
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele);
+/**
+ * Generic python seq as BMVert/Edge/Face array,
+ * return value must be freed with PyMem_FREE(...);
+ *
+ * The 'bm_r' value is assigned when empty, and used when set.
+ */
void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm,
PyObject *seq_fast,
Py_ssize_t min,
@@ -177,6 +183,11 @@ PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_le
PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop **elem, Py_ssize_t elem_len);
int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype);
+/**
+ * Use for error strings only, not thread safe,
+ *
+ * \return a string like '(BMVert/BMEdge/BMFace/BMLoop)'
+ */
char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32]);
char *BPy_BMElem_StringFromHType(const char htype);
@@ -198,7 +209,9 @@ int bpy_bm_generic_valid_check_source(BMesh *bm_source,
} \
(void)0
-/* macros like BPY_BM_CHECK_OBJ/BPY_BM_CHECK_INT that ensure we're from the right BMesh */
+/**
+ * Macros like `BPY_BM_CHECK_OBJ/BPY_BM_CHECK_INT` that ensure we're from the right #BMesh.
+ */
#define BPY_BM_CHECK_SOURCE_OBJ(bm, errmsg, ...) \
{ \
void *_args[] = {__VA_ARGS__}; \
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index 0aa92158524..1e1ba5edb0f 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -1104,13 +1104,6 @@ static void *bpy_bmlayeritem_ptr_get(BPy_BMElem *py_ele, BPy_BMLayerItem *py_lay
return value;
}
-/**
- *\brief BMElem.__getitem__()
- *
- * assume all error checks are done, eg:
- *
- * uv = vert[uv_layer]
- */
PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
{
void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer);
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.h b/source/blender/python/bmesh/bmesh_py_types_customdata.h
index 8552942f73a..a5555a14ad7 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.h
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.h
@@ -23,7 +23,8 @@
#pragma once
-/* all use BPy_BMLayerAccess struct */
+/* All use #BPy_BMLayerAccess struct. */
+
extern PyTypeObject BPy_BMLayerAccessVert_Type;
extern PyTypeObject BPy_BMLayerAccessEdge_Type;
extern PyTypeObject BPy_BMLayerAccessFace_Type;
@@ -36,14 +37,14 @@ extern PyTypeObject BPy_BMLayerItem_Type;
#define BPy_BMLayerCollection_Check(v) (Py_TYPE(v) == &BPy_BMLayerCollection_Type)
#define BPy_BMLayerItem_Check(v) (Py_TYPE(v) == &BPy_BMLayerItem_Type)
-/* all layers for vert/edge/face/loop */
+/** All layers for vert/edge/face/loop. */
typedef struct BPy_BMLayerAccess {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
char htype;
} BPy_BMLayerAccess;
-/* access different layer types deform/uv/vertexcolor */
+/** Access different layer types deform/uv/vertex-color. */
typedef struct BPy_BMLayerCollection {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
@@ -51,7 +52,7 @@ typedef struct BPy_BMLayerCollection {
int type; /* customdata type - CD_XXX */
} BPy_BMLayerCollection;
-/* access a specific layer directly */
+/** Access a specific layer directly. */
typedef struct BPy_BMLayerItem {
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
@@ -66,6 +67,10 @@ PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, const char htype, int type,
void BPy_BM_init_types_customdata(void);
-/* __getitem__ / __setitem__ */
+/**
+ *\brief BMElem.__getitem__() / __setitem__()
+ *
+ * Assume all error checks are done, eg: `uv = vert[uv_layer]`
+ */
PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer);
int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *value);
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index ca5d408bfdb..766e1d08443 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -689,7 +689,6 @@ PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert)
/* --- End Mesh Deform Vert --- */
-/* call to init all types */
void BPy_BM_init_types_meshdata(void)
{
bm_init_types_bmloopuv();
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.h b/source/blender/python/bmesh/bmesh_py_types_meshdata.h
index 426bfcef6a0..b52bf6889bc 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.h
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.h
@@ -50,4 +50,5 @@ PyObject *BPy_BMLoopColor_CreatePyObject(struct MLoopCol *mloopcol);
int BPy_BMDeformVert_AssignPyObject(struct MDeformVert *dvert, PyObject *value);
PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert);
+/* call to init all types */
void BPy_BM_init_types_meshdata(void);
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c
index b89822a080c..bc8c6853ff5 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.c
+++ b/source/blender/python/bmesh/bmesh_py_types_select.c
@@ -411,9 +411,6 @@ void BPy_BM_init_types_select(void)
/* utility function */
-/**
- * \note doesn't actually check selection.
- */
int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value)
{
BMesh *bm;
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.h b/source/blender/python/bmesh/bmesh_py_types_select.h
index 34ca162dd09..6b8609e36a6 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.h
+++ b/source/blender/python/bmesh/bmesh_py_types_select.h
@@ -46,4 +46,7 @@ void BPy_BM_init_types_select(void);
PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm);
PyObject *BPy_BMEditSelIter_CreatePyObject(BMesh *bm);
+/**
+ * \note doesn't actually check selection.
+ */
int BPy_BMEditSel_Assign(struct BPy_BMesh *self, PyObject *value);
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index e416727fa70..3f01ff86f49 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -666,13 +666,6 @@ static Buffer *BGL_MakeBuffer_FromData(
return buffer;
}
-/**
- * Create a buffer object
- *
- * \param dimensions: An array of ndimensions integers representing the size of each dimension.
- * \param initbuffer: When not NULL holds a contiguous buffer
- * with the correct format from which the buffer will be initialized
- */
Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuffer)
{
Buffer *buffer;
diff --git a/source/blender/python/generic/bgl.h b/source/blender/python/generic/bgl.h
index 4e59eab46ce..479c69b5de2 100644
--- a/source/blender/python/generic/bgl.h
+++ b/source/blender/python/generic/bgl.h
@@ -22,6 +22,13 @@
PyObject *BPyInit_bgl(void);
+/**
+ * Create a buffer object
+ *
+ * \param dimensions: An array of ndimensions integers representing the size of each dimension.
+ * \param initbuffer: When not NULL holds a contiguous buffer
+ * with the correct format from which the buffer will be initialized
+ */
struct _Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuffer);
int BGL_typeSize(int type);
@@ -50,5 +57,5 @@ typedef struct _Buffer {
} buf;
} Buffer;
-/** The type object */
+/** The type object. */
extern PyTypeObject BGL_bufferType;
diff --git a/source/blender/python/generic/bpy_threads.c b/source/blender/python/generic/bpy_threads.c
index 8aa8c5c5d92..41e2fb4adf2 100644
--- a/source/blender/python/generic/bpy_threads.c
+++ b/source/blender/python/generic/bpy_threads.c
@@ -26,7 +26,6 @@
#include "../BPY_extern.h"
#include "BLI_utildefines.h"
-/* analogue of PyEval_SaveThread() */
BPy_ThreadStatePtr BPY_thread_save(void)
{
/* Use `_PyThreadState_UncheckedGet()` instead of `PyThreadState_Get()`, to avoid a fatal error
@@ -40,7 +39,6 @@ BPy_ThreadStatePtr BPY_thread_save(void)
return NULL;
}
-/* analogue of PyEval_RestoreThread() */
void BPY_thread_restore(BPy_ThreadStatePtr tstate)
{
if (tstate) {
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 8dc0d2fb857..0a870102b6f 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -686,12 +686,6 @@ static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
/** \name Mapping Get/Set (Internal Access)
* \{ */
-/**
- * \note group can be a pointer array or a group.
- * assume we already checked key is a string.
- *
- * \return success.
- */
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
{
IDProperty *prop = idp_from_PyObject(name_obj, ob);
@@ -779,7 +773,6 @@ static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
return BPy_IDGroup_ViewKeys_CreatePyObject(self);
}
-/* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
{
switch (prop->type) {
@@ -1975,6 +1968,8 @@ static PyBufferProcs BPy_IDArray_Buffer = {
(releasebufferproc)BPy_IDArray_releasebuffer,
};
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name ID Array Type
* \{ */
diff --git a/source/blender/python/generic/idprop_py_api.h b/source/blender/python/generic/idprop_py_api.h
index f53c45b07c2..e4addcecc10 100644
--- a/source/blender/python/generic/idprop_py_api.h
+++ b/source/blender/python/generic/idprop_py_api.h
@@ -95,8 +95,17 @@ PyObject *BPy_Wrap_GetItems_View_WithID(struct ID *id, struct IDProperty *prop);
int BPy_Wrap_SetMapItem(struct IDProperty *prop, PyObject *key, PyObject *val);
+/**
+ * For simple, non nested types this is the same as #BPy_IDGroup_WrapData.
+ */
PyObject *BPy_IDGroup_MapDataToPy(struct IDProperty *prop);
PyObject *BPy_IDGroup_WrapData(struct ID *id, struct IDProperty *prop, struct IDProperty *parent);
+/**
+ * \note group can be a pointer array or a group.
+ * assume we already checked key is a string.
+ *
+ * \return success.
+ */
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *key, struct IDProperty *group, PyObject *ob);
void IDProp_Init_Types(void);
diff --git a/source/blender/python/generic/py_capi_rna.c b/source/blender/python/generic/py_capi_rna.c
index 235b136ca74..a6a0d820d07 100644
--- a/source/blender/python/generic/py_capi_rna.c
+++ b/source/blender/python/generic/py_capi_rna.c
@@ -41,10 +41,6 @@
/** \name Enum Utilities
* \{ */
-/**
- * Convert all items into a single comma separated string.
- * Use for creating useful error messages.
- */
char *pyrna_enum_repr(const EnumPropertyItem *item)
{
DynStr *dynstr = BLI_dynstr_new();
@@ -69,9 +65,6 @@ char *pyrna_enum_repr(const EnumPropertyItem *item)
/** \name Enum Conversion Utilities
* \{ */
-/**
- * Same as #RNA_enum_value_from_id, but raises an exception.
- */
int pyrna_enum_value_from_id(const EnumPropertyItem *item,
const char *identifier,
int *r_value,
@@ -88,14 +81,6 @@ int pyrna_enum_value_from_id(const EnumPropertyItem *item,
return 0;
}
-/**
- * Takes a set of strings and map it to and array of booleans.
- *
- * Useful when the values aren't flags.
- *
- * \param type_convert_sign: Maps signed to unsigned range,
- * needed when we want to use the full range of a signed short/char.
- */
BLI_bitmap *pyrna_enum_bitmap_from_set(const EnumPropertyItem *items,
PyObject *value,
int type_size,
@@ -159,9 +144,6 @@ error:
return NULL;
}
-/**
- * 'value' _must_ be a set type, error check before calling.
- */
int pyrna_enum_bitfield_from_set(const EnumPropertyItem *items,
PyObject *value,
int *r_value,
@@ -223,9 +205,6 @@ PyObject *pyrna_enum_bitfield_as_set(const EnumPropertyItem *items, int value)
/** \name Argument Parsing Helpers
* \{ */
-/**
- * Use with #PyArg_ParseTuple's `O&` formatting.
- */
int pyrna_enum_value_parse_string(PyObject *o, void *p)
{
const char *identifier = PyUnicode_AsUTF8(o);
@@ -244,9 +223,6 @@ int pyrna_enum_value_parse_string(PyObject *o, void *p)
return 1;
}
-/**
- * Use with #PyArg_ParseTuple's `O&` formatting.
- */
int pyrna_enum_bitfield_parse_set(PyObject *o, void *p)
{
if (!PySet_Check(o)) {
diff --git a/source/blender/python/generic/py_capi_rna.h b/source/blender/python/generic/py_capi_rna.h
index 326ca777a4b..9733cb043ea 100644
--- a/source/blender/python/generic/py_capi_rna.h
+++ b/source/blender/python/generic/py_capi_rna.h
@@ -25,13 +25,28 @@
struct EnumPropertyItem;
+/**
+ * Convert all items into a single comma separated string.
+ * Use for creating useful error messages.
+ */
char *pyrna_enum_repr(const struct EnumPropertyItem *item);
+/**
+ * Same as #RNA_enum_value_from_id, but raises an exception.
+ */
int pyrna_enum_value_from_id(const struct EnumPropertyItem *item,
const char *identifier,
int *value,
const char *error_prefix);
+/**
+ * Takes a set of strings and map it to and array of booleans.
+ *
+ * Useful when the values aren't flags.
+ *
+ * \param type_convert_sign: Maps signed to unsigned range,
+ * needed when we want to use the full range of a signed short/char.
+ */
unsigned int *pyrna_enum_bitmap_from_set(const struct EnumPropertyItem *items,
PyObject *value,
int type_size,
@@ -39,6 +54,9 @@ unsigned int *pyrna_enum_bitmap_from_set(const struct EnumPropertyItem *items,
int bitmap_size,
const char *error_prefix);
+/**
+ * 'value' _must_ be a set type, error check before calling.
+ */
int pyrna_enum_bitfield_from_set(const struct EnumPropertyItem *items,
PyObject *value,
int *r_value,
@@ -62,5 +80,11 @@ struct BPy_EnumProperty_Parse {
int value;
bool is_set;
};
+/**
+ * Use with #PyArg_ParseTuple's `O&` formatting.
+ */
int pyrna_enum_value_parse_string(PyObject *o, void *p);
+/**
+ * Use with #PyArg_ParseTuple's `O&` formatting.
+ */
int pyrna_enum_bitfield_parse_set(PyObject *o, void *p);
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 9cccc2f608f..acb6d76f30b 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -470,10 +470,6 @@ PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], co
/** \name Tuple/List Filling
* \{ */
-/**
- * Caller needs to ensure tuple is uninitialized.
- * Handy for filling a tuple with None for eg.
- */
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value)
{
const uint tot = PyTuple_GET_SIZE(tuple);
@@ -502,11 +498,6 @@ void PyC_List_Fill(PyObject *list, PyObject *value)
/** \name Bool/Enum Argument Parsing
* \{ */
-/**
- * Use with PyArg_ParseTuple's "O&" formatting.
- *
- * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
- */
int PyC_ParseBool(PyObject *o, void *p)
{
bool *bool_p = p;
@@ -520,9 +511,6 @@ int PyC_ParseBool(PyObject *o, void *p)
return 1;
}
-/**
- * Use with PyArg_ParseTuple's "O&" formatting.
- */
int PyC_ParseStringEnum(PyObject *o, void *p)
{
struct PyC_StringEnum *e = p;
@@ -598,10 +586,6 @@ void PyC_ObSpit(const char *name, PyObject *var)
}
}
-/**
- * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument).
- * Use for logging.
- */
void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var)
{
/* No name, creator of string can manage that. */
@@ -789,13 +773,6 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings)
/** \name Exception Utilities
* \{ */
-/**
- * Similar to #PyErr_Format(),
- *
- * Implementation - we can't actually prepend the existing exception,
- * because it could have _any_ arguments given to it, so instead we get its
- * `__str__` output and raise our own exception including it.
- */
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...)
{
PyObject *error_value_prefix;
@@ -835,10 +812,6 @@ PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *
return PyC_Err_Format_Prefix(exception_type_prefix, "%s", str);
}
-/**
- * Use for Python callbacks run directly from C,
- * when we can't use normal methods of raising exceptions.
- */
void PyC_Err_PrintWithFunc(PyObject *py_func)
{
/* since we return to C code we can't leave the error */
@@ -1014,7 +987,6 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
* In some cases we need to coerce strings, avoid doing this inline.
* \{ */
-/* string conversion, escape non-unicode chars, coerce must be set to NULL */
const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce)
{
const char *result;
@@ -1093,18 +1065,6 @@ PyObject *PyC_UnicodeFromByte(const char *str)
/** \name Name Space Creation/Manipulation
* \{ */
-/*****************************************************************************
- * Description: This function creates a new Python dictionary object.
- * NOTE: dict is owned by sys.modules["__main__"] module, reference is borrowed
- * NOTE: important we use the dict from __main__, this is what python expects
- * for 'pickle' to work as well as strings like this...
- * >> foo = 10
- * >> print(__import__("__main__").foo)
- *
- * NOTE: this overwrites __main__ which gives problems with nested calls.
- * be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
- * any chance that python is in the call stack.
- ****************************************************************************/
PyObject *PyC_DefaultNameSpace(const char *filename)
{
PyObject *modules = PyImport_GetModuleDict();
@@ -1143,7 +1103,6 @@ bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[])
return true;
}
-/* restore MUST be called after this */
void PyC_MainModule_Backup(PyObject **r_main_mod)
{
PyObject *modules = PyImport_GetModuleDict();
@@ -1468,11 +1427,6 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
/** \name Run String (Evaluate to Primitive Types)
* \{ */
-/**
- * \return success
- *
- * \note it is caller's responsibility to acquire & release GIL!
- */
bool PyC_RunString_AsNumber(const char *imports[],
const char *expr,
const char *filename,
@@ -1648,32 +1602,6 @@ bool PyC_RunString_AsString(const char *imports[],
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
-/**
- *
- * Comparison with #PyObject_IsTrue
- * ================================
- *
- * Even though Python provides a way to retrieve the boolean value for an object,
- * in many cases it's far too relaxed, with the following examples coercing values.
- *
- * \code{.py}
- * data.value = "Text" # True.
- * data.value = "" # False.
- * data.value = {1, 2} # True
- * data.value = {} # False.
- * data.value = None # False.
- * \endcode
- *
- * In practice this is often a mistake by the script author that doesn't behave as they expect.
- * So it's better to be more strict for attribute assignment and function arguments,
- * only accepting True/False 0/1.
- *
- * If coercing a value is desired, it can be done explicitly: `data.value = bool(value)`
- *
- * \see #PyC_ParseBool for use with #PyArg_ParseTuple and related functions.
- *
- * \note Don't use `bool` return type, so -1 can be used as an error value.
- */
int PyC_Long_AsBool(PyObject *value)
{
const int test = _PyLong_AsInt(value);
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index a8695d2330a..f6d8d7298af 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -26,6 +26,10 @@
#include "BLI_utildefines_variadic.h"
void PyC_ObSpit(const char *name, PyObject *var);
+/**
+ * A version of #PyC_ObSpit that writes into a string (and doesn't take a name argument).
+ * Use for logging.
+ */
void PyC_ObSpitStr(char *result, size_t result_len, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
@@ -34,9 +38,20 @@ PyObject *PyC_ExceptionBuffer_Simple(void);
PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
PyObject *PyC_FrozenSetFromStrings(const char **strings);
+/**
+ * Similar to #PyErr_Format(),
+ *
+ * Implementation - we can't actually prepend the existing exception,
+ * because it could have _any_ arguments given to it, so instead we get its
+ * `__str__` output and raise our own exception including it.
+ */
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *str);
+/**
+ * Use for Python callbacks run directly from C,
+ * when we can't use normal methods of raising exceptions.
+ */
void PyC_Err_PrintWithFunc(PyObject *py_func);
void PyC_FileAndNum(const char **r_filename, int *r_lineno);
@@ -92,6 +107,10 @@ PyObject *PyC_Tuple_PackArray_Multi_F64(const double *array, const int dims[], c
PyObject *PyC_Tuple_PackArray_Multi_I32(const int *array, const int dims[], const int dims_len);
PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], const int dims_len);
+/**
+ * Caller needs to ensure tuple is uninitialized.
+ * Handy for filling a tuple with None for eg.
+ */
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value);
void PyC_List_Fill(PyObject *list, PyObject *value);
@@ -99,13 +118,39 @@ void PyC_List_Fill(PyObject *list, PyObject *value);
PyObject *PyC_UnicodeFromByte(const char *str);
PyObject *PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size);
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */
+/**
+ * String conversion, escape non-unicode chars
+ * \param coerce: must be set to NULL.
+ */
const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce);
-/* name namespace function for bpy */
+/**
+ * Description: This function creates a new Python dictionary object.
+ * NOTE: dict is owned by sys.modules["__main__"] module, reference is borrowed
+ * NOTE: important we use the dict from __main__, this is what python expects
+ * for 'pickle' to work as well as strings like this...
+ * >> foo = 10
+ * >> print(__import__("__main__").foo)
+ *
+ * NOTE: this overwrites __main__ which gives problems with nested calls.
+ * be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
+ * any chance that python is in the call stack.
+ */
PyObject *PyC_DefaultNameSpace(const char *filename);
void PyC_RunQuicky(const char *filepath, int n, ...);
+/**
+ * Import `imports` into `py_dict`.
+ *
+ * \param py_dict: A Python dictionary, typically used as a name-space for script execution.
+ * \param imports: A NULL terminated array of strings.
+ * \return true when all modules import without errors, otherwise return false.
+ * The caller is expected to handle the exception.
+ */
bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[]);
+/**
+ * #PyC_MainModule_Restore MUST be called after #PyC_MainModule_Backup.
+ */
void PyC_MainModule_Backup(PyObject **r_main_mod);
void PyC_MainModule_Restore(PyObject *main_mod);
@@ -131,6 +176,11 @@ int PyC_FlagSet_ToBitfield(const PyC_FlagSet *items,
const char *error_prefix);
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);
+/**
+ * \return success
+ *
+ * \note it is caller's responsibility to acquire & release GIL!
+ */
bool PyC_RunString_AsNumber(const char **imports,
const char *expr,
const char *filename,
@@ -149,6 +199,11 @@ bool PyC_RunString_AsString(const char **imports,
const char *filename,
char **r_value);
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ *
+ * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing.
+ */
int PyC_ParseBool(PyObject *o, void *p);
struct PyC_StringEnumItems {
@@ -160,6 +215,9 @@ struct PyC_StringEnum {
int value_found;
};
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
int PyC_ParseStringEnum(PyObject *o, void *p);
const char *PyC_StringEnum_FindIDFromValue(const struct PyC_StringEnumItems *items,
const int value);
@@ -167,6 +225,32 @@ const char *PyC_StringEnum_FindIDFromValue(const struct PyC_StringEnumItems *ite
int PyC_CheckArgs_DeepCopy(PyObject *args);
/* Integer parsing (with overflow checks), -1 on error. */
+/**
+ *
+ * Comparison with #PyObject_IsTrue
+ * ================================
+ *
+ * Even though Python provides a way to retrieve the boolean value for an object,
+ * in many cases it's far too relaxed, with the following examples coercing values.
+ *
+ * \code{.py}
+ * data.value = "Text" # True.
+ * data.value = "" # False.
+ * data.value = {1, 2} # True
+ * data.value = {} # False.
+ * data.value = None # False.
+ * \endcode
+ *
+ * In practice this is often a mistake by the script author that doesn't behave as they expect.
+ * So it's better to be more strict for attribute assignment and function arguments,
+ * only accepting True/False 0/1.
+ *
+ * If coercing a value is desired, it can be done explicitly: `data.value = bool(value)`
+ *
+ * \see #PyC_ParseBool for use with #PyArg_ParseTuple and related functions.
+ *
+ * \note Don't use `bool` return type, so -1 can be used as an error value.
+ */
int PyC_Long_AsBool(PyObject *value);
int8_t PyC_Long_AsI8(PyObject *value);
int16_t PyC_Long_AsI16(PyObject *value);
diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h
index 1f093e633e4..25300c2fd45 100644
--- a/source/blender/python/generic/python_utildefines.h
+++ b/source/blender/python/generic/python_utildefines.h
@@ -36,16 +36,20 @@ extern "C" {
} \
(void)0
-/* wrap Py_INCREF & return the result,
- * use sparingly to avoid comma operator or temp var assignment */
+/**
+ * Wrap #Py_INCREF & return the result,
+ * use sparingly to avoid comma operator or temp var assignment.
+ */
Py_LOCAL_INLINE(PyObject *) Py_INCREF_RET(PyObject *op)
{
Py_INCREF(op);
return op;
}
-/* Append & transfer ownership to the list,
- * avoids inline Py_DECREF all over (which is quite a large macro). */
+/**
+ * Append & transfer ownership to the list,
+ * avoids inline #Py_DECREF all over (which is quite a large macro).
+ */
Py_LOCAL_INLINE(int) PyList_APPEND(PyObject *op, PyObject *v)
{
int ret = PyList_Append(op, v);
diff --git a/source/blender/python/gpu/gpu_py.c b/source/blender/python/gpu/gpu_py.c
index e6ba46b2b05..a2d4b0e1031 100644
--- a/source/blender/python/gpu/gpu_py.c
+++ b/source/blender/python/gpu/gpu_py.c
@@ -58,6 +58,7 @@ struct PyC_StringEnumItems bpygpu_dataformat_items[] = {
{GPU_DATA_10_11_11_REV, "10_11_11_REV"},
{0, NULL},
};
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c
index abfde7b48c8..f074b51af32 100644
--- a/source/blender/python/gpu/gpu_py_buffer.c
+++ b/source/blender/python/gpu/gpu_py_buffer.c
@@ -687,13 +687,6 @@ size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer)
return pygpu_buffer_calc_size(buffer->format, buffer->shape_len, buffer->shape);
}
-/**
- * Create a buffer object
- *
- * \param shape: An array of `shape_len` integers representing the size of each dimension.
- * \param buffer: When not NULL holds a contiguous buffer
- * with the correct format from which the buffer will be initialized
- */
BPyGPUBuffer *BPyGPU_Buffer_CreatePyObject(const int format,
const Py_ssize_t *shape,
const int shape_len,
diff --git a/source/blender/python/gpu/gpu_py_buffer.h b/source/blender/python/gpu/gpu_py_buffer.h
index 9df22e9b780..cbc46339628 100644
--- a/source/blender/python/gpu/gpu_py_buffer.h
+++ b/source/blender/python/gpu/gpu_py_buffer.h
@@ -48,6 +48,13 @@ typedef struct BPyGPUBuffer {
} BPyGPUBuffer;
size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer);
+/**
+ * Create a buffer object
+ *
+ * \param shape: An array of `shape_len` integers representing the size of each dimension.
+ * \param buffer: When not NULL holds a contiguous buffer
+ * with the correct format from which the buffer will be initialized
+ */
BPyGPUBuffer *BPyGPU_Buffer_CreatePyObject(const int format,
const Py_ssize_t *shape,
const int shape_len,
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 6f23c2213e2..48fbe09f0ce 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -44,6 +44,7 @@
#include "GPU_context.h"
#include "GPU_framebuffer.h"
#include "GPU_texture.h"
+#include "GPU_viewport.h"
#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
@@ -355,6 +356,15 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
GPU_offscreen_bind(self->ofs, true);
+ /* Cache the #GPUViewport so the frame-buffers and associated textures are
+ * not reallocated each time, see: T89204 */
+ if (!self->viewport) {
+ self->viewport = GPU_viewport_create();
+ }
+ else {
+ GPU_viewport_tag_update(self->viewport);
+ }
+
ED_view3d_draw_offscreen(depsgraph,
scene,
v3d->shading.type,
@@ -370,7 +380,7 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
do_color_management,
true,
self->ofs,
- NULL);
+ self->viewport);
GPU_offscreen_unbind(self->ofs, true);
@@ -391,6 +401,11 @@ static PyObject *pygpu_offscreen_free(BPyGPUOffScreen *self)
{
BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ if (self->viewport) {
+ GPU_viewport_free(self->viewport);
+ self->viewport = NULL;
+ }
+
GPU_offscreen_free(self->ofs);
self->ofs = NULL;
Py_RETURN_NONE;
@@ -399,6 +414,9 @@ static PyObject *pygpu_offscreen_free(BPyGPUOffScreen *self)
static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self)
{
+ if (self->viewport) {
+ GPU_viewport_free(self->viewport);
+ }
if (self->ofs) {
GPU_offscreen_free(self->ofs);
}
@@ -469,6 +487,7 @@ PyObject *BPyGPUOffScreen_CreatePyObject(GPUOffScreen *ofs)
self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type);
self->ofs = ofs;
+ self->viewport = NULL;
return (PyObject *)self;
}
diff --git a/source/blender/python/gpu/gpu_py_offscreen.h b/source/blender/python/gpu/gpu_py_offscreen.h
index 309735a6202..78bad595a3d 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.h
+++ b/source/blender/python/gpu/gpu_py_offscreen.h
@@ -26,9 +26,13 @@ extern PyTypeObject BPyGPUOffScreen_Type;
#define BPyGPUOffScreen_Check(v) (Py_TYPE(v) == &BPyGPUOffScreen_Type)
+struct GPUOffscreen;
+struct GPUViewport;
+
typedef struct BPyGPUOffScreen {
PyObject_HEAD
struct GPUOffScreen *ofs;
+ struct GPUViewport *viewport;
} BPyGPUOffScreen;
PyObject *BPyGPUOffScreen_CreatePyObject(struct GPUOffScreen *ofs) ATTR_NONNULL(1);
diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c
index 4db102118f1..43980530f38 100644
--- a/source/blender/python/gpu/gpu_py_select.c
+++ b/source/blender/python/gpu/gpu_py_select.c
@@ -56,6 +56,7 @@ static PyObject *pygpu_select_load_id(PyObject *UNUSED(self), PyObject *value)
GPU_select_load_id(id);
Py_RETURN_NONE;
}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/python/gpu/gpu_py_texture.c b/source/blender/python/gpu/gpu_py_texture.c
index c034c31d828..66b9cf5e86e 100644
--- a/source/blender/python/gpu/gpu_py_texture.c
+++ b/source/blender/python/gpu/gpu_py_texture.c
@@ -527,6 +527,7 @@ PyTypeObject BPyGPUTexture_Type = {
/* -------------------------------------------------------------------- */
/** \name GPU Texture module
* \{ */
+
PyDoc_STRVAR(pygpu_texture_from_image_doc,
".. function:: from_image(image)\n"
"\n"
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 3377b2c283e..c792773272b 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -94,10 +94,13 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self))
return ret;
}
-static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
+static bool bpy_blend_foreach_path_cb(BPathForeachPathData *bpath_data,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- PyList_APPEND((PyObject *)userdata, PyC_UnicodeFromByte(path_src));
- return false; /* never edits the path */
+ PyObject *py_list = bpath_data->user_data;
+ PyList_APPEND(py_list, PyC_UnicodeFromByte(path_src));
+ return false; /* Never edits the path. */
}
PyDoc_STRVAR(bpy_blend_paths_doc,
@@ -115,7 +118,7 @@ PyDoc_STRVAR(bpy_blend_paths_doc,
" :rtype: list of strings\n");
static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- int flag = 0;
+ eBPathForeachFlag flag = 0;
PyObject *list;
bool absolute = false;
@@ -137,18 +140,23 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
}
if (absolute) {
- flag |= BKE_BPATH_TRAVERSE_ABS;
+ flag |= BKE_BPATH_FOREACH_PATH_ABSOLUTE;
}
if (!packed) {
- flag |= BKE_BPATH_TRAVERSE_SKIP_PACKED;
+ flag |= BKE_BPATH_FOREACH_PATH_SKIP_PACKED;
}
if (local) {
- flag |= BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
+ flag |= BKE_BPATH_FOREACH_PATH_SKIP_LINKED;
}
list = PyList_New(0);
- BKE_bpath_traverse_main(G_MAIN, bpy_blend_paths_visit_cb, flag, (void *)list);
+ BKE_bpath_foreach_path_main(&(BPathForeachPathData){
+ .bmain = G_MAIN,
+ .callback_function = bpy_blend_foreach_path_cb,
+ .flag = flag,
+ .user_data = list,
+ });
return list;
}
@@ -442,9 +450,6 @@ static PyObject *bpy_import_test(const char *modname)
return mod;
}
-/******************************************************************************
- * Description: Creates the bpy module and adds it to sys.modules for importing
- ******************************************************************************/
void BPy_init_modules(struct bContext *C)
{
PointerRNA ctx_ptr;
diff --git a/source/blender/python/intern/bpy.h b/source/blender/python/intern/bpy.h
index 25a047edfb5..b77a3e9fb7d 100644
--- a/source/blender/python/intern/bpy.h
+++ b/source/blender/python/intern/bpy.h
@@ -26,7 +26,9 @@ extern "C" {
struct bContext;
+/** Creates the bpy module and adds it to `sys.modules` for importing. */
void BPy_init_modules(struct bContext *C);
+
extern PyObject *bpy_package_py;
/* bpy_interface_atexit.c */
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index de70035eb2b..4fa71c0c976 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -69,12 +69,12 @@ static BlenderAppTranslations *_translations = NULL;
/** \} */
-#ifdef WITH_INTERNATIONAL
-
/* ------------------------------------------------------------------- */
/** \name Helpers for GHash
* \{ */
+#ifdef WITH_INTERNATIONAL
+
typedef struct GHashKey {
const char *msgctxt;
const char *msgid;
diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c
index 8e9d8c02c03..ed01132ed4e 100644
--- a/source/blender/python/intern/bpy_capi_utils.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -56,9 +56,6 @@ short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool
return (report_str == NULL) ? 0 : -1;
}
-/**
- * A version of #BKE_report_write_file_fp that uses Python's stdout.
- */
void BPy_reports_write_stdout(const ReportList *reports, const char *header)
{
if (header) {
diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h
index 80e92d918ac..0e4a28fb657 100644
--- a/source/blender/python/intern/bpy_capi_utils.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -33,6 +33,9 @@ struct ReportList;
/* error reporting */
short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear);
+/**
+ * A version of #BKE_report_write_file_fp that uses Python's stdout.
+ */
void BPy_reports_write_stdout(const struct ReportList *reports, const char *header);
bool BPy_errors_to_report_ex(struct ReportList *reports,
const char *error_prefix,
@@ -44,6 +47,9 @@ bool BPy_errors_to_report(struct ReportList *reports);
struct bContext *BPY_context_get(void);
extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate);
+/**
+ * Context should be used but not now because it causes some bugs.
+ */
extern void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate);
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 7effa25e6e8..bd1f3cd301f 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -57,19 +57,12 @@
# include <opcode.h>
#endif
-/**
- * For PyDrivers
- * (drivers using one-line Python expressions to express relationships between targets).
- */
PyObject *bpy_pydriver_Dict = NULL;
#ifdef USE_BYTECODE_WHITELIST
static PyObject *bpy_pydriver_Dict__whitelist = NULL;
#endif
-/* For faster execution we keep a special dictionary for pydrivers, with
- * the needed modules and aliases.
- */
int bpy_pydriver_create_dict(void)
{
PyObject *d, *mod;
@@ -220,11 +213,6 @@ static void bpy_pydriver_namespace_clear_self(void)
}
}
-/* Update function, it gets rid of pydrivers global dictionary, forcing
- * BPY_driver_exec to recreate it. This function is used to force
- * reloading the Blender text module "pydrivers.py", if available, so
- * updates in it reach pydriver evaluation.
- */
void BPY_driver_reset(void)
{
PyGILState_STATE gilstate;
@@ -429,28 +417,24 @@ static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars,
}
}
-/**
- * This evaluates Python driver expressions, `driver_orig->expression`
- * is a Python expression that should evaluate to a float number, which is returned.
- *
- * (old) NOTE: PyGILState_Ensure() isn't always called because python can call
- * the bake operator which intern starts a thread which calls scene update
- * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
- * if #PyGILState_Ensure() is needed, see T27683.
- *
- * (new) NOTE: checking if python is running is not thread-safe T28114
- * now release the GIL on python operator execution instead, using
- * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
- *
- * For copy-on-write we always cache expressions and write errors in the
- * original driver, otherwise these would get freed while editing. Due to
- * the GIL this is thread-safe.
- */
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
ChannelDriver *driver,
ChannelDriver *driver_orig,
const AnimationEvalContext *anim_eval_context)
{
+ /* (old) NOTE: PyGILState_Ensure() isn't always called because python can call
+ * the bake operator which intern starts a thread which calls scene update
+ * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
+ * if #PyGILState_Ensure() is needed, see T27683.
+ *
+ * (new) NOTE: checking if python is running is not thread-safe T28114
+ * now release the GIL on python operator execution instead, using
+ * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
+ *
+ * For copy-on-write we always cache expressions and write errors in the
+ * original driver, otherwise these would get freed while editing.
+ * Due to the GIL this is thread-safe. */
+
PyObject *driver_vars = NULL;
PyObject *retval = NULL;
diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h
index d5064d9fa56..b7bb0f846e8 100644
--- a/source/blender/python/intern/bpy_driver.h
+++ b/source/blender/python/intern/bpy_driver.h
@@ -24,7 +24,15 @@
extern "C" {
#endif
+/**
+ * For faster execution we keep a special dictionary for py-drivers, with
+ * the needed modules and aliases.
+ */
int bpy_pydriver_create_dict(void);
+/**
+ * For PyDrivers
+ * (drivers using one-line Python expressions to express relationships between targets).
+ */
extern PyObject *bpy_pydriver_Dict;
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 95affa9dba9..faa668df775 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -80,6 +80,7 @@
#include "../mathutils/mathutils.h"
/* Logging types to use anywhere in the Python modules. */
+
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_CONTEXT, "bpy.context");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_INTERFACE, "bpy.interface");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna");
@@ -103,7 +104,6 @@ static double bpy_timer_run; /* time for each python script run */
static double bpy_timer_run_tot; /* accumulate python runs */
#endif
-/* use for updating while a python script runs - in case of file load */
void BPY_context_update(bContext *C)
{
/* don't do this from a non-main (e.g. render) thread, it can cause a race
@@ -141,7 +141,6 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
}
}
-/* context should be used but not now because it causes some bugs */
void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
{
py_call_level--;
@@ -175,16 +174,6 @@ static void bpy_context_end(bContext *C)
CTX_wm_operator_poll_msg_clear(C);
}
-/**
- * Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
- * In this case we don't want the Python context to override the values as it causes problems
- * see T66256.
- *
- * \param dict_p: A pointer to #bContext.data.py_context so we can assign a new value.
- * \param dict_orig: The value of #bContext.data.py_context_orig to check if we need to copy.
- *
- * \note Typically accessed via #BPY_context_dict_clear_members macro.
- */
void BPY_context_dict_clear_members_array(void **dict_p,
void *dict_orig,
const char *context_members[],
@@ -238,9 +227,6 @@ void BPY_text_free_code(Text *text)
}
}
-/**
- * Needed so the #Main pointer in `bpy.data` doesn't become out of date.
- */
void BPY_modules_update(void)
{
#if 0 /* slow, this runs all the time poll, draw etc 100's of time a sec. */
@@ -333,7 +319,6 @@ static void pystatus_exit_on_error(PyStatus status)
}
#endif
-/* call BPY_context_set first */
void BPY_python_start(bContext *C, int argc, const char **argv)
{
#ifndef WITH_PYTHON_MODULE
@@ -881,9 +866,6 @@ static void bpy_module_free(void *UNUSED(mod))
#endif
-/**
- * Avoids duplicating keyword list.
- */
bool BPY_string_is_keyword(const char *str)
{
/* list is from...
@@ -905,8 +887,7 @@ bool BPY_string_is_keyword(const char *str)
return false;
}
-/* EVIL, define text.c functions here... */
-/* BKE_text.h */
+/* EVIL: define `text.c` functions here (declared in `BKE_text.h`). */
int text_check_identifier_unicode(const uint ch)
{
return (ch < 255 && text_check_identifier((char)ch)) || Py_UNICODE_ISALNUM(ch);
diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c
index f7d6a33c904..bc21c91074f 100644
--- a/source/blender/python/intern/bpy_interface_run.c
+++ b/source/blender/python/intern/bpy_interface_run.c
@@ -80,6 +80,14 @@ typedef struct {
} PyModuleObject;
#endif
+/**
+ * Execute a file-path or text-block.
+ *
+ * \param reports: Report exceptions as errors (may be NULL).
+ * \param do_jump: See #BPY_run_text.
+ *
+ * \note Share a function for this since setup/cleanup logic is the same.
+ */
static bool python_script_exec(
bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump)
{
@@ -212,7 +220,6 @@ static bool python_script_exec(
/** \name Run Text / Filename / String
* \{ */
-/* Can run a file or text block */
bool BPY_run_filepath(bContext *C, const char *filepath, struct ReportList *reports)
{
return python_script_exec(C, filepath, NULL, reports, false);
@@ -271,17 +278,11 @@ static bool bpy_run_string_impl(bContext *C,
return ok;
}
-/**
- * Run an expression, matches: `exec(compile(..., "eval"))`
- */
bool BPY_run_string_eval(bContext *C, const char *imports[], const char *expr)
{
return bpy_run_string_impl(C, imports, expr, Py_eval_input);
}
-/**
- * Run an entire script, matches: `exec(compile(..., "exec"))`
- */
bool BPY_run_string_exec(bContext *C, const char *imports[], const char *expr)
{
return bpy_run_string_impl(C, imports, expr, Py_file_input);
@@ -330,9 +331,6 @@ static void run_string_handle_error(struct BPy_RunErrInfo *err_info)
Py_XDECREF(py_err_str);
}
-/**
- * \return success
- */
bool BPY_run_string_as_number(bContext *C,
const char *imports[],
const char *expr,
@@ -342,10 +340,6 @@ bool BPY_run_string_as_number(bContext *C,
PyGILState_STATE gilstate;
bool ok = true;
- if (!r_value || !expr) {
- return -1;
- }
-
if (expr[0] == '\0') {
*r_value = 0.0;
return ok;
@@ -364,9 +358,6 @@ bool BPY_run_string_as_number(bContext *C,
return ok;
}
-/**
- * \return success
- */
bool BPY_run_string_as_string_and_size(bContext *C,
const char *imports[],
const char *expr,
@@ -374,7 +365,6 @@ bool BPY_run_string_as_string_and_size(bContext *C,
char **r_value,
size_t *r_value_size)
{
- BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
bool ok = true;
@@ -406,18 +396,12 @@ bool BPY_run_string_as_string(bContext *C,
return BPY_run_string_as_string_and_size(C, imports, expr, err_info, r_value, &value_dummy_size);
}
-/**
- * Support both int and pointers.
- *
- * \return success
- */
bool BPY_run_string_as_intptr(bContext *C,
const char *imports[],
const char *expr,
struct BPy_RunErrInfo *err_info,
intptr_t *r_value)
{
- BLI_assert(r_value && expr);
PyGILState_STATE gilstate;
bool ok = true;
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 059d692a9ba..fe279c0b940 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -34,6 +34,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -346,11 +347,63 @@ static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
PyErr_Restore(exc, val, tb);
}
+struct LibExitLappContextItemsIterData {
+ short idcode;
+ BPy_Library *py_library;
+ PyObject *py_list;
+ Py_ssize_t py_list_size;
+};
+
+static bool bpy_lib_exit_lapp_context_items_cb(BlendfileLinkAppendContext *lapp_context,
+ BlendfileLinkAppendContextItem *item,
+ void *userdata)
+{
+ struct LibExitLappContextItemsIterData *data = userdata;
+
+ /* Since `bpy_lib_exit` loops over all ID types, all items in `lapp_context` end up being looped
+ * over for each ID type, so when it does not match the item can simply be skipped: it either has
+ * already been processed, or will be processed in a later loop. */
+ if (BKE_blendfile_link_append_context_item_idcode_get(lapp_context, item) != data->idcode) {
+ return true;
+ }
+
+ const int py_list_index = POINTER_AS_INT(
+ BKE_blendfile_link_append_context_item_userdata_get(lapp_context, item));
+ ID *new_id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);
+
+ BLI_assert(py_list_index < data->py_list_size);
+
+ /* Fully invalid items (which got set to `Py_None` already in first loop of `bpy_lib_exit`)
+ * should never be accessed here, since their index should never be set to any item in
+ * `lapp_context`. */
+ PyObject *item_src = PyList_GET_ITEM(data->py_list, py_list_index);
+ BLI_assert(item_src != Py_None);
+
+ PyObject *py_item;
+ if (new_id != NULL) {
+ PointerRNA newid_ptr;
+ RNA_id_pointer_create(new_id, &newid_ptr);
+ py_item = pyrna_struct_CreatePyObject(&newid_ptr);
+ }
+ else {
+ const char *item_idname = PyUnicode_AsUTF8(item_src);
+ const char *idcode_name_plural = BKE_idtype_idcode_to_name_plural(data->idcode);
+
+ bpy_lib_exit_warn_idname(data->py_library, idcode_name_plural, item_idname);
+
+ py_item = Py_INCREF_RET(Py_None);
+ }
+
+ PyList_SET_ITEM(data->py_list, py_list_index, py_item);
+
+ Py_DECREF(item_src);
+
+ return true;
+}
+
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
Main *bmain = self->bmain;
- Main *mainl = NULL;
- const int err = 0;
const bool do_append = ((self->flag & FILE_LINK) == 0);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
@@ -360,134 +413,100 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
struct LibraryLink_Params liblink_params;
BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra);
- mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params);
-
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
- if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
- const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- // printf("lib: %s\n", name_plural);
- if (ls && PyList_Check(ls)) {
- /* loop */
- const Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
-
- for (i = 0; i < size; i++) {
- PyObject *item_src = PyList_GET_ITEM(ls, i);
- PyObject *item_dst; /* must be set below */
- const char *item_idname = PyUnicode_AsUTF8(item_src);
-
- // printf(" %s\n", item_idname);
-
- if (item_idname) {
- ID *id = BLO_library_link_named_part(
- mainl, &(self->blo_handle), idcode, item_idname, &liblink_params);
- if (id) {
-
- if (self->bmain_is_temp) {
- /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */
- BLI_assert(id->tag & LIB_TAG_TEMP_MAIN);
- }
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(
+ &liblink_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, self->abspath, self->blo_handle);
-#ifdef USE_RNA_DATABLOCKS
- /* swap name for pointer to the id */
- item_dst = PyCapsule_New((void *)id, NULL, NULL);
-#else
- /* leave as is */
- continue;
-#endif
- }
- else {
- bpy_lib_exit_warn_idname(self, name_plural, item_idname);
- /* just warn for now */
- /* err = -1; */
- item_dst = Py_INCREF_RET(Py_None);
- }
-
- /* ID or None */
- }
- else {
- /* XXX, could complain about this */
- bpy_lib_exit_warn_type(self, item_src);
- PyErr_Clear();
- item_dst = Py_INCREF_RET(Py_None);
- }
-
- /* item_dst must be new or already incref'd */
- Py_DECREF(item_src);
- PyList_SET_ITEM(ls, i, item_dst);
- }
- }
- }
+ int idcode_step = 0;
+ short idcode;
+ while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) {
+ continue;
}
- }
- if (err == -1) {
- /* exception raised above, XXX, this leaks some memory */
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- return NULL;
- }
+ const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls == NULL || !PyList_Check(ls)) {
+ continue;
+ }
- Library *lib = mainl->curlib; /* newly added lib, assign before append end */
- BLO_library_link_end(mainl, &(self->blo_handle), &liblink_params);
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
+ const Py_ssize_t size = PyList_GET_SIZE(ls);
+ if (size == 0) {
+ continue;
+ }
- GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__);
+ /* loop */
+ for (Py_ssize_t i = 0; i < size; i++) {
+ PyObject *item_src = PyList_GET_ITEM(ls, i);
+ const char *item_idname = PyUnicode_AsUTF8(item_src);
- /* copied from wm_operator.c */
- {
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
+ // printf(" %s\n", item_idname);
- /* append, rather than linking */
- if (do_append) {
- BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
+ /* NOTE: index of item in py list is stored in userdata pointer, so that it can be found
+ * later on to replace the ID name by the actual ID pointer. */
+ if (item_idname != NULL) {
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, item_idname, idcode, POINTER_FROM_INT(i));
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
+ }
+ else {
+ /* XXX, could complain about this */
+ bpy_lib_exit_warn_type(self, item_src);
+ PyErr_Clear();
+
+#ifdef USE_RNA_DATABLOCKS
+ /* We can replace the item immediately with `None`. */
+ PyObject *py_item = Py_INCREF_RET(Py_None);
+ PyList_SET_ITEM(ls, i, py_item);
+ Py_DECREF(item_src);
+#endif
+ }
}
}
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+ BKE_blendfile_link(lapp_context, NULL);
+ if (do_append) {
+ BKE_blendfile_append(lapp_context, NULL);
+ }
- /* finally swap the capsules for real bpy objects
- * important since BLO_library_append_end initializes NodeTree types used by srna->refine */
+ /* If enabled, replace named items in given lists by the final matching new ID pointer. */
#ifdef USE_RNA_DATABLOCKS
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
- if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
- const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- if (ls && PyList_Check(ls)) {
- const Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
- PyObject *item;
-
- for (i = 0; i < size; i++) {
- item = PyList_GET_ITEM(ls, i);
- if (PyCapsule_CheckExact(item)) {
- PointerRNA id_ptr;
- ID *id;
-
- id = PyCapsule_GetPointer(item, NULL);
- id = BLI_ghash_lookup_default(old_to_new_ids, id, id);
- Py_DECREF(item);
-
- RNA_id_pointer_create(id, &id_ptr);
- item = pyrna_struct_CreatePyObject(&id_ptr);
- PyList_SET_ITEM(ls, i, item);
- }
- }
- }
- }
+ idcode_step = 0;
+ while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
+ if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) {
+ continue;
+ }
+ const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls == NULL || !PyList_Check(ls)) {
+ continue;
}
+
+ const Py_ssize_t size = PyList_GET_SIZE(ls);
+ if (size == 0) {
+ continue;
+ }
+
+ /* Loop over linked items in `lapp_context` to find matching python one in the list, and
+ * replace them with proper ID pointer. */
+ struct LibExitLappContextItemsIterData iter_data = {
+ .idcode = idcode, .py_library = self, .py_list = ls, .py_list_size = size};
+ BKE_blendfile_link_append_context_item_foreach(
+ lapp_context,
+ bpy_lib_exit_lapp_context_items_cb,
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT,
+ &iter_data);
}
-#endif /* USE_RNA_DATABLOCKS */
+#endif // USE_RNA_DATABLOCKS
+
+ BLO_blendhandle_close(self->blo_handle);
+ self->blo_handle = NULL;
+
+ BKE_blendfile_link_append_context_free(lapp_context);
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- BLI_ghash_free(old_to_new_ids, NULL, NULL);
Py_RETURN_NONE;
}
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index c2d7257e458..bee64f5de2c 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -115,10 +115,6 @@ static void operator_properties_init(wmOperatorType *ot)
/* end 'ot->prop' assignment */
}
-/**
- * Generic function used by all Python defined operators
- * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
- */
void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
{
/* take care not to overwrite anything set in
@@ -135,10 +131,6 @@ void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
operator_properties_init(ot);
}
-/**
- * Generic function used by all Python defined macro-operators
- * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
- */
void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata)
{
wmOperatorType *data = (wmOperatorType *)userdata;
diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h
index 9e496cd8d26..41deb06814b 100644
--- a/source/blender/python/intern/bpy_operator_wrap.h
+++ b/source/blender/python/intern/bpy_operator_wrap.h
@@ -30,7 +30,15 @@ extern "C" {
PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args);
/* exposed to rna/wm api */
+/**
+ * Generic function used by all Python defined operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata);
+/**
+ * Generic function used by all Python defined macro-operators
+ * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration.
+ */
void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata);
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 13c7d2947cf..ed9547ee13f 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -434,6 +434,10 @@ static PyObject *bpy_prop_deferred_data_CreatePyObject(PyObject *fn, PyObject *k
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Shared Property Utilities
+ * \{ */
+
/* PyObject's */
static PyObject *pymeth_BoolProperty = NULL;
static PyObject *pymeth_BoolVectorProperty = NULL;
@@ -2630,10 +2634,14 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" This function must take 2 values (self, value) and return None.\n" \
" :type set: function\n"
-#define BPY_PROPDEF_TYPE_DOC \
+#define BPY_PROPDEF_POINTER_TYPE_DOC \
" :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
" :type type: class\n"
+#define BPY_PROPDEF_COLLECTION_TYPE_DOC \
+ " :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \
+ " :type type: class\n"
+
#define BPY_PROPDEF_TAGS_DOC \
" :arg tags: Enumerator of tags that are defined by parent class.\n" \
" :type tags: set\n"
@@ -3981,7 +3989,7 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
"update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
- "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ "\n" BPY_PROPDEF_POINTER_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
BPY_PROPDEF_POLL_DOC BPY_PROPDEF_UPDATE_DOC);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -4104,7 +4112,7 @@ PyDoc_STRVAR(BPy_CollectionProperty_doc,
"tags=set())\n"
"\n"
" Returns a new collection property definition.\n"
- "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
+ "\n" BPY_PROPDEF_COLLECTION_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC
BPY_PROPDEF_TAGS_DOC);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -4392,10 +4400,6 @@ PyObject *BPY_rna_props(void)
return submodule;
}
-/**
- * Run this on exit, clearing all Python callback users and disable the RNA callback,
- * as it would be called after Python has already finished.
- */
void BPY_rna_props_clear_all(void)
{
/* Remove all user counts, so this isn't considered a leak from Python's perspective. */
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index e6bbd6f708d..9d739540919 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -25,6 +25,10 @@ extern "C" {
#endif
PyObject *BPY_rna_props(void);
+/**
+ * Run this on exit, clearing all Python callback users and disable the RNA callback,
+ * as it would be called after Python has already finished.
+ */
void BPY_rna_props_clear_all(void);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 707de1c2581..a79a0ed32bf 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1462,10 +1462,6 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
return ret;
}
-/**
- * This function is used by operators and converting dicts into collections.
- * It takes keyword args and fills them with property values.
- */
int pyrna_pydict_to_props(PointerRNA *ptr,
PyObject *kw,
const bool all_args,
@@ -7545,7 +7541,6 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop)
return (PyObject *)pyrna;
}
-/* Utility func to be used by external modules, sneaky! */
PyObject *pyrna_id_CreatePyObject(ID *id)
{
if (id) {
@@ -7777,9 +7772,6 @@ static struct PyModuleDef bpy_types_module_def = {
NULL, /* m_free */
};
-/**
- * Accessed from Python as 'bpy.types'
- */
PyObject *BPY_rna_types(void)
{
PyObject *submodule = PyModule_Create(&bpy_types_module_def);
@@ -7864,11 +7856,6 @@ StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *e
}
/* Orphan functions, not sure where they should go. */
-/**
- * Get the SRNA for methods attached to types.
- *
- * Caller needs to raise error.
- */
StructRNA *srna_from_self(PyObject *self, const char *error_prefix)
{
@@ -9094,9 +9081,6 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
Py_RETURN_NONE;
}
-/**
- * Extend RNA types with C/API methods, properties.
- */
void pyrna_struct_type_extend_capi(struct StructRNA *srna,
struct PyMethodDef *method,
struct PyGetSetDef *getset)
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 2096734ef96..9a6339c0a89 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -401,6 +401,10 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
return NULL;
}
+ if (result) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+
return PyBool_FromLong(result);
}
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index fcc796d4545..270c9ad431c 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -990,9 +990,10 @@ PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
return pyrna_prop_CreatePyObject(ptr, prop);
}
-/* TODO: multi-dimensional arrays. */
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
{
+ /* TODO: multi-dimensional arrays. */
+
const int len = RNA_property_array_length(ptr, prop);
int type;
int i;
diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c
index 639999b69d4..c781fe4a4e7 100644
--- a/source/blender/python/intern/bpy_rna_data.c
+++ b/source/blender/python/intern/bpy_rna_data.c
@@ -177,7 +177,7 @@ static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args,
ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type);
- STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name);
+ STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->filepath);
return (PyObject *)ret;
}
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index 3bddd0ad8c0..0bb8b1ba3e1 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -34,9 +34,6 @@
#include "bpy_rna_driver.h" /* own include */
-/**
- * A version of #driver_get_variable_value which returns a PyObject.
- */
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar)
{
PyObject *driver_arg = NULL;
diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h
index cc2c4550870..e34c7e4597c 100644
--- a/source/blender/python/intern/bpy_rna_driver.h
+++ b/source/blender/python/intern/bpy_rna_driver.h
@@ -28,6 +28,9 @@ struct PathResolvedRNA;
extern "C" {
#endif
+/**
+ * A version of #driver_get_variable_value which returns a #PyObject.
+ */
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna);
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 0043fc36162..6eee9ceebb8 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -77,11 +77,6 @@ static int mathutils_array_parse_fast(float *array,
return size;
}
-/**
- * helper function that returns a Python `__hash__`.
- *
- * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
- */
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
{
int i;
@@ -114,7 +109,6 @@ Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
return x;
}
-/* helper function returns length of the 'value', -1 on error */
int mathutils_array_parse(
float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
@@ -211,7 +205,6 @@ int mathutils_array_parse(
return size;
}
-/* on error, -1 is returned and no allocation is made */
int mathutils_array_parse_alloc(float **array,
int array_min,
PyObject *value,
@@ -279,7 +272,6 @@ int mathutils_array_parse_alloc(float **array,
return ret;
}
-/* parse an array of vectors */
int mathutils_array_parse_alloc_v(float **array,
int array_dim,
PyObject *value,
@@ -321,7 +313,6 @@ int mathutils_array_parse_alloc_v(float **array,
return size;
}
-/* Parse an sequence array_dim integers into array. */
int mathutils_int_array_parse(int *array, int array_dim, PyObject *value, const char *error_prefix)
{
int size, i;
@@ -357,7 +348,6 @@ int mathutils_int_array_parse(int *array, int array_dim, PyObject *value, const
return size;
}
-/* Parse sequence of array_dim sequences of integers and return allocated result. */
int mathutils_array_parse_alloc_vi(int **array,
int array_dim,
PyObject *value,
@@ -395,12 +385,6 @@ int mathutils_array_parse_alloc_vi(int **array,
return size;
}
-/* Parse sequence of variable-length sequences of int and return allocated
- * triple of arrays to represent the result:
- * The flattened sequences are put into *array.
- * The start index of each sequence goes into start_table.
- * The length of each index goes into len_table.
- */
int mathutils_array_parse_alloc_viseq(
int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix)
{
@@ -560,7 +544,6 @@ int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int flo
}
#ifndef MATH_STANDALONE
-/* dynstr as python string utility functions, frees 'ds'! */
PyObject *mathutils_dynstr_to_py(struct DynStr *ds)
{
const int ds_len = BLI_dynstr_get_len(ds); /* space for \0 */
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index 4aa26dcc5be..d73d2afe69b 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -162,28 +162,56 @@ void _BaseMathObject_RaiseNotFrozenExc(const BaseMathObject *self);
0)
/* utility func */
+/**
+ * Helper function.
+ * \return length of `value`, -1 on error.
+ */
int mathutils_array_parse(
float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
+/**
+ * \return -1 is returned on error and no allocation is made.
+ */
int mathutils_array_parse_alloc(float **array,
int array_min,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse an array of vectors.
+ */
int mathutils_array_parse_alloc_v(float **array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse an sequence array_dim integers into array.
+ */
int mathutils_int_array_parse(int *array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse sequence of array_dim sequences of integers and return allocated result.
+ */
int mathutils_array_parse_alloc_vi(int **array,
int array_dim,
PyObject *value,
const char *error_prefix);
+/**
+ * Parse sequence of variable-length sequences of int and return allocated
+ * triple of arrays to represent the result:
+ * The flattened sequences are put into *array.
+ * The start index of each sequence goes into start_table.
+ * The length of each index goes into len_table.
+ */
int mathutils_array_parse_alloc_viseq(
int **array, int **start_table, int **len_table, PyObject *value, const char *error_prefix);
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
+/**
+ * helper function that returns a Python `__hash__`.
+ *
+ * \note consistent with the equivalent tuple of floats (CPython's 'tuplehash')
+ */
Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len);
/* zero remaining unused elements of the array */
@@ -194,9 +222,21 @@ Py_hash_t mathutils_array_hash(const float *float_array, size_t array_len);
#define MU_ARRAY_FLAGS (MU_ARRAY_ZERO | MU_ARRAY_SPILL)
+/**
+ * Column vector multiplication (Matrix * Vector).
+ * <pre>
+ * [1][4][7] [a]
+ * [2][5][8] * [b]
+ * [3][6][9] [c]
+ * </pre>
+ *
+ * \note Vector/Matrix multiplication is not commutative.
+ * \note Assume read callbacks have been done first.
+ */
int column_vector_multiplication(float r_vec[4], VectorObject *vec, MatrixObject *mat);
#ifndef MATH_STANDALONE
/* dynstr as python string utility functions */
+/* dynstr as python string utility functions, frees 'ds'! */
PyObject *mathutils_dynstr_to_py(struct DynStr *ds);
#endif
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 28b91e13d47..4396e2f9c7b 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -3382,9 +3382,6 @@ PyObject *Matrix_CreatePyObject_cb(
return (PyObject *)self;
}
-/**
- * \param mat: Initialized matrix value to use in-place, allocated with #PyMem_Malloc
- */
PyObject *Matrix_CreatePyObject_alloc(float *mat,
const ushort num_col,
const ushort num_row,
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 588c0b94891..56bb4d39d01 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -75,6 +75,9 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *user,
unsigned char cb_type,
unsigned char cb_subtype) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \param mat: Initialized matrix value to use in-place, allocated with #PyMem_Malloc
+ */
PyObject *Matrix_CreatePyObject_alloc(float *mat,
const ushort num_col,
const ushort num_row,
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 23758c5603e..daaf3b3da26 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -1676,17 +1676,6 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2)
/*------------------------obj * obj------------------------------
* multiplication */
-/**
- * Column vector multiplication (Matrix * Vector).
- * <pre>
- * [1][4][7] [a]
- * [2][5][8] * [b]
- * [3][6][9] [c]
- * </pre>
- *
- * \note Vector/Matrix multiplication is not commutative.
- * \note Assume read callbacks have been done first.
- */
int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat)
{
float vec_cpy[MAX_DIMENSIONS];
@@ -3166,11 +3155,6 @@ PyObject *Vector_CreatePyObject(const float *vec, const int size, PyTypeObject *
return (PyObject *)self;
}
-/**
- * Create a vector that wraps existing memory.
- *
- * \param vec: Use this vector in-place.
- */
PyObject *Vector_CreatePyObject_wrap(float *vec, const int size, PyTypeObject *base_type)
{
VectorObject *self;
@@ -3194,10 +3178,6 @@ PyObject *Vector_CreatePyObject_wrap(float *vec, const int size, PyTypeObject *b
return (PyObject *)self;
}
-/**
- * Create a vector where the value is defined by registered callbacks,
- * see: #Mathutils_RegisterCallback
- */
PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, uchar cb_type, uchar cb_subtype)
{
VectorObject *self = (VectorObject *)Vector_CreatePyObject(NULL, size, NULL);
@@ -3212,9 +3192,6 @@ PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int size, uchar cb_type, u
return (PyObject *)self;
}
-/**
- * \param vec: Initialized vector value to use in-place, allocated with #PyMem_Malloc
- */
PyObject *Vector_CreatePyObject_alloc(float *vec, const int size, PyTypeObject *base_type)
{
VectorObject *self;
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index 09fc429f9cc..fb420b32df4 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -35,14 +35,26 @@ typedef struct {
PyObject *Vector_CreatePyObject(const float *vec,
const int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Create a vector that wraps existing memory.
+ *
+ * \param vec: Use this vector in-place.
+ */
PyObject *Vector_CreatePyObject_wrap(float *vec,
const int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
+/**
+ * Create a vector where the value is defined by registered callbacks,
+ * see: #Mathutils_RegisterCallback
+ */
PyObject *Vector_CreatePyObject_cb(PyObject *user,
int size,
unsigned char cb_type,
unsigned char subtype) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \param vec: Initialized vector value to use in-place, allocated with #PyMem_Malloc
+ */
PyObject *Vector_CreatePyObject_alloc(float *vec,
const int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/render/RE_bake.h b/source/blender/render/RE_bake.h
index 47a15199701..b2c44e051d1 100644
--- a/source/blender/render/RE_bake.h
+++ b/source/blender/render/RE_bake.h
@@ -120,6 +120,10 @@ void RE_bake_normal_world_to_object(const BakePixel pixel_array[],
float result[],
struct Object *ob,
const eBakeNormalSwizzle normal_swizzle[3]);
+/**
+ * This function converts an object space normal map
+ * to a tangent space normal map for a given low poly mesh.
+ */
void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
const size_t num_pixels,
const int depth,
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index 2a3a5964262..b22d263490c 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -180,6 +180,10 @@ typedef struct RenderEngine {
RenderEngine *RE_engine_create(RenderEngineType *type);
void RE_engine_free(RenderEngine *engine);
+/**
+ * Loads in image into a result, size must match
+ * x/y offsets are only used on a partial copy when dimensions don't match.
+ */
void RE_layer_load_from_file(
struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y);
void RE_result_load_from_file(struct RenderResult *result,
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 0d2d93ae026..073bb0a3697 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -167,8 +167,10 @@ typedef struct RenderStats {
/* *********************** API ******************** */
-/* the name is used as identifier, so elsewhere in blender the result can retrieved */
-/* calling a new render with same name, frees automatic existing render */
+/**
+ * The name is used as identifier, so elsewhere in blender the result can retrieved.
+ * Calling a new render with same name, frees automatic existing render.
+ */
struct Render *RE_NewRender(const char *name);
struct Render *RE_GetRender(const char *name);
@@ -176,36 +178,80 @@ struct Scene;
struct Render *RE_NewSceneRender(const struct Scene *scene);
struct Render *RE_GetSceneRender(const struct Scene *scene);
-/* assign default dummy callbacks */
+/* Assign default dummy callbacks. */
+
+/**
+ * Called for new renders and when finishing rendering
+ * so we always have valid callbacks on a render.
+ */
void RE_InitRenderCB(struct Render *re);
-/* use free render as signal to do everything over (previews) */
+/**
+ * Use free render as signal to do everything over (previews).
+ *
+ * Only call this while you know it will remove the link too.
+ */
void RE_FreeRender(struct Render *re);
-/* only called on exit */
+/**
+ * Only called on exit.
+ */
void RE_FreeAllRender(void);
-/* On file load, free render results. */
+/**
+ * On file load, free render results.
+ */
void RE_FreeAllRenderResults(void);
-/* On file load or changes engines, free persistent render data.
- * Assumes no engines are currently rendering. */
+/**
+ * On file load or changes engines, free persistent render data.
+ * Assumes no engines are currently rendering.
+ */
void RE_FreeAllPersistentData(void);
-/* Free persistent render data, optionally only for the given scene. */
+/**
+ * Free persistent render data, optionally only for the given scene.
+ */
void RE_FreePersistentData(const Scene *scene);
-/* get results and statistics */
+/**
+ * Get results and statistics.
+ */
void RE_FreeRenderResult(struct RenderResult *rr);
+/**
+ * If you want to know exactly what has been done.
+ */
struct RenderResult *RE_AcquireResultRead(struct Render *re);
struct RenderResult *RE_AcquireResultWrite(struct Render *re);
void RE_ReleaseResult(struct Render *re);
+/**
+ * Same as #RE_AcquireResultImage but creating the necessary views to store the result
+ * fill provided result struct with a copy of thew views of what is done so far the
+ * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
+ */
void RE_AcquireResultImageViews(struct Render *re, struct RenderResult *rr);
+/**
+ * Clear temporary #RenderResult struct.
+ */
void RE_ReleaseResultImageViews(struct Render *re, struct RenderResult *rr);
+
+/**
+ * Fill provided result struct with what's currently active or done.
+ * This #RenderResult struct is the only exception to the rule of a #RenderResult
+ * always having at least one #RenderView.
+ */
void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, const int view_id);
void RE_ReleaseResultImage(struct Render *re);
void RE_SwapResult(struct Render *re, struct RenderResult **rr);
void RE_ClearResult(struct Render *re);
struct RenderStats *RE_GetStats(struct Render *re);
+/**
+ * Caller is responsible for allocating `rect` in correct size!
+ */
void RE_ResultGet32(struct Render *re, unsigned int *rect);
+/**
+ * Only for acquired results, for lock.
+ *
+ * \note The caller is responsible for allocating `rect` in correct size!
+ */
void RE_AcquiredResultGet32(struct Render *re,
struct RenderResult *result,
unsigned int *rect,
@@ -223,7 +269,10 @@ float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl,
bool RE_HasSingleLayer(struct Render *re);
-/* add passes for grease pencil */
+/**
+ * Add passes for grease pencil.
+ * Create a render-layer and render-pass for grease-pencil layer.
+ */
struct RenderPass *RE_create_gp_pass(struct RenderResult *rr,
const char *layername,
const char *viewname);
@@ -236,7 +285,10 @@ void RE_create_render_pass(struct RenderResult *rr,
const char *viewname,
const bool allocate);
-/* obligatory initialize call, disprect is optional */
+/**
+ * Obligatory initialize call, doesn't change during entire render sequence.
+ * \param disprect: is optional. if NULL it assumes full window render.
+ */
void RE_InitState(struct Render *re,
struct Render *source,
struct RenderData *rd,
@@ -246,15 +298,28 @@ void RE_InitState(struct Render *re,
int winy,
rcti *disprect);
-/* set up the viewplane/perspective matrix, three choices */
-struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */
+/**
+ * Set up the view-plane/perspective matrix, three choices.
+ *
+ * \return camera override if set.
+ */
+struct Object *RE_GetCamera(struct Render *re);
void RE_SetOverrideCamera(struct Render *re, struct Object *cam_ob);
+/**
+ * Per render, there's one persistent view-plane. Parts will set their own view-planes.
+ *
+ * \note call this after #RE_InitState().
+ */
void RE_SetCamera(struct Render *re, struct Object *cam_ob);
-/* get current view and window transform */
+/**
+ * Get current view and window transform.
+ */
void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
-/* Set the render threads based on the command-line and auto-threads setting. */
+/**
+ * Set the render threads based on the command-line and auto-threads setting.
+ */
void RE_init_threadcount(Render *re);
bool RE_WriteRenderViewsImage(struct ReportList *reports,
@@ -271,7 +336,11 @@ bool RE_WriteRenderViewsMovie(struct ReportList *reports,
const int totvideos,
bool preview);
-/* only RE_NewRender() needed, main Blender render calls */
+/**
+ * Only #RE_NewRender() needed, main Blender render calls.
+ *
+ * General Blender frame render call.
+ */
void RE_RenderFrame(struct Render *re,
struct Main *bmain,
struct Scene *scene,
@@ -279,6 +348,9 @@ void RE_RenderFrame(struct Render *re,
struct Object *camera_override,
int frame,
const bool write_still);
+/**
+ * Saves images to disk.
+ */
void RE_RenderAnim(struct Render *re,
struct Main *bmain,
struct Scene *scene,
@@ -298,13 +370,24 @@ void RE_RenderFreestyleExternal(struct Render *re);
void RE_SetActiveRenderView(struct Render *re, const char *viewname);
const char *RE_GetActiveRenderView(struct Render *re);
-/* error reporting */
+/**
+ * Error reporting.
+ */
void RE_SetReports(struct Render *re, struct ReportList *reports);
-/* main preview render call */
+/**
+ * Main preview render call.
+ */
void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene);
+/**
+ * Only the temp file!
+ */
bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
+/**
+ * Called from the UI and render pipeline, to save multi-layer and multi-view
+ * images, optionally isolating a specific, view, layer or RGBA/Z pass.
+ */
bool RE_WriteRenderResult(struct ReportList *reports,
RenderResult *rr,
const char *filename,
@@ -314,7 +397,11 @@ bool RE_WriteRenderResult(struct ReportList *reports,
struct RenderResult *RE_MultilayerConvert(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
-/* display and event callbacks */
+/* Display and event callbacks. */
+
+/**
+ * Image and movie output has to move to either imbuf or kernel.
+ */
void RE_display_init_cb(struct Render *re,
void *handle,
void (*f)(void *handle, RenderResult *rr));
@@ -337,17 +424,27 @@ void RE_gl_context_destroy(Render *re);
void *RE_gl_context_get(Render *re);
void *RE_gpu_context_get(Render *re);
-/* should move to kernel once... still unsure on how/where */
+/**
+ * \param x: ranges from -1 to 1.
+ *
+ * TODO: Should move to kernel once... still unsure on how/where.
+ */
float RE_filter_value(int type, float x);
int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
+/**
+ * Used in the interface to decide whether to show layers or passes.
+ */
bool RE_layers_have_name(struct RenderResult *result);
bool RE_passes_have_name(struct RenderLayer *rl);
struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl,
const char *name,
const char *viewname);
+/**
+ * Only provided for API compatibility, don't use this in new code!
+ */
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl,
int passtype,
const char *viewname);
@@ -358,8 +455,14 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl,
#define RE_BAKE_AO 2
void RE_GetCameraWindow(struct Render *re, struct Object *camera, float mat[4][4]);
+/**
+ * Must be called after #RE_GetCameraWindow(), does not change `re->winmat`.
+ */
void RE_GetCameraWindowWithOverscan(struct Render *re, float overscan, float r_winmat[4][4]);
void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_modelmat[4][4]);
+
+/* displist.c utility. */
+
struct Scene *RE_GetScene(struct Render *re);
void RE_SetScene(struct Render *re, struct Scene *sce);
diff --git a/source/blender/render/RE_texture.h b/source/blender/render/RE_texture.h
index 39d773777ab..cb18dc92415 100644
--- a/source/blender/render/RE_texture.h
+++ b/source/blender/render/RE_texture.h
@@ -18,13 +18,13 @@
*/
/** \file
* \ingroup render
+ *
+ * This include is for non-render pipeline exports (still old cruft here).
*/
#pragma once
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* this include is for non-render pipeline exports (still old cruft here) */
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include "BLI_compiler_attrs.h"
/* called by meshtools */
struct Depsgraph;
@@ -37,6 +37,12 @@ extern "C" {
#endif
/* texture_procedural.c */
+
+/**
+ * \param pool: Thread pool, may be NULL.
+ *
+ * \return True if the texture has color, otherwise false.
+ */
bool RE_texture_evaluate(const struct MTex *mtex,
const float vec[3],
const int thread,
@@ -47,6 +53,13 @@ bool RE_texture_evaluate(const struct MTex *mtex,
float *r_intensity,
float r_rgba[4]) ATTR_NONNULL(1, 2, 7, 8);
+/**
+ * \param in: Destination
+ * \param tex: Texture.
+ * \param out: Previous color.
+ * \param fact: Texture strength.
+ * \param facg: Button strength value.
+ */
void texture_rgb_blend(
float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype);
@@ -55,9 +68,11 @@ void RE_texture_rng_init(void);
void RE_texture_rng_exit(void);
/* texture_image.c */
+
void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]);
/* texture_pointdensity.c */
+
struct PointDensity;
void RE_point_density_cache(struct Depsgraph *depsgraph, struct PointDensity *pd);
@@ -67,6 +82,10 @@ void RE_point_density_minmax(struct Depsgraph *depsgraph,
float r_min[3],
float r_max[3]);
+/**
+ * \note Requires #RE_point_density_cache() to be called first.
+ * \note Frees point density structure after sampling.
+ */
void RE_point_density_sample(struct Depsgraph *depsgraph,
struct PointDensity *pd,
const int resolution,
@@ -78,8 +97,10 @@ void RE_point_density_fix_linking(void);
/* texture_procedural.c */
-/* Texture evaluation result.
- * NOTE: tr tg tb ta has to remain in this order for array access. */
+/**
+ * Texture evaluation result.
+ * \note `tr tg tb ta` have to remain in this order for array access.
+ */
typedef struct TexResult {
float tin, tr, tg, tb, ta;
int talpha;
@@ -87,6 +108,14 @@ typedef struct TexResult {
} TexResult;
/* This one uses nodes. */
+
+/**
+ * \warning if the texres's values are not declared zero,
+ * check the return value to be sure the color values are set before using the r/g/b values,
+ * otherwise you may use uninitialized values - Campbell
+ *
+ * Use it for stuff which is out of render pipeline.
+ */
int multitex_ext(struct Tex *tex,
float texvec[3],
float dxt[3],
@@ -97,14 +126,26 @@ int multitex_ext(struct Tex *tex,
struct ImagePool *pool,
bool scene_color_manage,
const bool skip_load_image);
-/* Nodes disabled. */
+
+/**
+ * Nodes disabled.
+ * extern-tex doesn't support nodes (#ntreeBeginExec() can't be called when rendering is going on).
+ *
+ * Use it for stuff which is out of render pipeline.
+ */
int multitex_ext_safe(struct Tex *tex,
const float texvec[3],
struct TexResult *texres,
struct ImagePool *pool,
bool scene_color_manage,
const bool skip_load_image);
-/* Only for internal node usage. */
+
+/**
+ * Only for internal node usage.
+ *
+ * this is called from the shader and texture nodes
+ * Use it from render pipeline only!
+ */
int multitex_nodes(struct Tex *tex,
const float texvec[3],
float dxt[3],
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 0f893ce8cd5..6794a9cd1ad 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -814,10 +814,6 @@ static void normal_compress(float out[3],
}
}
-/**
- * This function converts an object space normal map
- * to a tangent space normal map for a given low poly mesh.
- */
void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
const size_t num_pixels,
const int depth,
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index cb92b15f873..e1778897777 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -784,6 +784,7 @@ void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
}
/* Bake */
+
void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
{
re->scene = scene;
diff --git a/source/blender/render/intern/initrender.c b/source/blender/render/intern/initrender.c
index 2370d8e893b..f696b81cffb 100644
--- a/source/blender/render/intern/initrender.c
+++ b/source/blender/render/intern/initrender.c
@@ -121,7 +121,6 @@ static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */
return 0.0f;
}
-/* x ranges from -1 to 1 */
float RE_filter_value(int type, float x)
{
float gaussfac = 1.6f;
@@ -163,6 +162,7 @@ float RE_filter_value(int type, float x)
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
struct Object *RE_GetCamera(Render *re)
{
Object *camera = re->camera_override ? re->camera_override : re->scene->camera;
@@ -174,11 +174,6 @@ void RE_SetOverrideCamera(Render *re, Object *cam_ob)
re->camera_override = cam_ob;
}
-/**
- * Per render, there's one persistent view-plane. Parts will set their own view-planes.
- *
- * \note call this after #RE_InitState().
- */
void RE_SetCamera(Render *re, Object *cam_ob)
{
CameraParams params;
@@ -205,7 +200,6 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, float r_winmat
copy_m4_m4(r_winmat, re->winmat);
}
-/* Must be called after RE_GetCameraWindow(), does not change re->winmat. */
void RE_GetCameraWindowWithOverscan(struct Render *re, float overscan, float r_winmat[4][4])
{
CameraParams params;
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 1bf0dfe079c..44abbbdf074 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -338,7 +338,6 @@ Render *RE_GetRender(const char *name)
return re;
}
-/* if you want to know exactly what has been done */
RenderResult *RE_AcquireResultRead(Render *re)
{
if (re) {
@@ -383,7 +382,6 @@ void RE_ReleaseResult(Render *re)
}
}
-/* displist.c util.... */
Scene *RE_GetScene(Render *re)
{
if (re) {
@@ -399,11 +397,6 @@ void RE_SetScene(Render *re, Scene *sce)
}
}
-/**
- * Same as #RE_AcquireResultImage but creating the necessary views to store the result
- * fill provided result struct with a copy of thew views of what is done so far the
- * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
- */
void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
{
memset(rr, 0, sizeof(RenderResult));
@@ -449,7 +442,6 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
}
}
-/* clear temporary renderresult struct */
void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
{
if (re) {
@@ -460,9 +452,6 @@ void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
}
}
-/* fill provided result struct with what's currently active or done */
-/* this RenderResult struct is the only exception to the rule of a RenderResult */
-/* always having at least one RenderView */
void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
{
memset(rr, 0, sizeof(RenderResult));
@@ -516,7 +505,6 @@ void RE_ReleaseResultImage(Render *re)
}
}
-/* caller is responsible for allocating rect in correct size! */
void RE_ResultGet32(Render *re, unsigned int *rect)
{
RenderResult rres;
@@ -533,8 +521,6 @@ void RE_ResultGet32(Render *re, unsigned int *rect)
RE_ReleaseResultImageViews(re, &rres);
}
-/* caller is responsible for allocating rect in correct size! */
-/* Only for acquired results, for lock */
void RE_AcquiredResultGet32(Render *re,
RenderResult *result,
unsigned int *rect,
@@ -603,8 +589,6 @@ Render *RE_NewSceneRender(const Scene *scene)
return RE_NewRender(render_name);
}
-/* called for new renders and when finishing rendering so
- * we always have valid callbacks on a render */
void RE_InitRenderCB(Render *re)
{
/* set default empty callbacks */
@@ -624,7 +608,6 @@ void RE_InitRenderCB(Render *re)
re->dih = re->dch = re->duh = re->sdh = re->prh = re->tbh = NULL;
}
-/* only call this while you know it will remove the link too */
void RE_FreeRender(Render *re)
{
if (re->engine) {
@@ -655,7 +638,6 @@ void RE_FreeRender(Render *re)
MEM_freeN(re);
}
-/* exit blender */
void RE_FreeAllRender(void)
{
while (RenderGlobal.renderlist.first) {
@@ -668,7 +650,6 @@ void RE_FreeAllRender(void)
#endif
}
-/* on file load, free all re */
void RE_FreeAllRenderResults(void)
{
Render *re;
@@ -769,8 +750,6 @@ void render_copy_renderdata(RenderData *to, RenderData *from)
BKE_curvemapping_copy_data(&to->mblur_shutter_curve, &from->mblur_shutter_curve);
}
-/* what doesn't change during entire render sequence */
-/* disprect is optional, if NULL it assumes full window render */
void RE_InitState(Render *re,
Render *source,
RenderData *rd,
@@ -874,8 +853,6 @@ void RE_InitState(Render *re,
RE_point_density_fix_linking();
}
-/* update some variables that can be animated, and otherwise wouldn't be due to
- * RenderData getting copied once at the start of animation render */
void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_layers)
{
/* filter */
@@ -897,7 +874,6 @@ void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_
BLI_duplicatelist(&re->r.views, &rd->views);
}
-/* image and movie output has to move to either imbuf or kernel */
void RE_display_init_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr))
{
re->display_init = f;
@@ -1834,7 +1810,6 @@ static void render_pipeline_free(Render *re)
}
}
-/* general Blender frame render call */
void RE_RenderFrame(Render *re,
Main *bmain,
Scene *scene,
@@ -1846,7 +1821,7 @@ void RE_RenderFrame(Render *re,
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
/* Ugly global still...
- * is to prevent preview events and signal subsurfs etc to make full resol. */
+ * is to prevent preview events and signal subdivision-surface etc to make full resolution. */
G.is_rendering = true;
scene->r.cfra = frame;
@@ -2280,7 +2255,6 @@ static void re_movie_free_all(Render *re, bMovieHandle *mh, int totvideos)
MEM_SAFE_FREE(re->movie_ctx_arr);
}
-/* saves images to disk */
void RE_RenderAnim(Render *re,
Main *bmain,
Scene *scene,
@@ -2357,8 +2331,8 @@ void RE_RenderAnim(Render *re,
}
}
- /* Ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol
- * is also set by caller renderwin.c */
+ /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc
+ * to make full resolution is also set by caller renderwin.c */
G.is_rendering = true;
re->flag |= R_ANIMATION;
@@ -2583,7 +2557,6 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
/* NOTE: repeated win/disprect calc... solve that nicer, also in compo. */
-/* only the temp file! */
bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
{
Render *re;
@@ -2635,8 +2608,6 @@ void RE_init_threadcount(Render *re)
re->r.threads = BKE_render_num_threads(&re->r);
}
-/* loads in image into a result, size must match
- * x/y offsets are only used on a partial copy when dimensions don't match */
void RE_layer_load_from_file(
RenderLayer *layer, ReportList *reports, const char *filename, int x, int y)
{
@@ -2712,7 +2683,6 @@ void RE_result_load_from_file(RenderResult *result, ReportList *reports, const c
}
}
-/* Used in the interface to decide whether to show layers or passes. */
bool RE_layers_have_name(struct RenderResult *rr)
{
switch (BLI_listbase_count_at_most(&rr->layers, 2)) {
@@ -2754,7 +2724,6 @@ RenderPass *RE_pass_find_by_name(volatile RenderLayer *rl, const char *name, con
return rp;
}
-/* Only provided for API compatibility, don't use this in new code! */
RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
{
#define CHECK_PASS(NAME) \
@@ -2793,7 +2762,6 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c
return NULL;
}
-/* create a renderlayer and renderpass for grease pencil layer */
RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
{
RenderLayer *rl = BLI_findstring(&rr->layers, layername, offsetof(RenderLayer, name));
diff --git a/source/blender/render/intern/pipeline.h b/source/blender/render/intern/pipeline.h
index 062df59bfd3..ba2e382619d 100644
--- a/source/blender/render/intern/pipeline.h
+++ b/source/blender/render/intern/pipeline.h
@@ -34,6 +34,10 @@ extern "C" {
#endif
struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr);
+/**
+ * Update some variables that can be animated, and otherwise wouldn't be due to
+ * #RenderData getting copied once at the start of animation render.
+ */
void render_update_anim_renderdata(struct Render *re,
struct RenderData *rd,
struct ListBase *render_layers);
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index 0681bcd9aa5..a21351539f6 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -126,7 +126,6 @@ void render_result_free(RenderResult *rr)
MEM_freeN(rr);
}
-/** Version that's compatible with full-sample buffers. */
void render_result_free_list(ListBase *lb, RenderResult *rr)
{
RenderResult *rrnext;
@@ -144,7 +143,6 @@ void render_result_free_list(ListBase *lb, RenderResult *rr)
/********************************* multiview *************************************/
-/* create a new views Listbase in rr without duplicating the memory pointers */
void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
{
RenderView *rview;
@@ -166,7 +164,6 @@ void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
}
}
-/* free the views created temporarily */
void render_result_views_shallowdelete(RenderResult *rr)
{
if (rr == NULL) {
@@ -286,10 +283,6 @@ RenderPass *render_layer_add_pass(RenderResult *rr,
return rpass;
}
-/* called by main render as well for parts */
-/* will read info from Render *re to define layers */
-/* called in threads */
-/* re->winx,winy is coordinate space of entire image, partrct the part within */
RenderResult *render_result_new(Render *re,
rcti *partrct,
const char *layername,
@@ -733,10 +726,6 @@ static int order_render_passes(const void *a, const void *b)
return (rpa->view_id < rpb->view_id);
}
-/**
- * From imbuf, if a handle was returned and
- * it's not a single-layer multi-view we convert this to render result.
- */
RenderResult *render_result_new_from_exr(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
{
@@ -837,9 +826,6 @@ static void do_merge_tile(
}
}
-/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
-/* no test happens here if it fits... we also assume layers are in sync */
-/* is used within threads */
void render_result_merge(RenderResult *rr, RenderResult *rrpart)
{
RenderLayer *rl, *rlp;
@@ -869,8 +855,6 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
}
}
-/* Called from the UI and render pipeline, to save multilayer and multiview
- * images, optionally isolating a specific, view, layer or RGBA/Z pass. */
bool RE_WriteRenderResult(ReportList *reports,
RenderResult *rr,
const char *filename,
@@ -1040,7 +1024,6 @@ void render_result_single_layer_begin(Render *re)
re->result = NULL;
}
-/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
void render_result_single_layer_end(Render *re)
{
ViewLayer *view_layer;
@@ -1085,7 +1068,6 @@ void render_result_single_layer_end(Render *re)
re->pushedresult = NULL;
}
-/* called for reading temp files, and for external engines */
int render_result_exr_file_read_path(RenderResult *rr,
RenderLayer *rl_single,
const char *filepath)
@@ -1184,7 +1166,6 @@ void render_result_exr_file_cache_write(Render *re)
RE_WriteRenderResult(NULL, rr, str, NULL, NULL, -1);
}
-/* For cache, makes exact copy of render result */
bool render_result_exr_file_cache_read(Render *re)
{
/* File path to cache. */
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index 34b8143869c..ede0a0d21ea 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -46,6 +46,12 @@ extern "C" {
/* New */
+/**
+ * Called by main render as well for parts will read info from Render *re to define layers.
+ * \note Called in threads.
+ *
+ * `re->winx`, `re->winy` is coordinate space of entire image, `partrct` the part within.
+ */
struct RenderResult *render_result_new(struct Render *re,
struct rcti *partrct,
const char *layername,
@@ -53,6 +59,10 @@ struct RenderResult *render_result_new(struct Render *re,
void render_result_passes_allocated_ensure(struct RenderResult *rr);
+/**
+ * From imbuf, if a handle was returned and
+ * it's not a single-layer multi-view we convert this to render result.
+ */
struct RenderResult *render_result_new_from_exr(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
@@ -61,6 +71,11 @@ void render_result_views_new(struct RenderResult *rr, const struct RenderData *r
/* Merge */
+/**
+ * Used when rendering to a full buffer, or when reading the EXR part-layer-pass file.
+ * no test happens here if it fits... we also assume layers are in sync.
+ * \note Is used within threads.
+ */
void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart);
/* Add Passes */
@@ -70,14 +85,22 @@ void render_result_clone_passes(struct Render *re, struct RenderResult *rr, cons
/* Free */
void render_result_free(struct RenderResult *rr);
+/**
+ * Version that's compatible with full-sample buffers.
+ */
void render_result_free_list(struct ListBase *lb, struct RenderResult *rr);
/* Single Layer Render */
void render_result_single_layer_begin(struct Render *re);
+/**
+ * If #RenderData.scemode is #R_SINGLE_LAYER, at end of rendering, merge the both render results.
+ */
void render_result_single_layer_end(struct Render *re);
-/* render pass wrapper for gpencil */
+/**
+ * Render pass wrapper for grease-pencil.
+ */
struct RenderPass *render_layer_add_pass(struct RenderResult *rr,
struct RenderLayer *rl,
int channels,
@@ -86,6 +109,9 @@ struct RenderPass *render_layer_add_pass(struct RenderResult *rr,
const char *chan_id,
const bool allocate);
+/**
+ * Called for reading temp files, and for external engines.
+ */
int render_result_exr_file_read_path(struct RenderResult *rr,
struct RenderLayer *rl_single,
const char *filepath);
@@ -93,6 +119,9 @@ int render_result_exr_file_read_path(struct RenderResult *rr,
/* EXR cache */
void render_result_exr_file_cache_write(struct Render *re);
+/**
+ * For cache, makes exact copy of render result.
+ */
bool render_result_exr_file_cache_read(struct Render *re);
/* Combined Pixel Rect */
@@ -110,7 +139,13 @@ void render_result_rect_get_pixels(struct RenderResult *rr,
const struct ColorManagedDisplaySettings *display_settings,
const int view_id);
+/**
+ * Create a new views #ListBase in rr without duplicating the memory pointers.
+ */
void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResult *src);
+/**
+ * Free the views created temporarily.
+ */
void render_result_views_shallowdelete(struct RenderResult *rr);
bool render_result_has_views(const struct RenderResult *rr);
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index 06dd570ce2c..8ca1decdea7 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -928,9 +928,6 @@ static void point_density_sample_func(void *__restrict data_v,
}
}
-/* NOTE 1: Requires RE_point_density_cache() to be called first.
- * NOTE 2: Frees point density structure after sampling.
- */
void RE_point_density_sample(Depsgraph *depsgraph,
PointDensity *pd,
const int resolution,
diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c
index 5a94bc09b93..f563cb9f84a 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -1399,9 +1399,6 @@ static int multitex_nodes_intern(Tex *tex,
use_nodes);
}
-/* this is called from the shader and texture nodes
- * Use it from render pipeline only!
- */
int multitex_nodes(Tex *tex,
const float texvec[3],
float dxt[3],
@@ -1429,13 +1426,6 @@ int multitex_nodes(Tex *tex,
true);
}
-/**
- * \warning if the texres's values are not declared zero,
- * check the return value to be sure the color values are set before using the r/g/b values,
- * otherwise you may use uninitialized values - Campbell
- *
- * Use it for stuff which is out of render pipeline.
- */
int multitex_ext(Tex *tex,
float texvec[3],
float dxt[3],
@@ -1463,10 +1453,6 @@ int multitex_ext(Tex *tex,
true);
}
-/* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\
- *
- * Use it for stuff which is out of render pipeline.
- */
int multitex_ext_safe(Tex *tex,
const float texvec[3],
TexResult *texres,
@@ -1492,8 +1478,6 @@ int multitex_ext_safe(Tex *tex,
/* ------------------------------------------------------------------------- */
-/* in = destination, tex = texture, out = previous color */
-/* fact = texture strength, facg = button strength value */
void texture_rgb_blend(
float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype)
{
@@ -1722,11 +1706,6 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
/* ------------------------------------------------------------------------- */
-/**
- * \param pool: Thread pool, may be NULL.
- *
- * \return True if the texture has color, otherwise false.
- */
bool RE_texture_evaluate(const MTex *mtex,
const float vec[3],
const int thread,
diff --git a/source/blender/render/intern/zbuf.c b/source/blender/render/intern/zbuf.c
index 726124871ee..1812a492ac0 100644
--- a/source/blender/render/intern/zbuf.c
+++ b/source/blender/render/intern/zbuf.c
@@ -41,7 +41,6 @@
/* ****************** Spans ******************************* */
-/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */
void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
{
memset(zspan, 0, sizeof(ZSpan));
@@ -170,9 +169,6 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
/* Functions */
/*-----------------------------------------------------------*/
-/* Scan-convert for strand triangles, calls function for each x, y coordinate
- * and gives UV barycentrics and z. */
-
void zspan_scanconvert(ZSpan *zspan,
void *handle,
float *v1,
diff --git a/source/blender/render/intern/zbuf.h b/source/blender/render/intern/zbuf.h
index 41fa15c594f..c5108a9d6a7 100644
--- a/source/blender/render/intern/zbuf.h
+++ b/source/blender/render/intern/zbuf.h
@@ -33,9 +33,16 @@ typedef struct ZSpan {
float *span1, *span2;
} ZSpan;
+/**
+ * Each Z-buffer has coordinates transformed to local rect coordinates, so we can simply clip.
+ */
void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty);
void zbuf_free_span(struct ZSpan *zspan);
+/**
+ * Scan-convert for strand triangles, calls function for each x, y coordinate
+ * and gives UV barycentrics and z.
+ */
void zspan_scanconvert(struct ZSpan *zspan,
void *handle,
float *v1,
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index d2a731d9953..936868725b4 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -67,43 +67,142 @@ typedef struct SeqLoadData {
bool allow_invalid_file; /* Used by RNA API to create placeholder strips. */
} SeqLoadData;
+/**
+ * Initialize common SeqLoadData members
+ *
+ * \param load_data: SeqLoadData to be initialized
+ * \param name: strip name (can be NULL)
+ * \param path: path to file that is used as strip input (can be NULL)
+ * \param start_frame: timeline frame where strip will be created
+ * \param channel: timeline channel where strip will be created
+ */
void SEQ_add_load_data_init(struct SeqLoadData *load_data,
const char *name,
const char *path,
const int start_frame,
const int channel);
+/**
+ * Add image strip.
+ * \note Use #SEQ_add_image_set_directory() and #SEQ_add_image_load_file() to load image sequences
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_image_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add sound strip.
+ * \note Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_sound_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data,
const double audio_offset);
+/**
+ * Add meta strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_meta_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add movie strip.
+ *
+ * \param bmain: Main reference
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_movie_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data,
double *r_start_offset);
+/**
+ * Add scene strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_scene_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add movieclip strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_movieclip_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add mask strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_mask_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Add effect strip.
+ *
+ * \param scene: Scene where strips will be added
+ * \param seqbase: ListBase where strips will be added
+ * \param load_data: SeqLoadData with information necessary to create strip
+ * \return created strip
+ */
struct Sequence *SEQ_add_effect_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
+/**
+ * Set directory used by image strip.
+ *
+ * \param seq: image strip to be changed
+ * \param path: directory path
+ */
void SEQ_add_image_set_directory(struct Sequence *seq, char *path);
+/**
+ * Set directory used by image strip.
+ *
+ * \param seq: image strip to be changed
+ * \param strip_frame: frame index of strip to be changed
+ * \param filename: image filename (only filename, not complete path)
+ */
void SEQ_add_image_load_file(struct Sequence *seq, size_t strip_frame, char *filename);
+/**
+ * Set image strip alpha mode
+ *
+ * \param seq: image strip to be changed
+ */
void SEQ_add_image_init_alpha_mode(struct Sequence *seq);
+/**
+ * \note caller should run `SEQ_time_update_sequence(scene, seq)` after..
+ */
void SEQ_add_reload_new_file(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
diff --git a/source/blender/sequencer/SEQ_clipboard.h b/source/blender/sequencer/SEQ_clipboard.h
index ea7f01e6ae3..72388c5db64 100644
--- a/source/blender/sequencer/SEQ_clipboard.h
+++ b/source/blender/sequencer/SEQ_clipboard.h
@@ -38,6 +38,13 @@ void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase);
void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
void SEQ_clipboard_free(void);
void SEQ_clipboard_active_seq_name_store(struct Scene *scene);
+/**
+ * Check if strip was active when it was copied. User should restrict this check to pasted strips
+ * before ensuring original name, because strip name comparison is used to check.
+ *
+ * \param pasted_seq: Strip that is pasted(duplicated) from clipboard
+ * \return true if strip was active, false otherwise
+ */
bool SEQ_clipboard_pasted_seq_was_active(struct Sequence *pasted_seq);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h
index f3a64c9cd62..fe12ac253b9 100644
--- a/source/blender/sequencer/SEQ_edit.h
+++ b/source/blender/sequencer/SEQ_edit.h
@@ -33,18 +33,40 @@ struct Scene;
struct Sequence;
int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str);
+/**
+ * Move sequence to seqbase.
+ *
+ * \param scene: Scene containing the editing
+ * \param seqbase: seqbase where `seq` is located
+ * \param seq: Sequence to move
+ * \param dst_seqbase: Target seqbase
+ */
bool SEQ_edit_move_strip_to_seqbase(struct Scene *scene,
ListBase *seqbase,
- struct Sequence *src_seq,
+ struct Sequence *seq,
ListBase *dst_seqbase);
+/**
+ * Move sequence to meta sequence.
+ *
+ * \param scene: Scene containing the editing
+ * \param src_seq: Sequence to move
+ * \param dst_seqm: Target Meta sequence
+ * \param error_str: Error message
+ */
bool SEQ_edit_move_strip_to_meta(struct Scene *scene,
struct Sequence *src_seq,
struct Sequence *dst_seqm,
const char **error_str);
bool SEQ_meta_separate(struct Scene *scene, struct Sequence *src_meta, const char **error_str);
+/**
+ * Flag seq and its users (effects) for removal.
+ */
void SEQ_edit_flag_for_removal(struct Scene *scene,
struct ListBase *seqbase,
struct Sequence *seq);
+/**
+ * Remove all flagged sequences, return true if sequence is removed.
+ */
void SEQ_edit_remove_flagged_sequences(struct Scene *scene, struct ListBase *seqbase);
void SEQ_edit_update_muting(struct Editing *ed);
@@ -53,6 +75,17 @@ typedef enum eSeqSplitMethod {
SEQ_SPLIT_HARD,
} eSeqSplitMethod;
+/**
+ * Split Sequence at timeline_frame in two.
+ *
+ * \param bmain: Main in which Sequence is located
+ * \param scene: Scene in which Sequence is located
+ * \param seqbase: ListBase in which Sequence is located
+ * \param seq: Sequence to be split
+ * \param timeline_frame: frame at which seq is split.
+ * \param method: affects type of offset to be applied to resize Sequence
+ * \return The newly created sequence strip. This is always Sequence on right side.
+ */
struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
@@ -60,6 +93,15 @@ struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
const int timeline_frame,
const eSeqSplitMethod method,
const char **r_error);
+/**
+ * Find gap after initial_frame and move strips on right side to close the gap
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param initial_frame: frame on timeline from where gaps are searched for
+ * \param remove_all_gaps: remove all gaps instead of one gap
+ * \return true if gap is removed, otherwise false
+ */
bool SEQ_edit_remove_gaps(struct Scene *scene,
struct ListBase *seqbase,
const int initial_frame,
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index 4de7c09640b..2826e6b75cb 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -63,52 +63,184 @@ typedef struct SeqIterator {
bool iterator_initialized;
} SeqIterator;
+/**
+ * Utility function for SEQ_ITERATOR_FOREACH macro.
+ * Ensure, that iterator is initialized. During initialization return pointer to collection element
+ * and step gset iterator. When this function is called after iterator has been initialized, it
+ * will do nothing and return true.
+ *
+ * \param collection: collection to iterate
+ * \param iterator: iterator to be initialized
+ * \param r_seq: pointer to Sequence pointer
+ *
+ * \return false when iterator can not be initialized, true otherwise
+ */
bool SEQ_iterator_ensure(SeqCollection *collection,
SeqIterator *iterator,
struct Sequence **r_seq);
+/**
+ * Utility function for SEQ_ITERATOR_FOREACH macro.
+ * Yield collection element
+ *
+ * \param iterator: iterator to be initialized
+ *
+ * \return collection element or NULL when iteration has ended
+ */
struct Sequence *SEQ_iterator_yield(SeqIterator *iterator);
-/* Callback format for the for_each function below. */
+/**
+ * Callback format for the for_each function below.
+ */
typedef bool (*SeqForEachFunc)(struct Sequence *seq, void *user_data);
+/**
+ * Utility function to recursively iterate through all sequence strips in a `seqbase` list.
+ * Uses callback to do operations on each sequence element.
+ * The callback can stop the iteration if needed.
+ *
+ * \param seqbase: #ListBase of sequences to be iterated over.
+ * \param callback: query function callback, returns false if iteration should stop.
+ * \param user_data: pointer to user data that can be used in the callback function.
+ */
void SEQ_for_each_callback(struct ListBase *seqbase, SeqForEachFunc callback, void *user_data);
+/**
+ * Create new empty strip collection.
+ *
+ * \return empty strip collection.
+ */
SeqCollection *SEQ_collection_create(const char *name);
+/**
+ * Duplicate collection
+ *
+ * \param collection: collection to be duplicated
+ * \return duplicate of collection
+ */
SeqCollection *SEQ_collection_duplicate(SeqCollection *collection);
+/**
+ * Return number of items in collection.
+ */
uint SEQ_collection_len(const SeqCollection *collection);
+/**
+ * Check if seq is in collection.
+ */
bool SEQ_collection_has_strip(const struct Sequence *seq, const SeqCollection *collection);
-bool SEQ_collection_append_strip(struct Sequence *seq, SeqCollection *data);
-bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *data);
+/**
+ * Add strip to collection.
+ *
+ * \param seq: strip to be added
+ * \param collection: collection to which strip will be added
+ * \return false if strip is already in set, otherwise true
+ */
+bool SEQ_collection_append_strip(struct Sequence *seq, SeqCollection *collection);
+/**
+ * Remove strip from collection.
+ *
+ * \param seq: strip to be removed
+ * \param collection: collection from which strip will be removed
+ * \return true if strip exists in set and it was removed from set, otherwise false
+ */
+bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *collection);
+/**
+ * Free strip collection.
+ *
+ * \param collection: collection to be freed
+ */
void SEQ_collection_free(SeqCollection *collection);
+/**
+ * Move strips from collection_src to collection_dst. Source collection will be freed.
+ *
+ * \param collection_dst: destination collection
+ * \param collection_src: source collection
+ */
void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collection_src);
+/**
+ * Remove strips from collection that are also in `exclude_elements`. Source collection will be
+ * freed.
+ *
+ * \param collection: collection from which strips are removed
+ * \param exclude_elements: collection of strips to be removed
+ */
void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_elements);
+/**
+ * Expand collection by running SEQ_query() for each strip, which will be used as reference.
+ * Results of these queries will be merged into provided collection.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \param collection: SeqCollection to be expanded
+ * \param seq_query_func: query function callback
+ */
void SEQ_collection_expand(struct ListBase *seqbase,
SeqCollection *collection,
- void query_func(struct Sequence *seq_reference,
- struct ListBase *seqbase,
- SeqCollection *collection));
+ void seq_query_func(struct Sequence *seq_reference,
+ struct ListBase *seqbase,
+ SeqCollection *collection));
+/**
+ * Query strips from seqbase. seq_reference is used by query function as filter condition.
+ *
+ * \param seq_reference: reference strip for query function
+ * \param seqbase: ListBase in which strips are queried
+ * \param seq_query_func: query function callback
+ * \return strip collection
+ */
SeqCollection *SEQ_query_by_reference(struct Sequence *seq_reference,
struct ListBase *seqbase,
void seq_query_func(struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection));
+/**
+ * Query all selected strips in seqbase.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_selected_strips(struct ListBase *seqbase);
+/**
+ * Query all unselected strips in seqbase.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_unselected_strips(struct ListBase *seqbase);
+/**
+ * Query all strips in seqbase. This does not include strips nested in meta strips.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_all_strips(ListBase *seqbase);
+/**
+ * Query all strips in seqbase and nested meta strips.
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \return strip collection
+ */
SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase);
+/**
+ * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \param timeline_frame: viewed frame
+ * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied
+ * \return strip collection
+ */
SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
const int timeline_frame,
const int displayed_channel);
+/**
+ * Query all effect strips that are directly or indirectly connected to seq_reference.
+ * This includes all effects of seq_reference, strips used by another inputs and their effects, so
+ * that whole chain is fully independent of other strips.
+ *
+ * \param seq_reference: reference strip
+ * \param seqbase: ListBase in which strips are queried
+ * \param collection: collection to be filled
+ */
void SEQ_query_strip_effect_chain(struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection);
void SEQ_filter_selected_strips(SeqCollection *collection);
-/* Utilities to access these as tags. */
-int SEQ_query_rendered_strips_to_tag(ListBase *seqbase,
- const int timeline_frame,
- const int displayed_channel);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/SEQ_prefetch.h b/source/blender/sequencer/SEQ_prefetch.h
index 93fc8883e99..980f7611094 100644
--- a/source/blender/sequencer/SEQ_prefetch.h
+++ b/source/blender/sequencer/SEQ_prefetch.h
@@ -31,6 +31,10 @@ struct Main;
struct Scene;
void SEQ_prefetch_stop_all(void);
+/**
+ * Use also to update scene and context changes
+ * This function should almost always be called by cache invalidation, not directly.
+ */
void SEQ_prefetch_stop(struct Scene *scene);
bool SEQ_prefetch_need_redraw(struct Main *bmain, struct Scene *scene);
diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h
index 3b9d430a3c9..9571e826759 100644
--- a/source/blender/sequencer/SEQ_relations.h
+++ b/source/blender/sequencer/SEQ_relations.h
@@ -34,8 +34,14 @@ struct ReportList;
struct Scene;
struct Sequence;
+/**
+ * Function to free imbuf and anim data on changes.
+ */
void SEQ_relations_sequence_free_anim(struct Sequence *seq);
bool SEQ_relations_check_scene_recursion(struct Scene *scene, struct ReportList *reports);
+/**
+ * Check if "seq_main" (indirectly) uses strip "seq".
+ */
bool SEQ_relations_render_loop_check(struct Sequence *seq_main, struct Sequence *seq);
void SEQ_relations_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render);
void SEQ_relations_invalidate_cache_raw(struct Scene *scene, struct Sequence *seq);
@@ -48,11 +54,18 @@ void SEQ_relations_invalidate_cache_in_range(struct Scene *scene,
struct Sequence *seq,
struct Sequence *range_mask,
int invalidate_types);
+/**
+ * Release FFmpeg handles of strips that are not currently displayed to minimize memory usage.
+ */
void SEQ_relations_free_all_anim_ibufs(struct Scene *scene, int timeline_frame);
-/* A debug and development function which checks whether sequences have unique UUIDs.
- * Errors will be reported to the console. */
+/**
+ * A debug and development function which checks whether sequences have unique UUIDs.
+ * Errors will be reported to the console.
+ */
void SEQ_relations_check_uuids_unique_and_report(const struct Scene *scene);
-/* Generate new UUID for the given sequence. */
+/**
+ * Generate new UUID for the given sequence.
+ */
void SEQ_relations_session_uuid_generate(struct Sequence *sequence);
void SEQ_cache_cleanup(struct Scene *scene);
@@ -61,6 +74,9 @@ void SEQ_cache_iterate(
void *userdata,
bool callback_init(void *userdata, size_t item_count),
bool callback_iter(void *userdata, struct Sequence *seq, int timeline_frame, int cache_type));
+/**
+ * Return immediate parent meta of sequence.
+ */
struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */,
struct Sequence *meta /* = NULL */,
struct Sequence *seq);
diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h
index e99dc6d344f..7f10160bf6a 100644
--- a/source/blender/sequencer/SEQ_render.h
+++ b/source/blender/sequencer/SEQ_render.h
@@ -63,12 +63,20 @@ typedef struct SeqRenderData {
// bool gpu_full_samples;
} SeqRenderData;
+/**
+ * \return The image buffer or NULL.
+ *
+ * \note The returned #ImBuf has its reference increased, free after usage!
+ */
struct ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context,
float timeline_frame,
int chanshown);
struct ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context,
float timeline_frame,
struct Sequence *seq);
+/**
+ * Render the series of thumbnails and store in cache.
+ */
void SEQ_render_thumbnails(const struct SeqRenderData *context,
struct Sequence *seq,
struct Sequence *seq_orig,
@@ -76,12 +84,22 @@ void SEQ_render_thumbnails(const struct SeqRenderData *context,
float frame_step,
rctf *view_area,
const short *stop);
+/**
+ * Get cached thumbnails.
+ */
struct ImBuf *SEQ_get_thumbnail(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
rcti *crop,
bool clipped);
+/**
+ * Get frame step for equally spaced thumbnails. These thumbnails should always be present in
+ * memory, so they can be used when zooming.
+ */
int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const struct Sequence *seq);
+/**
+ * Render set of evenly spaced thumbnails that are drawn when zooming..
+ */
void SEQ_render_thumbnails_base_set(const struct SeqRenderData *context,
struct Sequence *seq,
struct Sequence *seq_orig,
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index 1b8982da0d2..a3ee716c3f6 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -69,12 +69,43 @@ struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSetting
struct Editing *SEQ_editing_get(const struct Scene *scene);
struct Editing *SEQ_editing_ensure(struct Scene *scene);
void SEQ_editing_free(struct Scene *scene, const bool do_id_user);
+/**
+ * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
+ *
+ * \param ed: sequence editor data
+ * \return pointer to active seqbase. returns NULL if ed is NULL
+ */
struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed);
+/**
+ * Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
+ *
+ * \param ed: sequence editor data
+ * \param seqbase: ListBase with strips
+ */
void SEQ_seqbase_active_set(struct Editing *ed, struct ListBase *seqbase);
struct Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type);
void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata);
+/**
+ * Create and initialize #MetaStack, append it to `ed->metastack` ListBase
+ *
+ * \param ed: sequence editor data
+ * \param seq_meta: meta strip
+ * \return pointer to created meta stack
+ */
struct MetaStack *SEQ_meta_stack_alloc(struct Editing *ed, struct Sequence *seq_meta);
+/**
+ * Get #MetaStack that corresponds to current level that is being viewed
+ *
+ * \param ed: sequence editor data
+ * \return pointer to meta stack
+ */
struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed);
+/**
+ * Free #MetaStack and remove it from `ed->metastack` ListBase.
+ *
+ * \param ed: sequence editor data
+ * \param ms: meta stack
+ */
void SEQ_meta_stack_free(struct Editing *ed, struct MetaStack *ms);
void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs);
void SEQ_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst);
@@ -91,7 +122,9 @@ void SEQ_sequence_base_dupli_recursive(const struct Scene *scene_src,
const int flag);
bool SEQ_valid_strip_channel(struct Sequence *seq);
-/* Read and Write functions for .blend file data */
+/**
+ * Read and Write functions for `.blend` file data.
+ */
void SEQ_blend_write(struct BlendWriter *writer, struct ListBase *seqbase);
void SEQ_blend_read(struct BlendDataReader *reader, struct ListBase *seqbase);
@@ -101,7 +134,13 @@ void SEQ_blend_read_lib(struct BlendLibReader *reader,
void SEQ_blend_read_expand(struct BlendExpander *expander, struct ListBase *seqbase);
-/* Depsgraph update function */
+/* Depsgraph update function. */
+
+/**
+ * Evaluate parts of sequences which needs to be done as a part of a dependency graph evaluation.
+ * This does NOT include actual rendering of the strips, but rather makes them up-to-date for
+ * animation playback and makes them ready for the sequencer's rendering pipeline to render them.
+ */
void SEQ_eval_sequences(struct Depsgraph *depsgraph,
struct Scene *scene,
struct ListBase *seqbase);
@@ -112,8 +151,29 @@ typedef enum eSequenceLookupTag {
SEQ_LOOKUP_TAG_INVALID = (1 << 0),
} eSequenceLookupTag;
+/**
+ * Find a sequence with a given name.
+ * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
+ * rebuilt.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param key: Sequence name without SQ prefix (seq->name + 2)
+ *
+ * \return pointer to Sequence
+ */
struct Sequence *SEQ_sequence_lookup_by_name(const struct Scene *scene, const char *key);
+/**
+ * Free lookup hash data.
+ *
+ * \param scene: scene that owns lookup hash
+ */
void SEQ_sequence_lookup_free(const struct Scene *scene);
+/**
+ * Find a sequence with a given name.
+ *
+ * \param scene: scene that owns lookup hash
+ * \param tag: tag to set
+ */
void SEQ_sequence_lookup_tag(const struct Scene *scene, eSequenceLookupTag tag);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index a0abaf8813a..e563e94da24 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -32,8 +32,27 @@ struct Scene;
struct Sequence;
struct rctf;
+/**
+ * Initialize given rectangle with the Scene's timeline boundaries.
+ *
+ * \param scene: the Scene instance whose timeline boundaries are extracted from
+ * \param rect: output parameter to be filled with timeline boundaries
+ */
void SEQ_timeline_init_boundbox(const struct Scene *scene, struct rctf *rect);
+/**
+ * Stretch the given rectangle to include the given strips boundaries
+ *
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: output parameter to be filled with strips' boundaries
+ */
void SEQ_timeline_expand_boundbox(const struct ListBase *seqbase, struct rctf *rect);
+/**
+ * Define boundary rectangle of sequencer timeline and fill in rect data
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param rect: data structure describing rectangle, that will be filled in by this function
+ */
void SEQ_timeline_boundbox(const struct Scene *scene,
const struct ListBase *seqbase,
struct rctf *rect);
@@ -46,6 +65,15 @@ int SEQ_time_find_next_prev_edit(struct Scene *scene,
const bool do_unselected);
void SEQ_time_update_sequence(struct Scene *scene, struct ListBase *seqbase, struct Sequence *seq);
void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq);
+/**
+ * Test if strip intersects with timeline frame.
+ * \note This checks if strip would be rendered at this frame. For rendering it is assumed, that
+ * timeline frame has width of 1 frame and therefore ends at timeline_frame + 1
+ *
+ * \param seq: Sequence to be checked
+ * \param timeline_frame: absolute frame position
+ * \return true if strip intersects with timeline frame.
+ */
bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, const int timeline_frame);
void SEQ_time_update_meta_strip_range(struct Scene *scene, struct Sequence *seq_meta);
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index 18437680731..fe0c223bcb1 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -36,13 +36,24 @@ int SEQ_transform_get_left_handle_frame(struct Sequence *seq);
int SEQ_transform_get_right_handle_frame(struct Sequence *seq);
void SEQ_transform_set_left_handle_frame(struct Sequence *seq, int val);
void SEQ_transform_set_right_handle_frame(struct Sequence *seq, int val);
+/**
+ * Use to impose limits when dragging/extending - so impossible situations don't happen.
+ * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
+ */
void SEQ_transform_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag);
bool SEQ_transform_sequence_can_be_translated(struct Sequence *seq);
+/**
+ * Used so we can do a quick check for single image seq
+ * since they work a bit differently to normal image seq's (during transform).
+ */
bool SEQ_transform_single_image_check(struct Sequence *seq);
void SEQ_transform_fix_single_image_seq_offsets(struct Sequence *seq);
bool SEQ_transform_test_overlap(struct ListBase *seqbasep, struct Sequence *test);
bool SEQ_transform_test_overlap_seq_seq(struct Sequence *seq1, struct Sequence *seq2);
void SEQ_transform_translate_sequence(struct Scene *scene, struct Sequence *seq, int delta);
+/**
+ * \return 0 if there weren't enough space.
+ */
bool SEQ_transform_seqbase_shuffle_ex(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene,
@@ -55,21 +66,57 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
struct Scene *evil_scene,
struct ListBase *markers,
const bool use_sync_markers);
+/**
+ * Check if the selected seq's reference unselected seq's.
+ */
bool SEQ_transform_seqbase_isolated_sel_check(struct ListBase *seqbase);
+/**
+ * Move strips and markers (if not locked) that start after timeline_frame by delta frames
+ *
+ * \param scene: Scene in which strips are located
+ * \param seqbase: ListBase in which strips are located
+ * \param delta: offset in frames to be applied
+ * \param timeline_frame: frame on timeline from where strips are moved
+ */
void SEQ_transform_offset_after_frame(struct Scene *scene,
struct ListBase *seqbase,
const int delta,
const int timeline_frame);
/* Image transformation. */
+
void SEQ_image_transform_mirror_factor_get(const struct Sequence *seq, float r_mirror[2]);
+/**
+ * Get strip transform origin offset from image center
+ * NOTE: This function does not apply axis mirror.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate image transform origin
+ * \param r_origin: return value
+ */
void SEQ_image_transform_origin_offset_pixelspace_get(const struct Scene *scene,
const struct Sequence *seq,
float r_origin[2]);
+/**
+ * Get 4 corner points of strip image, optionally without rotation component applied.
+ * Corner vectors are in viewport space.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate transformed image quad
+ * \param apply_rotation: Apply sequence rotation transform to the quad
+ * \param r_quad: array of 4 2D vectors
+ */
void SEQ_image_transform_quad_get(const struct Scene *scene,
const struct Sequence *seq,
bool apply_rotation,
float r_quad[4][2]);
+/**
+ * Get 4 corner points of strip image. Corner vectors are in viewport space.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate transformed image quad
+ * \param r_quad: array of 4 2D vectors
+ */
void SEQ_image_transform_final_quad_get(const struct Scene *scene,
const struct Sequence *seq,
float r_quad[4][2]);
diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
index d30a1b2d7ae..58d7a92f370 100644
--- a/source/blender/sequencer/SEQ_utils.h
+++ b/source/blender/sequencer/SEQ_utils.h
@@ -36,6 +36,13 @@ struct Sequence;
struct StripElem;
struct SeqRenderData;
+/**
+ * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by
+ * channel position as well.
+ * This is important for SEQ_time_update_sequence to work properly
+ *
+ * \param seqbase: ListBase with strips
+ */
void SEQ_sort(struct ListBase *seqbase);
void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
struct ListBase *seqbasep,
@@ -43,7 +50,14 @@ void SEQ_sequence_base_unique_name_recursive(struct Scene *scene,
const char *SEQ_sequence_give_name(struct Sequence *seq);
struct ListBase *SEQ_get_seqbase_from_sequence(struct Sequence *seq, int *r_offset);
const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int frame);
+/**
+ * In cases where we don't know the sequence's listbase.
+ */
struct ListBase *SEQ_get_seqbase_by_seq(struct ListBase *seqbase, struct Sequence *seq);
+/**
+ * Only use as last resort when the StripElem is available but no the Sequence.
+ * (needed for RNA)
+ */
struct Sequence *SEQ_sequence_from_strip_elem(struct ListBase *seqbase, struct StripElem *se);
struct Sequence *SEQ_get_sequence_by_name(struct ListBase *seqbase,
const char *name,
@@ -57,6 +71,13 @@ void SEQ_set_scale_to_fit(const struct Sequence *seq,
const int preview_width,
const int preview_height,
const eSeqImageFitMethod fit_method);
+/**
+ * Ensure, that provided Sequence has unique name. If animation data exists for this Sequence, it
+ * will be duplicated and mapped onto new name
+ *
+ * \param seq: Sequence which name will be ensured to be unique
+ * \param scene: Scene in which name must be unique
+ */
void SEQ_ensure_unique_name(struct Sequence *seq, struct Scene *scene);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c
index 05406c50303..73e0f616da4 100644
--- a/source/blender/sequencer/intern/clipboard.c
+++ b/source/blender/sequencer/intern/clipboard.c
@@ -194,13 +194,6 @@ void SEQ_clipboard_active_seq_name_store(Scene *scene)
}
}
-/**
- * Check if strip was active when it was copied. User should restrict this check to pasted strips
- * before ensuring original name, because strip name comparison is used to check.
- *
- * \param pasted_seq: Strip that is pasted(duplicated) from clipboard
- * \return true if strip was active, false otherwise
- */
bool SEQ_clipboard_pasted_seq_was_active(Sequence *pasted_seq)
{
return STREQ(pasted_seq->name, seq_clipboard_active_seq_name);
diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c
index 06d27717bdd..2db6a3cc8ee 100644
--- a/source/blender/sequencer/intern/disk_cache.c
+++ b/source/blender/sequencer/intern/disk_cache.c
@@ -148,7 +148,7 @@ bool seq_disk_cache_is_enabled(Main *bmain)
{
return (U.sequencer_disk_cache_dir[0] != '\0' && U.sequencer_disk_cache_size_limit != 0 &&
(U.sequencer_disk_cache_flag & SEQ_CACHE_DISK_CACHE_ENABLE) != 0 &&
- bmain->name[0] != '\0');
+ bmain->filepath[0] != '\0');
}
static DiskCacheFile *seq_disk_cache_add_file_to_list(SeqDiskCache *disk_cache, const char *path)
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 6a6889c3679..05ce35deeec 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -3135,8 +3135,6 @@ static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *s
return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
}
-/* Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated.
- * This is, because `target_frame` value is integrated over time. */
void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
{
if ((seq->seq1 == NULL) || (seq->len < 1)) {
@@ -3175,7 +3173,6 @@ static void seq_effect_speed_frame_map_ensure(Scene *scene, Sequence *seq)
seq_effect_speed_rebuild_map(scene, seq);
}
-/* Override timeline_frame when rendering speed effect input. */
float seq_speed_effect_target_frame_get(Scene *scene,
Sequence *seq_speed,
float timeline_frame,
diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h
index 25ba4d8956e..c63f8f7a404 100644
--- a/source/blender/sequencer/intern/effects.h
+++ b/source/blender/sequencer/intern/effects.h
@@ -39,7 +39,14 @@ struct Sequence;
*/
struct SeqEffectHandle seq_effect_get_sequence_blend(struct Sequence *seq);
+/**
+ * Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated.
+ * This is, because `target_frame` value is integrated over time.
+ */
void seq_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq);
+/**
+ * Override timeline_frame when rendering speed effect input.
+ */
float seq_speed_effect_target_frame_get(struct Scene *scene,
struct Sequence *seq,
float timeline_frame,
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index c742fca0562..51e4613f088 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -453,9 +453,6 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
return finalkey;
}
-/* Find only "base" keys.
- * Sources(other types) for a frame must be freed all at once.
- */
bool seq_cache_recycle_item(Scene *scene)
{
SeqCache *cache = seq_cache_get_from_scene(scene);
diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h
index e7827c15305..65732b5d83d 100644
--- a/source/blender/sequencer/intern/image_cache.h
+++ b/source/blender/sequencer/intern/image_cache.h
@@ -70,6 +70,10 @@ bool seq_cache_put_if_possible(const struct SeqRenderData *context,
float timeline_frame,
int type,
struct ImBuf *nval);
+/**
+ * Find only "base" keys.
+ * Sources(other types) for a frame must be freed all at once.
+ */
bool seq_cache_recycle_item(struct Scene *scene);
void seq_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame);
void seq_cache_destruct(struct Scene *scene);
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
index 68f632ddb28..6cd53f08b3a 100644
--- a/source/blender/sequencer/intern/iterator.c
+++ b/source/blender/sequencer/intern/iterator.c
@@ -44,18 +44,6 @@
/** \Iterator API
* \{ */
-/**
- * Utility function for SEQ_ITERATOR_FOREACH macro.
- * Ensure, that iterator is initialized. During initialization return pointer to collection element
- * and step gset iterator. When this function is called after iterator has been initialized, it
- * will do nothing and return true.
- *
- * \param collection: collection to iterate
- * \param iterator: iterator to be initialized
- * \param r_seq: pointer to Sequence pointer
- *
- * \return false when iterator can not be initialized, true otherwise
- */
bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Sequence **r_seq)
{
if (iterator->iterator_initialized) {
@@ -76,14 +64,6 @@ bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Seque
return true;
}
-/**
- * Utility function for SEQ_ITERATOR_FOREACH macro.
- * Yield collection element
- *
- * \param iterator: iterator to be initialized
- *
- * \return collection element or NULL when iteration has ended
- */
Sequence *SEQ_iterator_yield(SeqIterator *iterator)
{
Sequence *seq = BLI_gsetIterator_done(&iterator->gsi) ? NULL :
@@ -108,36 +88,17 @@ static bool seq_for_each_recursive(ListBase *seqbase, SeqForEachFunc callback, v
return true;
}
-/**
- * Utility function to recursively iterate through all sequence strips in a `seqbase` list.
- * Uses callback to do operations on each sequence element.
- * The callback can stop the iteration if needed.
- *
- * \param seqbase: #ListBase of sequences to be iterated over.
- * \param callback: query function callback, returns false if iteration should stop.
- * \param user_data: pointer to user data that can be used in the callback function.
- */
void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data)
{
seq_for_each_recursive(seqbase, callback, user_data);
}
-/**
- * Free strip collection.
- *
- * \param collection: collection to be freed
- */
void SEQ_collection_free(SeqCollection *collection)
{
BLI_gset_free(collection->set, NULL);
MEM_freeN(collection);
}
-/**
- * Create new empty strip collection.
- *
- * \return empty strip collection.
- */
SeqCollection *SEQ_collection_create(const char *name)
{
SeqCollection *collection = MEM_callocN(sizeof(SeqCollection), name);
@@ -146,30 +107,16 @@ SeqCollection *SEQ_collection_create(const char *name)
return collection;
}
-/**
- * Return number of items in collection.
- */
uint SEQ_collection_len(const SeqCollection *collection)
{
return BLI_gset_len(collection->set);
}
-/**
- * Check if seq is in collection.
- */
bool SEQ_collection_has_strip(const Sequence *seq, const SeqCollection *collection)
{
return BLI_gset_haskey(collection->set, seq);
}
-/**
- * Query strips from seqbase. seq_reference is used by query function as filter condition.
- *
- * \param seq_reference: reference strip for query function
- * \param seqbase: ListBase in which strips are queried
- * \param seq_query_func: query function callback
- * \return strip collection
- */
SeqCollection *SEQ_query_by_reference(Sequence *seq_reference,
ListBase *seqbase,
void seq_query_func(Sequence *seq_reference,
@@ -180,13 +127,6 @@ SeqCollection *SEQ_query_by_reference(Sequence *seq_reference,
seq_query_func(seq_reference, seqbase, collection);
return collection;
}
-/**
- * Add strip to collection.
- *
- * \param seq: strip to be added
- * \param collection: collection to which strip will be added
- * \return false if strip is already in set, otherwise true
- */
bool SEQ_collection_append_strip(Sequence *seq, SeqCollection *collection)
{
void **key;
@@ -198,24 +138,11 @@ bool SEQ_collection_append_strip(Sequence *seq, SeqCollection *collection)
return true;
}
-/**
- * Remove strip from collection.
- *
- * \param seq: strip to be removed
- * \param collection: collection from which strip will be removed
- * \return true if strip exists in set and it was removed from set, otherwise false
- */
bool SEQ_collection_remove_strip(Sequence *seq, SeqCollection *collection)
{
return BLI_gset_remove(collection->set, seq, NULL);
}
-/**
- * Move strips from collection_src to collection_dst. Source collection will be freed.
- *
- * \param collection_dst: destination collection
- * \param collection_src: source collection
- */
void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collection_src)
{
Sequence *seq;
@@ -225,13 +152,6 @@ void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collecti
SEQ_collection_free(collection_src);
}
-/**
- * Remove strips from collection that are also in `exclude_elements`. Source collection will be
- * freed.
- *
- * \param collection: collection from which strips are removed
- * \param exclude_elements: collection of strips to be removed
- */
void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_elements)
{
Sequence *seq;
@@ -241,14 +161,6 @@ void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_el
SEQ_collection_free(exclude_elements);
}
-/**
- * Expand collection by running SEQ_query() for each strip, which will be used as reference.
- * Results of these queries will be merged into provided collection.
- *
- * \param seqbase: ListBase in which strips are queried
- * \param collection: SeqCollection to be expanded
- * \param seq_query_func: query function callback
- */
void SEQ_collection_expand(ListBase *seqbase,
SeqCollection *collection,
void seq_query_func(Sequence *seq_reference,
@@ -267,12 +179,6 @@ void SEQ_collection_expand(ListBase *seqbase,
SEQ_collection_merge(collection, query_matches);
}
-/**
- * Duplicate collection
- *
- * \param collection: collection to be duplicated
- * \return duplicate of collection
- */
SeqCollection *SEQ_collection_duplicate(SeqCollection *collection)
{
SeqCollection *duplicate = SEQ_collection_create(__func__);
@@ -295,12 +201,6 @@ static void query_all_strips_recursive(ListBase *seqbase, SeqCollection *collect
}
}
-/**
- * Query all strips in seqbase and nested meta strips.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -313,12 +213,6 @@ SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase)
return collection;
}
-/**
- * Query all strips in seqbase. This does not include strips nested in meta strips.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_all_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -328,12 +222,6 @@ SeqCollection *SEQ_query_all_strips(ListBase *seqbase)
return collection;
}
-/**
- * Query all selected strips in seqbase.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_selected_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -434,14 +322,6 @@ static void collection_filter_rendered_strips(SeqCollection *collection)
}
}
-/**
- * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed
- *
- * \param seqbase: ListBase in which strips are queried
- * \param timeline_frame: viewed frame
- * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied
- * \return strip collection
- */
SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
const int timeline_frame,
const int displayed_channel)
@@ -454,12 +334,6 @@ SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
return collection;
}
-/**
- * Query all unselected strips in seqbase.
- *
- * \param seqbase: ListBase in which strips are queried
- * \return strip collection
- */
SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase)
{
SeqCollection *collection = SEQ_collection_create(__func__);
@@ -472,15 +346,6 @@ SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase)
return collection;
}
-/**
- * Query all effect strips that are directly or indirectly connected to seq_reference.
- * This includes all effects of seq_reference, strips used by another inputs and their effects, so
- * that whole chain is fully independent of other strips.
- *
- * \param seq_reference: reference strip
- * \param seqbase: ListBase in which strips are queried
- * \param collection: collection to be filled
- */
void SEQ_query_strip_effect_chain(Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
@@ -520,29 +385,3 @@ void SEQ_filter_selected_strips(SeqCollection *collection)
}
}
}
-
-static void seq_collection_to_tag(ListBase *seqbase, SeqCollection *collection)
-{
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- seq->tmp_tag = false;
- }
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- seq->tmp_tag = true;
- }
-}
-
-/* Utilities to access these as tags. */
-int SEQ_query_rendered_strips_to_tag(ListBase *seqbase,
- const int timeline_frame,
- const int displayed_channel)
-{
- SeqCollection *collection = SEQ_query_rendered_strips(
- seqbase, timeline_frame, displayed_channel);
-
- seq_collection_to_tag(seqbase, collection);
-
- const int len = SEQ_collection_len(collection);
- SEQ_collection_free(collection);
- return len;
-}
diff --git a/source/blender/sequencer/intern/modifier.c b/source/blender/sequencer/intern/modifier.c
index 1a63f4c4655..00ae88232fd 100644
--- a/source/blender/sequencer/intern/modifier.c
+++ b/source/blender/sequencer/intern/modifier.c
@@ -1161,6 +1161,7 @@ static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *
// SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
+ ibuf->planes = R_IMF_PLANES_RGBA;
}
static SequenceModifierTypeInfo seqModifier_Mask = {
diff --git a/source/blender/sequencer/intern/multiview.c b/source/blender/sequencer/intern/multiview.c
index e120234ed8b..68d2a33fd5c 100644
--- a/source/blender/sequencer/intern/multiview.c
+++ b/source/blender/sequencer/intern/multiview.c
@@ -40,7 +40,6 @@ void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id)
IMB_suffix_anim(anim, suffix);
}
-/* the number of files will vary according to the stereo format */
int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
{
if (!is_multiview) {
diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h
index bbc66c6f84c..3d528c22fff 100644
--- a/source/blender/sequencer/intern/multiview.h
+++ b/source/blender/sequencer/intern/multiview.h
@@ -43,6 +43,9 @@ void seq_multiview_name(struct Scene *scene,
const char *ext,
char *r_path,
size_t r_size);
+/**
+ * The number of files will vary according to the stereo format.
+ */
int seq_num_files(struct Scene *scene, char views_format, const bool is_multiview);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c
index 3e0b4738db1..0c45eb09492 100644
--- a/source/blender/sequencer/intern/prefetch.c
+++ b/source/blender/sequencer/intern/prefetch.c
@@ -162,14 +162,12 @@ static Sequence *sequencer_prefetch_get_original_sequence(Sequence *seq, ListBas
return NULL;
}
-/* for cache context swapping */
Sequence *seq_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
{
Editing *ed = scene->ed;
return sequencer_prefetch_get_original_sequence(seq, &ed->seqbase);
}
-/* for cache context swapping */
SeqRenderData *seq_prefetch_get_original_context(const SeqRenderData *context)
{
PrefetchJob *pfjob = seq_prefetch_job_get(context->scene);
@@ -268,9 +266,6 @@ void SEQ_prefetch_stop_all(void)
}
}
-/* Use also to update scene and context changes
- * This function should almost always be called by cache invalidation, not directly.
- */
void SEQ_prefetch_stop(Scene *scene)
{
PrefetchJob *pfjob;
@@ -561,7 +556,6 @@ static PrefetchJob *seq_prefetch_start_ex(const SeqRenderData *context, float cf
return pfjob;
}
-/* Start or resume prefetching. */
void seq_prefetch_start(const SeqRenderData *context, float timeline_frame)
{
Scene *scene = context->scene;
diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h
index 8cfc6bf90bd..8cc5f6d35d1 100644
--- a/source/blender/sequencer/intern/prefetch.h
+++ b/source/blender/sequencer/intern/prefetch.h
@@ -35,11 +35,20 @@ struct Sequence;
}
#endif
+/**
+ * Start or resume prefetching.
+ */
void seq_prefetch_start(const struct SeqRenderData *context, float timeline_frame);
void seq_prefetch_free(struct Scene *scene);
bool seq_prefetch_job_is_running(struct Scene *scene);
void seq_prefetch_get_time_range(struct Scene *scene, int *start, int *end);
+/**
+ * For cache context swapping.
+ */
struct SeqRenderData *seq_prefetch_get_original_context(const struct SeqRenderData *context);
+/**
+ * For cache context swapping.
+ */
struct Sequence *seq_prefetch_get_original_sequence(struct Sequence *seq, struct Scene *scene);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 2bc294c91cd..30afa3f9c59 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -34,6 +34,7 @@
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
+#include "BLI_session_uuid.h"
#include "BLI_string.h"
#ifdef WIN32
@@ -54,6 +55,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
+#include "SEQ_iterator.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
@@ -79,6 +81,7 @@ typedef struct SeqIndexBuildContext {
Depsgraph *depsgraph;
Scene *scene;
Sequence *seq, *orig_seq;
+ SessionUUID orig_seq_uuid;
} SeqIndexBuildContext;
int SEQ_rendersize_to_proxysize(int render_size)
@@ -458,6 +461,7 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
context->depsgraph = depsgraph;
context->scene = scene;
context->orig_seq = seq;
+ context->orig_seq_uuid = seq->runtime.session_uuid;
context->seq = nseq;
context->view_id = i; /* only for images */
@@ -560,6 +564,18 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context,
}
}
+static bool seq_orig_free_anims(Sequence *seq_iter, void *data)
+{
+ SessionUUID orig_seq_uuid = ((SeqIndexBuildContext *)data)->orig_seq_uuid;
+
+ if (BLI_session_uuid_is_equal(&seq_iter->runtime.session_uuid, &orig_seq_uuid)) {
+ for (StripAnim *sanim = seq_iter->anims.first; sanim; sanim = sanim->next) {
+ IMB_close_anim_proxies(sanim->anim);
+ }
+ }
+ return true;
+}
+
void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
{
if (context->index_context) {
@@ -569,9 +585,8 @@ void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
IMB_close_anim_proxies(sanim->anim);
}
- for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next) {
- IMB_close_anim_proxies(sanim->anim);
- }
+ /* `context->seq_orig` may have been removed during building. */
+ SEQ_for_each_callback(&context->scene->ed->seqbase, seq_orig_free_anims, context);
IMB_anim_index_rebuild_finish(context->index_context, stop);
}
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 6030b49537c..a391deaccb4 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -97,6 +97,7 @@ SequencerDrawView sequencer_view3d_fn = NULL; /* NULL in background mode */
/* -------------------------------------------------------------------- */
/** \name Color-space utility functions
* \{ */
+
void seq_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
{
#if 0
@@ -213,6 +214,7 @@ void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4
/* -------------------------------------------------------------------- */
/** \name Rendering utility functions
* \{ */
+
void SEQ_render_new_render_data(Main *bmain,
struct Depsgraph *depsgraph,
Scene *scene,
@@ -301,25 +303,24 @@ int seq_get_shown_sequences(ListBase *seqbase,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Preprocessing and effects
- * \{ */
-/*
- * input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE
+/** \name Preprocessing and Effects
+ *
+ * Input pre-processing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE.
*
* Do all the things you can't really do afterwards using sequence effects
- * (read: before rescaling to render resolution has been done)
+ * (read: before re-scaling to render resolution has been done).
*
* Order is important!
*
- * - Deinterlace
- * - Crop and transform in image source coordinate space
- * - Flip X + Flip Y (could be done afterwards, backward compatibility)
- * - Promote image to float data (affects pipeline operations afterwards)
+ * - De-interlace.
+ * - Crop and transform in image source coordinate space.
+ * - Flip X + Flip Y (could be done afterwards, backward compatibility).
+ * - Promote image to float data (affects pipeline operations afterwards).
* - Color balance (is most efficient in the byte -> float
* (future: half -> float should also work fine!)
- * case, if done on load, since we can use lookup tables)
- * - Premultiply
- */
+ * case, if done on load, since we can use lookup tables).
+ * - Pre-multiply.
+ * \{ */
static bool sequencer_use_transform(const Sequence *seq)
{
@@ -459,11 +460,7 @@ static void sequencer_thumbnail_transform(ImBuf *in, ImBuf *out)
transform_pivot_set_m4(transform_matrix, pivot);
invert_m4(transform_matrix);
- /* No crop. */
- rctf source_crop;
- BLI_rctf_init(&source_crop, 0, in->x, 0, in->y);
-
- IMB_transform(in, out, transform_matrix, &source_crop, IMB_FILTER_NEAREST);
+ IMB_transform(in, out, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, transform_matrix, NULL);
}
/* Check whether transform introduces transparent ares in the result (happens when the transformed
@@ -528,7 +525,7 @@ static void sequencer_preprocess_transform_crop(
const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR :
IMB_FILTER_NEAREST;
- IMB_transform(in, out, transform_matrix, &source_crop, filter);
+ IMB_transform(in, out, IMB_TRANSFORM_MODE_CROP_SRC, filter, transform_matrix, &source_crop);
if (!seq_image_transform_transparency_gained(context, seq)) {
out->planes = in->planes;
@@ -871,11 +868,13 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
return out;
}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Individual strip rendering functions
* \{ */
+
/**
* Render individual view for multi-view or single (default view) for mono-view.
*/
@@ -1618,11 +1617,13 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
return ibuf;
}
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Strip stack rendering functions
+/** \name Strip Stack Rendering Functions
* \{ */
+
static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -1918,11 +1919,6 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
return out;
}
-/**
- * \return The image buffer or NULL.
- *
- * \note The returned #ImBuf has its reference increased, free after usage!
- */
ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, int chanshown)
{
Scene *scene = context->scene;
@@ -2033,7 +2029,6 @@ static ImBuf *seq_get_uncached_thumbnail(const SeqRenderData *context,
return scaled_ibuf;
}
-/* Get cached thumbnails. */
ImBuf *SEQ_get_thumbnail(
const SeqRenderData *context, Sequence *seq, float timeline_frame, rcti *crop, bool clipped)
{
@@ -2058,7 +2053,6 @@ ImBuf *SEQ_get_thumbnail(
return ibuf_cropped;
}
-/* Render the series of thumbnails and store in cache. */
void SEQ_render_thumbnails(const SeqRenderData *context,
Sequence *seq,
Sequence *seq_orig,
@@ -2103,8 +2097,6 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
}
}
-/* Get frame step for equally spaced thumbnails. These thumbnails should always be present in
- * memory, so they can be used when zooming.*/
int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq)
{
const int content_len = (seq->enddisp - seq->startdisp - seq->startstill - seq->endstill);
@@ -2117,7 +2109,6 @@ int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq)
return content_len / thumbnails_base_set_count;
}
-/* Render set of evenly spaced thumbnails that are drawn when zooming. */
void SEQ_render_thumbnails_base_set(const SeqRenderData *context,
Sequence *seq,
Sequence *seq_orig,
diff --git a/source/blender/sequencer/intern/sequence_lookup.c b/source/blender/sequencer/intern/sequence_lookup.c
index 25b42957d99..8d451d59e92 100644
--- a/source/blender/sequencer/intern/sequence_lookup.c
+++ b/source/blender/sequencer/intern/sequence_lookup.c
@@ -105,11 +105,6 @@ static void seq_sequence_lookup_update_if_needed(const struct Scene *scene,
seq_sequence_lookup_rebuild(scene, lookup);
}
-/**
- * Free lookup hash data.
- *
- * \param scene: scene that owns lookup hash
- */
void SEQ_sequence_lookup_free(const Scene *scene)
{
BLI_assert(scene->ed);
@@ -119,16 +114,6 @@ void SEQ_sequence_lookup_free(const Scene *scene)
BLI_mutex_unlock(&lookup_lock);
}
-/**
- * Find a sequence with a given name.
- * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be
- * rebuilt.
- *
- * \param scene: scene that owns lookup hash
- * \param key: Sequence name without SQ prefix (seq->name + 2)
- *
- * \return pointer to Sequence
- */
Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
{
BLI_assert(scene->ed);
@@ -140,12 +125,6 @@ Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
return seq;
}
-/**
- * Find a sequence with a given name.
- *
- * \param scene: scene that owns lookup hash
- * \param tag: tag to set
- */
void SEQ_sequence_lookup_tag(const Scene *scene, eSequenceLookupTag tag)
{
if (!scene->ed) {
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 3478c2d4f97..908a5bd4f79 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -227,8 +227,6 @@ void SEQ_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata
seq_sequence_free_ex(scene, seq, true, true, do_clean_animdata);
}
-/* cache must be freed before calling this function
- * since it leaves the seqbase in an invalid state */
void seq_free_sequence_recurse(Scene *scene,
Sequence *seq,
const bool do_id_user,
@@ -388,12 +386,6 @@ int SEQ_tool_settings_pivot_point_get(Scene *scene)
return tool_settings->pivot_point;
}
-/**
- * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
- *
- * \param ed: sequence editor data
- * \return pointer to active seqbase. returns NULL if ed is NULL
- */
ListBase *SEQ_active_seqbase_get(const Editing *ed)
{
if (ed == NULL) {
@@ -403,24 +395,11 @@ ListBase *SEQ_active_seqbase_get(const Editing *ed)
return ed->seqbasep;
}
-/**
- * Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
- *
- * \param ed: sequence editor data
- * \param seqbase: ListBase with strips
- */
void SEQ_seqbase_active_set(Editing *ed, ListBase *seqbase)
{
ed->seqbasep = seqbase;
}
-/**
- * Create and initialize #MetaStack, append it to `ed->metastack` ListBase
- *
- * \param ed: sequence editor data
- * \param seq_meta: meta strip
- * \return pointer to created meta stack
- */
MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
{
MetaStack *ms = MEM_mallocN(sizeof(MetaStack), "metastack");
@@ -431,24 +410,12 @@ MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
return ms;
}
-/**
- * Free #MetaStack and remove it from `ed->metastack` ListBase.
- *
- * \param ed: sequence editor data
- * \param ms: meta stack
- */
void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
{
BLI_remlink(&ed->metastack, ms);
MEM_freeN(ms);
}
-/**
- * Get #MetaStack that corresponds to current level that is being viewed
- *
- * \param ed: sequence editor data
- * \return pointer to meta stack
- */
MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
{
return ed->metastack.last;
@@ -459,6 +426,7 @@ MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
/* -------------------------------------------------------------------- */
/** \name Duplicate Functions
* \{ */
+
static Sequence *seq_dupli(const Scene *scene_src,
Scene *scene_dst,
ListBase *new_seq_list,
@@ -662,9 +630,11 @@ static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char
str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
}
-/* XXX: hackish function needed for transforming strips! TODO: have some better solution. */
void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs)
{
+ /* XXX: hackish function needed for transforming strips!
+ * TODO: have some better solution. */
+
char str[SEQ_RNAPATH_MAXSTR];
size_t str_len;
FCurve *fcu;
@@ -1069,10 +1039,6 @@ static bool seq_update_seq_cb(Sequence *seq, void *user_data)
return true;
}
-/* Evaluate parts of sequences which needs to be done as a part of a dependency graph evaluation.
- * This does NOT include actual rendering of the strips, but rather makes them up-to-date for
- * animation playback and makes them ready for the sequencer's rendering pipeline to render them.
- */
void SEQ_eval_sequences(Depsgraph *depsgraph, Scene *scene, ListBase *seqbase)
{
DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene);
diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h
index e43535d14ee..f8ad17e9032 100644
--- a/source/blender/sequencer/intern/sequencer.h
+++ b/source/blender/sequencer/intern/sequencer.h
@@ -30,6 +30,10 @@ extern "C" {
struct Scene;
struct Sequence;
+/**
+ * Cache must be freed before calling this function
+ * since it leaves the seqbase in an invalid state.
+ */
void seq_free_sequence_recurse(struct Scene *scene,
struct Sequence *seq,
const bool do_id_user,
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index 382fdd4953f..a4b537b9074 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -70,16 +70,6 @@
#include "proxy.h"
#include "utils.h"
-/**
- * Initialize common SeqLoadData members
- *
- * \param load_data: SeqLoadData to be initialized
- * \param name: strip name (can be NULL)
- * \param path: path to file that is used as strip input (can be NULL)
- * \param start_frame: timeline frame where strip will be created
- * \param channel: timeline channel where strip will be created
- *
- */
void SEQ_add_load_data_init(SeqLoadData *load_data,
const char *name,
const char *path,
@@ -147,14 +137,6 @@ static void seq_add_set_view_transform(Scene *scene, Sequence *seq, SeqLoadData
}
}
-/**
- * Add scene strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -168,14 +150,6 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
return seq;
}
-/**
- * Add movieclip strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -189,14 +163,6 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
return seq;
}
-/**
- * Add mask strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -210,14 +176,6 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
return seq;
}
-/**
- * Add effect strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -248,35 +206,17 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
return seq;
}
-/**
- * Set directory used by image strip.
- *
- * \param seq: image strip to be changed
- * \param path: directory path
- */
void SEQ_add_image_set_directory(Sequence *seq, char *path)
{
BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
}
-/**
- * Set directory used by image strip.
- *
- * \param seq: image strip to be changed
- * \param strip_frame: frame index of strip to be changed
- * \param filename: image filename (only filename, not complete path)
- */
void SEQ_add_image_load_file(Sequence *seq, size_t strip_frame, char *filename)
{
StripElem *se = SEQ_render_give_stripelem(seq, seq->start + strip_frame);
BLI_strncpy(se->name, filename, sizeof(se->name));
}
-/**
- * Set image strip alpha mode
- *
- * \param seq: image strip to be changed
- */
void SEQ_add_image_init_alpha_mode(Sequence *seq)
{
if (seq->strip && seq->strip->stripdata) {
@@ -306,16 +246,6 @@ void SEQ_add_image_init_alpha_mode(Sequence *seq)
}
}
-/**
- * Add image strip.
- * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
Sequence *seq = SEQ_sequence_alloc(
@@ -364,17 +294,6 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
}
#ifdef WITH_AUDASPACE
-/**
- * Add sound strip.
- * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
-
Sequence *SEQ_add_sound_strip(Main *bmain,
Scene *scene,
ListBase *seqbase,
@@ -444,15 +363,6 @@ Sequence *SEQ_add_sound_strip(Main *UNUSED(bmain),
}
#endif // WITH_AUDASPACE
-/**
- * Add meta strip.
- *
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
-
Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_data)
{
/* Allocate sequence. */
@@ -470,15 +380,6 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_
return seqm;
}
-/**
- * Add movie strip.
- *
- * \param main: Main reference
- * \param scene: Scene where strips will be added
- * \param seqbase: ListBase where strips will be added
- * \param load_data: SeqLoadData with information necessary to create strip
- * \return created strip
- */
Sequence *SEQ_add_movie_strip(
Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data, double *r_start_offset)
{
@@ -617,7 +518,6 @@ Sequence *SEQ_add_movie_strip(
return seq;
}
-/* NOTE: caller should run SEQ_time_update_sequence(scene, seq) after. */
void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range)
{
char path[FILE_MAX];
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 00b3da86306..912ba9d41db 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -175,7 +175,6 @@ static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Se
}
}
-/* Flag seq and its users (effects) for removal. */
void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
{
if (seq == NULL || (seq->flag & SEQ_FLAG_DELETE) != 0) {
@@ -193,7 +192,6 @@ void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
sequencer_flag_users_for_removal(scene, seqbase, seq);
}
-/* Remove all flagged sequences, return true if sequence is removed. */
void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
{
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) {
@@ -221,14 +219,6 @@ static bool seq_exists_in_seqbase(Sequence *seq, ListBase *seqbase)
return false;
}
-/**
- * Move sequence to seqbase.
- *
- * \param scene: Scene containing the editing
- * \param dst_seqbase: seqbase where `seq` is located
- * \param seq: Sequence to move
- * \param dst_seqbase: Target seqbase
- */
bool SEQ_edit_move_strip_to_seqbase(Scene *scene,
ListBase *seqbase,
Sequence *seq,
@@ -247,14 +237,6 @@ bool SEQ_edit_move_strip_to_seqbase(Scene *scene,
return true;
}
-/**
- * Move sequence to meta sequence.
- *
- * \param scene: Scene containing the editing
- * \param src_seq: Sequence to move
- * \param dst_seqm: Target Meta sequence
- * \param error_str: Error message
- */
bool SEQ_edit_move_strip_to_meta(Scene *scene,
Sequence *src_seq,
Sequence *dst_seqm,
@@ -468,17 +450,6 @@ static bool seq_edit_split_operation_permitted_check(SeqCollection *strips,
return true;
}
-/**
- * Split Sequence at timeline_frame in two.
- *
- * \param bmain: Main in which Sequence is located
- * \param scene: Scene in which Sequence is located
- * \param seqbase: ListBase in which Sequence is located
- * \param seq: Sequence to be split
- * \param timeline_frame: frame at which seq is split.
- * \param method: affects type of offset to be applied to resize Sequence
- * \return The newly created sequence strip. This is always Sequence on right side.
- */
Sequence *SEQ_edit_strip_split(Main *bmain,
Scene *scene,
ListBase *seqbase,
@@ -558,15 +529,6 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
return return_seq;
}
-/**
- * Find gap after initial_frame and move strips on right side to close the gap
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param initial_frame: frame on timeline from where gaps are searched for
- * \param remove_all_gaps: remove all gaps instead of one gap
- * \return true if gap is removed, otherwise false
- */
bool SEQ_edit_remove_gaps(Scene *scene,
ListBase *seqbase,
const int initial_frame,
diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c
index e6d9cd330b3..7e7fc9e6bf7 100644
--- a/source/blender/sequencer/intern/strip_relations.c
+++ b/source/blender/sequencer/intern/strip_relations.c
@@ -29,6 +29,7 @@
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_session_uuid.h"
#include "BKE_main.h"
@@ -281,14 +282,31 @@ void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
}
}
-static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame)
+static void sequencer_all_free_anim_ibufs(Editing *ed,
+ ListBase *seqbase,
+ int timeline_frame,
+ const int frame_range[2])
{
for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
- if (!SEQ_time_strip_intersects_frame(seq, timeline_frame)) {
+ if (!SEQ_time_strip_intersects_frame(seq, timeline_frame) ||
+ !((frame_range[0] <= timeline_frame) && (frame_range[1] > timeline_frame))) {
SEQ_relations_sequence_free_anim(seq);
}
if (seq->type == SEQ_TYPE_META) {
- sequencer_all_free_anim_ibufs(&seq->seqbase, timeline_frame);
+ int meta_range[2];
+
+ MetaStack *ms = SEQ_meta_stack_active_get(ed);
+ if (ms != NULL && ms->parseq == seq) {
+ meta_range[0] = -MAXFRAME;
+ meta_range[1] = MAXFRAME;
+ }
+ else {
+ /* Limit frame range to meta strip. */
+ meta_range[0] = max_ii(frame_range[0], seq->startdisp);
+ meta_range[1] = min_ii(frame_range[1], seq->enddisp);
+ }
+
+ sequencer_all_free_anim_ibufs(ed, &seq->seqbase, timeline_frame, meta_range);
}
}
}
@@ -299,7 +317,9 @@ void SEQ_relations_free_all_anim_ibufs(Scene *scene, int timeline_frame)
if (ed == NULL) {
return;
}
- sequencer_all_free_anim_ibufs(&ed->seqbase, timeline_frame);
+
+ const int frame_range[2] = {-MAXFRAME, MAXFRAME};
+ sequencer_all_free_anim_ibufs(ed, &ed->seqbase, timeline_frame, frame_range);
}
static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
@@ -352,7 +372,6 @@ bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports)
return false;
}
-/* Check if "seq_main" (indirectly) uses strip "seq". */
bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq)
{
if (seq_main == NULL || seq == NULL) {
@@ -379,7 +398,6 @@ bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq)
return false;
}
-/* Function to free imbuf and anim data on changes */
void SEQ_relations_sequence_free_anim(Sequence *seq)
{
while (seq->anims.last) {
@@ -432,7 +450,6 @@ void SEQ_relations_check_uuids_unique_and_report(const Scene *scene)
BLI_gset_free(used_uuids, NULL);
}
-/* Return immediate parent meta of sequence */
struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq)
{
Sequence *iseq;
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index a8e07f37a0b..3228277ce72 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -434,12 +434,6 @@ float SEQ_time_sequence_get_fps(Scene *scene, Sequence *seq)
return 0.0f;
}
-/**
- * Initialize given rectangle with the Scene's timeline boundaries.
- *
- * \param scene: the Scene instance whose timeline boundaries are extracted from
- * \param rect: output parameter to be filled with timeline boundaries
- */
void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
{
rect->xmin = scene->r.sfra;
@@ -448,12 +442,6 @@ void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
rect->ymax = 8.0f;
}
-/**
- * Stretch the given rectangle to include the given strips boundaries
- *
- * \param seqbase: ListBase in which strips are located
- * \param rect: output parameter to be filled with strips' boundaries
- */
void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
{
if (seqbase == NULL) {
@@ -473,13 +461,6 @@ void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
}
}
-/**
- * Define boundary rectangle of sequencer timeline and fill in rect data
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param rect: data structure describing rectangle, that will be filled in by this function
- */
void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
{
SEQ_timeline_init_boundbox(scene, rect);
@@ -497,14 +478,6 @@ static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_
return false;
}
-/**
- * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param initial_frame: frame on timeline from where gaps are searched for
- * \param r_gap_info: data structure describing gap, that will be filled in by this function
- */
void seq_time_gap_info_get(const Scene *scene,
ListBase *seqbase,
const int initial_frame,
@@ -550,15 +523,6 @@ void seq_time_gap_info_get(const Scene *scene,
}
}
-/**
- * Test if strip intersects with timeline frame.
- * NOTE: This checks if strip would be rendered at this frame. For rendering it is assumed, that
- * timeline frame has width of 1 frame and therefore ends at timeline_frame + 1
- *
- * \param seq: Sequence to be checked
- * \param timeline_frame: absolute frame position
- * \return true if strip intersects with timeline frame.
- */
bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_frame)
{
return (seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame);
diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h
index ca9a935bc96..aa807b6da25 100644
--- a/source/blender/sequencer/intern/strip_time.h
+++ b/source/blender/sequencer/intern/strip_time.h
@@ -40,6 +40,15 @@ typedef struct GapInfo {
int gap_length; /* Length of the gap. */
bool gap_exists; /* False if there are no gaps. */
} GapInfo;
+
+/**
+ * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info
+ *
+ * \param scene: Scene in which strips are located.
+ * \param seqbase: ListBase in which strips are located.
+ * \param initial_frame: frame on timeline from where gaps are searched for.
+ * \param r_gap_info: data structure describing gap, that will be filled in by this function.
+ */
void seq_time_gap_info_get(const struct Scene *scene,
struct ListBase *seqbase,
const int initial_frame,
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 63ab4a30edc..ce5917b999f 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -86,8 +86,6 @@ void SEQ_transform_set_right_handle_frame(Sequence *seq, int val)
}
}
-/* used so we can do a quick check for single image seq
- * since they work a bit differently to normal image seq's (during transform) */
bool SEQ_transform_single_image_check(Sequence *seq)
{
return ((seq->len == 1) &&
@@ -95,7 +93,6 @@ bool SEQ_transform_single_image_check(Sequence *seq)
((seq->type & SEQ_TYPE_EFFECT) && SEQ_effect_get_num_inputs(seq->type) == 0)));
}
-/* check if the selected seq's reference unselected seq's */
bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
{
Sequence *seq;
@@ -137,10 +134,6 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
return true;
}
-/**
- * Use to impose limits when dragging/extending - so impossible situations don't happen.
- * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip.
- */
void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
{
if (leftflag) {
@@ -257,7 +250,6 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
SEQ_time_update_sequence(evil_scene, seqbase, seq);
}
-/* return 0 if there weren't enough space */
bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
Sequence *test,
Scene *evil_scene,
@@ -393,14 +385,6 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
return offset ? false : true;
}
-/**
- * Move strips and markers (if not locked) that start after timeline_frame by delta frames
- *
- * \param scene: Scene in which strips are located
- * \param seqbase: ListBase in which strips are located
- * \param delta: offset in frames to be applied
- * \param timeline_frame: frame on timeline from where strips are moved
- */
void SEQ_transform_offset_after_frame(Scene *scene,
ListBase *seqbase,
const int delta,
@@ -436,14 +420,6 @@ void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2
}
}
-/**
- * Get strip transform origin offset from image center
- * Note: This function does not apply axis mirror.
- *
- * \param scene: Scene in which strips are located
- * \param seq: Sequence to calculate image transform origin
- * \param r_origin: return value
- */
void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
const Sequence *seq,
float r_origin[2])
@@ -463,9 +439,11 @@ void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
r_origin[0] = (image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs;
r_origin[1] = (image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs;
+ const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
float mirror[2];
SEQ_image_transform_mirror_factor_get(seq, mirror);
mul_v2_v2(r_origin, mirror);
+ mul_v2_v2(r_origin, viewport_pixel_aspect);
}
static void seq_image_transform_quad_get_ex(const Scene *scene,
@@ -483,7 +461,6 @@ static void seq_image_transform_quad_get_ex(const Scene *scene,
}
float transform_matrix[4][4];
-
float rotation_matrix[3][3];
axis_angle_to_mat3_single(rotation_matrix, 'Z', apply_rotation ? transform->rotation : 0.0f);
loc_rot_size_to_mat4(transform_matrix,
@@ -512,22 +489,16 @@ static void seq_image_transform_quad_get_ex(const Scene *scene,
float mirror[2];
SEQ_image_transform_mirror_factor_get(seq, mirror);
+ const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
+
for (int i = 0; i < 4; i++) {
mul_m4_v3(transform_matrix, quad_temp[i]);
mul_v2_v2(quad_temp[i], mirror);
+ mul_v2_v2(quad_temp[i], viewport_pixel_aspect);
copy_v2_v2(r_quad[i], quad_temp[i]);
}
}
-/**
- * Get 4 corner points of strip image, optionally without rotation component applied.
- * Corner vectors are in viewport space.
- *
- * \param scene: Scene in which strips are located
- * \param seq: Sequence to calculate transformed image quad
- * \param apply_rotation: Apply sequence rotation transform to the quad
- * \param r_quad: array of 4 2D vectors
- */
void SEQ_image_transform_quad_get(const Scene *scene,
const Sequence *seq,
bool apply_rotation,
@@ -536,13 +507,6 @@ void SEQ_image_transform_quad_get(const Scene *scene,
seq_image_transform_quad_get_ex(scene, seq, apply_rotation, r_quad);
}
-/**
- * Get 4 corner points of strip image. Corner vectors are in viewport space.
- *
- * \param scene: Scene in which strips are located
- * \param seq: Sequence to calculate transformed image quad
- * \param r_quad: array of 4 2D vectors
- */
void SEQ_image_transform_final_quad_get(const Scene *scene,
const Sequence *seq,
float r_quad[4][2])
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index 71686065882..cd779b0b0c7 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -55,13 +55,6 @@
#include "proxy.h"
#include "utils.h"
-/**
- * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by
- * channel position as well.
- * This is important for SEQ_time_update_sequence to work properly
- *
- * \param seqbase: ListBase with strips
- */
void SEQ_sort(ListBase *seqbase)
{
if (seqbase == NULL) {
@@ -432,7 +425,6 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame)
return best_seq;
}
-/* in cases where we don't know the sequence's listbase */
ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq)
{
Sequence *iseq;
@@ -465,10 +457,6 @@ Sequence *SEQ_get_meta_by_seqbase(ListBase *seqbase_main, ListBase *meta_seqbase
return seq;
}
-/**
- * Only use as last resort when the StripElem is available but no the Sequence.
- * (needed for RNA)
- */
Sequence *SEQ_sequence_from_strip_elem(ListBase *seqbase, StripElem *se)
{
Sequence *iseq;
@@ -525,10 +513,10 @@ void SEQ_alpha_mode_from_file_extension(Sequence *seq)
}
}
-/* called on draw, needs to be fast,
- * we could cache and use a flag if we want to make checks for file paths resolving for eg. */
bool SEQ_sequence_has_source(const Sequence *seq)
{
+ /* Called on draw, needs to be fast,
+ * we could cache and use a flag if we want to make checks for file paths resolving for eg. */
switch (seq->type) {
case SEQ_TYPE_MASK:
return (seq->mask != NULL);
@@ -589,13 +577,6 @@ void SEQ_set_scale_to_fit(const Sequence *seq,
}
}
-/**
- * Ensure, that provided Sequence has unique name. If animation data exists for this Sequence, it
- * will be duplicated and mapped onto new name
- *
- * \param seq: Sequence which name will be ensured to be unique
- * \param scene: Scene in which name must be unique
- */
void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
{
char name[SEQ_NAME_MAXSTR];
diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c
index de5bef5d8d5..314aafd6b70 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.c
+++ b/source/blender/shader_fx/intern/FX_ui_common.c
@@ -93,9 +93,6 @@ static void set_shaderfx_expand_flag(const bContext *UNUSED(C), Panel *panel, sh
/** \name ShaderFx Panel Layouts
* \{ */
-/**
- * Draw shaderfx error message.
- */
void shaderfx_panel_end(uiLayout *layout, PointerRNA *ptr)
{
ShaderFxData *fx = ptr->data;
@@ -105,9 +102,6 @@ void shaderfx_panel_end(uiLayout *layout, PointerRNA *ptr)
}
}
-/**
- * Gets RNA pointers for the active object and the panel's shaderfx data.
- */
PointerRNA *shaderfx_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
{
PointerRNA *ptr = UI_panel_custom_data_get(panel);
@@ -117,7 +111,7 @@ PointerRNA *shaderfx_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_
RNA_pointer_create(ptr->owner_id, &RNA_Object, ptr->owner_id, r_ob_ptr);
}
- uiLayoutSetContextPointer(panel->layout, "shaderfx", ptr);
+ UI_panel_context_pointer_set(panel, "shaderfx", ptr);
return ptr;
}
@@ -236,9 +230,6 @@ static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt))
return (ob != NULL) && (ob->type == OB_GPENCIL);
}
-/**
- * Create a panel in the context's region
- */
PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw)
{
PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
@@ -264,12 +255,6 @@ PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type,
return panel_type;
}
-/**
- * Add a child panel to the parent.
- *
- * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
- * idname.
- */
PanelType *shaderfx_subpanel_register(ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/shader_fx/intern/FX_ui_common.h b/source/blender/shader_fx/intern/FX_ui_common.h
index 151a2d31eb8..04982b9c0cf 100644
--- a/source/blender/shader_fx/intern/FX_ui_common.h
+++ b/source/blender/shader_fx/intern/FX_ui_common.h
@@ -32,13 +32,28 @@ struct bContext;
struct uiLayout;
typedef void (*PanelDrawFn)(const bContext *, Panel *);
+/**
+ * Draw shaderfx error message.
+ */
void shaderfx_panel_end(struct uiLayout *layout, PointerRNA *ptr);
+/**
+ * Gets RNA pointers for the active object and the panel's shaderfx data.
+ */
struct PointerRNA *shaderfx_panel_get_property_pointers(struct Panel *panel,
struct PointerRNA *r_ob_ptr);
+/**
+ * Create a panel in the context's region
+ */
PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw);
+/**
+ * Add a child panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
struct PanelType *shaderfx_subpanel_register(struct ARegionType *region_type,
const char *name,
const char *label,
diff --git a/source/blender/simulation/intern/ConstrainedConjugateGradient.h b/source/blender/simulation/intern/ConstrainedConjugateGradient.h
index c231d511733..d4d6057cd4c 100644
--- a/source/blender/simulation/intern/ConstrainedConjugateGradient.h
+++ b/source/blender/simulation/intern/ConstrainedConjugateGradient.h
@@ -167,10 +167,10 @@ struct traits<
* algorithm. The sparse matrix A must be self-adjoint. The vectors x and b can be either dense or
* sparse.
*
- * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
- * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * \tparam _MatrixType: the type of the sparse matrix A, can be a dense or a sparse matrix.
+ * \tparam _UpLo: the triangular part that will be used for the computations. It can be Lower
* or Upper. Default is Lower.
- * \tparam _Preconditioner the type of the pre-conditioner. Default is #DiagonalPreconditioner
+ * \tparam _Preconditioner: the type of the pre-conditioner. Default is #DiagonalPreconditioner
*
* The maximal number of iterations and tolerance value can be controlled via the
* setMaxIterations() and setTolerance() methods. The defaults are the size of the problem for the
diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp
index 348c8683be9..e47593eda05 100644
--- a/source/blender/simulation/intern/hair_volume.cpp
+++ b/source/blender/simulation/intern/hair_volume.cpp
@@ -633,9 +633,6 @@ BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert,
}
}
-/* XXX simplified test implementation using a series of discrete sample along the segment,
- * instead of finding the closest point for all affected grid vertices.
- */
void SIM_hair_volume_add_segment(HairGrid *grid,
const float UNUSED(x1[3]),
const float UNUSED(v1[3]),
@@ -649,6 +646,9 @@ void SIM_hair_volume_add_segment(HairGrid *grid,
const float UNUSED(dir2[3]),
const float UNUSED(dir3[3]))
{
+ /* XXX simplified test implementation using a series of discrete sample along the segment,
+ * instead of finding the closest point for all affected grid vertices. */
+
const float radius = 1.5f;
const float dist_scale = grid->inv_cellsize;
diff --git a/source/blender/simulation/intern/implicit.h b/source/blender/simulation/intern/implicit.h
index a8693c61018..c8eab94d315 100644
--- a/source/blender/simulation/intern/implicit.h
+++ b/source/blender/simulation/intern/implicit.h
@@ -80,7 +80,8 @@ void SIM_mass_spring_get_motion_state(struct Implicit_Data *data,
void SIM_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]);
void SIM_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]);
-/* access to modified motion state during solver step */
+/* Access to modified motion state during solver step. */
+
void SIM_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]);
void SIM_mass_spring_set_new_position(struct Implicit_Data *data, int index, const float x[3]);
void SIM_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3]);
@@ -106,44 +107,64 @@ bool SIM_mass_spring_solve_velocities(struct Implicit_Data *data,
bool SIM_mass_spring_solve_positions(struct Implicit_Data *data, float dt);
void SIM_mass_spring_apply_result(struct Implicit_Data *data);
-/* Clear the force vector at the beginning of the time step */
+/**
+ * Clear the force vector at the beginning of the time step.
+ */
void SIM_mass_spring_clear_forces(struct Implicit_Data *data);
-/* Fictitious forces introduced by moving coordinate systems */
+/**
+ * Fictitious forces introduced by moving coordinate systems.
+ */
void SIM_mass_spring_force_reference_frame(struct Implicit_Data *data,
int index,
const float acceleration[3],
const float omega[3],
const float domega_dt[3],
float mass);
-/* Simple uniform gravity force */
+/**
+ * Simple uniform gravity force.
+ */
void SIM_mass_spring_force_gravity(struct Implicit_Data *data,
int index,
float mass,
const float g[3]);
-/* Global drag force (velocity damping) */
+/**
+ * Global drag force (velocity damping).
+ */
void SIM_mass_spring_force_drag(struct Implicit_Data *data, float drag);
-/* Custom external force */
+/**
+ * Custom external force.
+ */
void SIM_mass_spring_force_extern(
struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]);
-/* Wind force, acting on a face (only generates pressure from the normal component) */
+/**
+ * Wind force, acting on a face (only generates pressure from the normal component).
+ */
void SIM_mass_spring_force_face_wind(
struct Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3]);
-/* Arbitrary per-unit-area vector force field acting on a face. */
+/**
+ * Arbitrary per-unit-area vector force field acting on a face..
+ */
void SIM_mass_spring_force_face_extern(
struct Implicit_Data *data, int v1, int v2, int v3, const float (*forcevec)[3]);
-/* Wind force, acting on an edge */
+/**
+ * Wind force, acting on an edge.
+ */
void SIM_mass_spring_force_edge_wind(struct Implicit_Data *data,
int v1,
int v2,
float radius1,
float radius2,
const float (*winvec)[3]);
-/* Wind force, acting on a vertex */
+/**
+ * Wind force, acting on a vertex.
+ */
void SIM_mass_spring_force_vertex_wind(struct Implicit_Data *data,
int v,
float radius,
const float (*winvec)[3]);
-/* Linear spring force between two points */
+/**
+ * Linear spring force between two points.
+ */
bool SIM_mass_spring_force_spring_linear(struct Implicit_Data *data,
int i,
int j,
@@ -155,7 +176,9 @@ bool SIM_mass_spring_force_spring_linear(struct Implicit_Data *data,
bool resist_compress,
bool new_compress,
float clamp_force);
-/* Angular spring force between two polygons */
+/**
+ * Angular spring force between two polygons.
+ */
bool SIM_mass_spring_force_spring_angular(struct Implicit_Data *data,
int i,
int j,
@@ -166,10 +189,14 @@ bool SIM_mass_spring_force_spring_angular(struct Implicit_Data *data,
float restang,
float stiffness,
float damping);
-/* Bending force, forming a triangle at the base of two structural springs */
+/**
+ * Bending force, forming a triangle at the base of two structural springs.
+ */
bool SIM_mass_spring_force_spring_bending(
struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb);
-/* Angular bending force based on local target vectors */
+/**
+ * Angular bending force based on local target vectors.
+ */
bool SIM_mass_spring_force_spring_bending_hair(struct Implicit_Data *data,
int i,
int j,
@@ -177,7 +204,9 @@ bool SIM_mass_spring_force_spring_bending_hair(struct Implicit_Data *data,
const float target[3],
float stiffness,
float damping);
-/* Global goal spring */
+/**
+ * Global goal spring.
+ */
bool SIM_mass_spring_force_spring_goal(struct Implicit_Data *data,
int i,
const float goal_x[3],
@@ -242,13 +271,15 @@ void SIM_hair_volume_grid_interpolate(struct HairGrid *grid,
float density_gradient[3],
float velocity_gradient[3][3]);
-/* Effect of fluid simulation grid on velocities.
+/**
+ * Effect of fluid simulation grid on velocities.
* fluid_factor controls blending between PIC (Particle-in-Cell)
* and FLIP (Fluid-Implicit-Particle) methods (0 = only PIC, 1 = only FLIP)
*/
void SIM_hair_volume_grid_velocity(
struct HairGrid *grid, const float x[3], const float v[3], float fluid_factor, float r_v[3]);
-/* XXX Warning: expressing grid effects on velocity as a force is not very stable,
+/**
+ * WARNING: expressing grid effects on velocity as a force is not very stable,
* due to discontinuities in interpolated values!
* Better use hybrid approaches such as described in
* "Detail Preserving Continuum Simulation of Straight Hair"
diff --git a/source/blender/simulation/intern/implicit_blender.c b/source/blender/simulation/intern/implicit_blender.c
index ad903e9da4a..add047bf8c8 100644
--- a/source/blender/simulation/intern/implicit_blender.c
+++ b/source/blender/simulation/intern/implicit_blender.c
@@ -1475,11 +1475,12 @@ static float calc_nor_area_tri(float nor[3],
return normalize_v3(nor) / 2.0f;
}
-/* XXX does not support force jacobians yet, since the effector system does not provide them either
- */
void SIM_mass_spring_force_face_wind(
Implicit_Data *data, int v1, int v2, int v3, const float (*winvec)[3])
{
+ /* XXX does not support force jacobians yet,
+ * since the effector system does not provide them either. */
+
const float effector_scale = 0.02f;
const int vs[3] = {v1, v2, v3};
float win[3], nor[3], area;
@@ -1854,10 +1855,11 @@ bool SIM_mass_spring_force_spring_linear(Implicit_Data *data,
return true;
}
-/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
bool SIM_mass_spring_force_spring_bending(
Implicit_Data *data, int i, int j, float restlen, float kb, float cb)
{
+ /* See "Stable but Responsive Cloth" (Choi, Ko 2005). */
+
float extent[3], length, dir[3], vel[3];
/* calculate elongation */
@@ -1959,8 +1961,6 @@ BLI_INLINE void spring_angle(Implicit_Data *data,
sub_v3_v3(r_vel_b, vel_e);
}
-/* Angular springs roughly based on the bending model proposed by Baraff and Witkin in "Large Steps
- * in Cloth Simulation". */
bool SIM_mass_spring_force_spring_angular(Implicit_Data *data,
int i,
int j,
@@ -2179,9 +2179,6 @@ BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data,
}
}
-/* Angular spring that pulls the vertex toward the local target
- * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
- */
bool SIM_mass_spring_force_spring_bending_hair(Implicit_Data *data,
int i,
int j,
@@ -2190,6 +2187,9 @@ bool SIM_mass_spring_force_spring_bending_hair(Implicit_Data *data,
float stiffness,
float damping)
{
+ /* Angular springs roughly based on the bending model proposed by Baraff and Witkin in
+ * "Large Steps in Cloth Simulation". */
+
float goal[3];
float fj[3], fk[3];
float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 8d25ece3753..4ffd31a9923 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -84,11 +84,24 @@ typedef struct wmGizmoMap wmGizmoMap;
typedef struct wmGizmoMapType wmGizmoMapType;
typedef struct wmJob wmJob;
-/* general API */
+/* General API. */
+
+/**
+ * Used for setting app-template from the command line:
+ * - non-empty string: overrides.
+ * - empty string: override, using no app template.
+ * - NULL: clears override.
+ */
void WM_init_state_app_template_set(const char *app_template);
const char *WM_init_state_app_template_get(void);
+/**
+ * Called when no ghost system was initialized.
+ */
void WM_init_state_size_set(int stax, int stay, int sizx, int sizy);
+/**
+ * For border-less and border windows set from command-line.
+ */
void WM_init_state_fullscreen_set(void);
void WM_init_state_normal_set(void);
void WM_init_state_maximized_set(void);
@@ -97,9 +110,21 @@ void WM_init_window_focus_set(bool do_it);
void WM_init_native_pixels(bool do_it);
void WM_init_tablet_api(void);
+/**
+ * Initialize Blender and load the startup file & preferences
+ * (only called once).
+ */
void WM_init(struct bContext *C, int argc, const char **argv);
+/**
+ * \note doesn't run exit() call #WM_exit() for that.
+ */
void WM_exit_ex(struct bContext *C, const bool do_python);
+/**
+ * \brief Main exit function to close Blender ordinarily.
+ * \note Use #wm_exit_schedule_delayed() to close Blender from an operator.
+ * Might leak memory otherwise.
+ */
void WM_exit(struct bContext *C) ATTR_NORETURN;
void WM_main(struct bContext *C) ATTR_NORETURN;
@@ -111,6 +136,10 @@ void WM_init_opengl(void);
void WM_check(struct bContext *C);
void WM_reinit_gizmomap_all(struct Main *bmain);
+/**
+ * Needed for cases when operators are re-registered
+ * (when operator type pointers are stored).
+ */
void WM_script_tag_reload(void);
wmWindow *WM_window_find_under_cursor(const wmWindowManager *wm,
@@ -125,13 +154,30 @@ void WM_window_pixel_sample_read(const wmWindowManager *wm,
uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]);
+/**
+ * Support for native pixel size
+ *
+ * \note macOS retina opens window in size X, but it has up to 2 x more pixels.
+ */
int WM_window_pixels_x(const struct wmWindow *win);
int WM_window_pixels_y(const struct wmWindow *win);
+/**
+ * Get boundaries usable by all window contents, including global areas.
+ */
void WM_window_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
+/**
+ * Get boundaries usable by screen-layouts, excluding global areas.
+ * \note Depends on #U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
+ */
void WM_window_screen_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
bool WM_window_is_fullscreen(const struct wmWindow *win);
bool WM_window_is_maximized(const struct wmWindow *win);
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors
+ * in visible work-spaces and their visible layouts.
+ */
void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATTR_NONNULL();
struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm,
const struct bScreen *screen)
@@ -145,6 +191,9 @@ struct WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm
struct Scene *WM_window_get_active_scene(const struct wmWindow *win)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * \warning Only call outside of area/region loops.
+ */
void WM_window_set_active_scene(struct Main *bmain,
struct bContext *C,
struct wmWindow *win,
@@ -159,6 +208,9 @@ struct WorkSpaceLayout *WM_window_get_active_layout(const struct wmWindow *win)
void WM_window_set_active_layout(struct wmWindow *win,
struct WorkSpace *workspace,
struct WorkSpaceLayout *layout) ATTR_NONNULL(1);
+/**
+ * Get the active screen of the active workspace in \a win.
+ */
struct bScreen *WM_window_get_active_screen(const struct wmWindow *win)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
void WM_window_set_active_screen(struct wmWindow *win,
@@ -185,6 +237,14 @@ typedef enum eWindowAlignment {
WIN_ALIGN_PARENT_CENTER,
} eWindowAlignment;
+/**
+ * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
+ * \param toplevel: Not a child owned by other windows. A peer of main window.
+ * \param dialog: whether this should be made as a dialog-style window
+ * \param temp: whether this is considered a short-lived window
+ * \param alignment: how this window is positioned relative to its parent
+ * \return the window or NULL in case of failure.
+ */
struct wmWindow *WM_window_open(struct bContext *C,
const char *title,
int x,
@@ -208,6 +268,10 @@ void WM_autosave_init(struct wmWindowManager *wm);
bool WM_recover_last_session(struct bContext *C, struct ReportList *reports);
void WM_file_tag_modified(void);
+/**
+ * \note `scene` (and related `view_layer` and `v3d`) pointers may be NULL,
+ * in which case no instantiation of linked objects, collections etc. will be performed.
+ */
struct ID *WM_file_link_datablock(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -216,6 +280,10 @@ struct ID *WM_file_link_datablock(struct Main *bmain,
const short id_code,
const char *id_name,
int flag);
+/**
+ * \note `scene` (and related `view_layer` and `v3d`) pointers may be NULL,
+ * in which case no instantiation of appended objects, collections etc. will be performed.
+ */
struct ID *WM_file_append_datablock(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
@@ -226,14 +294,24 @@ struct ID *WM_file_append_datablock(struct Main *bmain,
int flag);
void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports);
-/* mouse cursors */
+/* Mouse cursors. */
+
void WM_cursor_set(struct wmWindow *win, int curs);
bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *area, const ARegion *region);
void WM_cursor_modal_set(struct wmWindow *win, int val);
void WM_cursor_modal_restore(struct wmWindow *win);
+/**
+ * To allow usage all over, we do entire WM.
+ */
void WM_cursor_wait(bool val);
+/**
+ * \param bounds: can be NULL
+ */
void WM_cursor_grab_enable(struct wmWindow *win, int wrap, bool hide, int bounds[4]);
void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]);
+/**
+ * After this you can call restore too.
+ */
void WM_cursor_time(struct wmWindow *win, int nr);
struct wmPaintCursor *WM_paint_cursor_activate(
@@ -249,10 +327,16 @@ void WM_paint_cursor_remove_by_type(struct wmWindowManager *wm,
void (*free)(void *));
void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *region);
+/**
+ * This function requires access to the GHOST_SystemHandle (g_system).
+ */
void WM_cursor_warp(struct wmWindow *win, int x, int y);
+/**
+ * Set x, y to values we can actually position the cursor to.
+ */
void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y);
-/* handlers */
+/* Handlers. */
typedef bool (*EventHandlerPoll)(const ARegion *region, const struct wmEvent *event);
struct wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap);
@@ -261,7 +345,9 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_poll(ListBase *handler
EventHandlerPoll poll);
struct wmEventHandler_Keymap *WM_event_add_keymap_handler_v2d_mask(ListBase *handlers,
wmKeyMap *keymap);
-/* priority not implemented, it adds in begin */
+/**
+ * \note Priorities not implemented yet, for time being just insert in begin of list.
+ */
struct wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
wmKeyMap *keymap,
int priority);
@@ -319,6 +405,10 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
const char flag);
+/**
+ * \param postpone: Enable for `win->modalhandlers`,
+ * this is in a running for () loop in wm_handlers_do().
+ */
void WM_event_remove_ui_handler(ListBase *handlers,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
@@ -331,13 +421,24 @@ void WM_event_free_ui_handler_all(struct bContext *C,
wmUIHandlerRemoveFunc remove_fn);
struct wmEventHandler_Op *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
+/**
+ * Modal handlers store a pointer to an area which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_area.
+ */
void WM_event_modal_handler_area_replace(wmWindow *win,
const struct ScrArea *old_area,
struct ScrArea *new_area);
+/**
+ * Modal handlers store a pointer to a region which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_region.
+ */
void WM_event_modal_handler_region_replace(wmWindow *win,
const struct ARegion *old_region,
struct ARegion *new_region);
+/**
+ * Called on exit or remove area, only here call cancel callback.
+ */
void WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
/* handler flag */
@@ -366,11 +467,20 @@ void WM_event_add_notifier_ex(struct wmWindowManager *wm,
void *reference);
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference);
void WM_main_add_notifier(unsigned int type, void *reference);
+/**
+ * Clear notifiers by reference, Used so listeners don't act on freed data.
+ */
void WM_main_remove_notifier_reference(const void *reference);
void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id);
/* reports */
+/**
+ * Show the report in the info header.
+ */
void WM_report_banner_show(void);
+/**
+ * Hide all currently displayed banners and abort their timer.
+ */
void WM_report_banners_cancel(struct Main *bmain);
void WM_report(eReportType type, const char *message);
void WM_reportf(eReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
@@ -398,44 +508,87 @@ void WM_event_remove_timer(struct wmWindowManager *wm,
void WM_event_remove_timer_notifier(struct wmWindowManager *wm,
struct wmWindow *win,
struct wmTimer *timer);
+/**
+ * To (de)activate running timers temporary.
+ */
void WM_event_timer_sleep(struct wmWindowManager *wm,
struct wmWindow *win,
struct wmTimer *timer,
bool do_sleep);
-/* operator api, default callbacks */
-/* invoke callback, uses enum property named "type" */
+/* Operator API, default callbacks. */
+
+/**
+ * Helper to get select and tweak-transform to work conflict free and as desired. See
+ * #WM_operator_properties_generic_select() for details.
+ *
+ * To be used together with #WM_generic_select_invoke() and
+ * #WM_operator_properties_generic_select().
+ */
int WM_generic_select_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Helper to get select and tweak-transform to work conflict free and as desired. See
+ * #WM_operator_properties_generic_select() for details.
+ *
+ * To be used together with #WM_generic_select_modal() and
+ * #WM_operator_properties_generic_select().
+ */
int WM_generic_select_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op);
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
+/**
+ * Invoke callback, uses enum property named "type".
+ */
int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, wmOperatorCallContext opcontext);
int WM_menu_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+/**
+ * Call an existent menu. The menu can be created in C or Python.
+ */
void WM_menu_name_call(struct bContext *C, const char *menu_name, short context);
+/**
+ * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
+ * be used as invoke callback directly since it needs additional info.
+ */
int WM_enum_search_invoke_previews(struct bContext *C,
struct wmOperator *op,
short prv_cols,
short prv_rows);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
-/* invoke callback, confirm menu + exec */
+/**
+ * Invoke callback, confirm menu + exec.
+ */
int WM_operator_confirm(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_operator_confirm_or_exec(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
-/* invoke callback, file selector "filepath" unset + exec */
+/**
+ * Invoke callback, file selector "filepath" unset + exec.
+ *
+ * #wmOperatorType.invoke, opens file-select if path property not set, otherwise executes.
+ */
int WM_operator_filesel(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op,
const struct ImageFormatData *im_format);
-/* poll callback, context checks */
+/** Callback for #wmOperatorType.poll */
bool WM_operator_winactive(struct bContext *C);
-/* invoke callback, exec + redo popup */
+/**
+ * Invoke callback, exec + redo popup.
+ *
+ * Same as #WM_operator_props_popup but don't use operator redo.
+ * just wraps #WM_operator_props_dialog_popup.
+ */
int WM_operator_props_popup_confirm(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * Same as #WM_operator_props_popup but call the operator first,
+ * This way - the button values correspond to the result of the operator.
+ * Without this, first access to a button will make the result jump, see T32452.
+ */
int WM_operator_props_popup_call(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
@@ -446,6 +599,9 @@ int WM_operator_props_dialog_popup(struct bContext *C, struct wmOperator *op, in
int WM_operator_redo_popup(struct bContext *C, struct wmOperator *op);
int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width);
+/**
+ * Can't be used as an invoke directly, needs message arg (can be NULL).
+ */
int WM_operator_confirm_message_ex(struct bContext *C,
struct wmOperator *op,
const char *title,
@@ -454,22 +610,60 @@ int WM_operator_confirm_message_ex(struct bContext *C,
const wmOperatorCallContext opcontext);
int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message);
-/* operator api */
+/* Operator API. */
+
void WM_operator_free(struct wmOperator *op);
void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op);
+/**
+ * Use with extreme care!
+ * Properties, custom-data etc - must be compatible.
+ *
+ * \param op: Operator to assign the type to.
+ * \param ot: Operator type to assign.
+ */
void WM_operator_type_set(struct wmOperator *op, struct wmOperatorType *ot);
void WM_operator_stack_clear(struct wmWindowManager *wm);
+/**
+ * This function is needed in the case when an addon id disabled
+ * while a modal operator it defined is running.
+ */
void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot);
bool WM_operator_poll(struct bContext *C, struct wmOperatorType *ot);
bool WM_operator_poll_context(struct bContext *C, struct wmOperatorType *ot, short context);
+/**
+ * For running operators with frozen context (modal handlers, menus).
+ *
+ * \param store: Store settings for re-use.
+ *
+ * \warning do not use this within an operator to call its self! T29537.
+ */
int WM_operator_call_ex(struct bContext *C, struct wmOperator *op, const bool store);
int WM_operator_call(struct bContext *C, struct wmOperator *op);
+/**
+ * This is intended to be used when an invoke operator wants to call exec on its self
+ * and is basically like running op->type->exec() directly, no poll checks no freeing,
+ * since we assume whoever called invoke will take care of that
+ */
int WM_operator_call_notest(struct bContext *C, struct wmOperator *op);
+/**
+ * Execute this operator again, put here so it can share above code
+ */
int WM_operator_repeat(struct bContext *C, struct wmOperator *op);
int WM_operator_repeat_last(struct bContext *C, struct wmOperator *op);
+/**
+ * \return true if #WM_operator_repeat can run.
+ * Simple check for now but may become more involved.
+ * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
+ * checks if #WM_operator_repeat() can run at all, not that it WILL run at any time.
+ */
bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op);
bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op);
+
+bool WM_operator_name_poll(struct bContext *C, const char *opstring);
+/**
+ * Invokes operator in context.
+ */
int WM_operator_name_call_ptr(struct bContext *C,
struct wmOperatorType *ot,
wmOperatorCallContext context,
@@ -482,6 +676,13 @@ int WM_operator_name_call_with_properties(struct bContext *C,
const char *opstring,
wmOperatorCallContext context,
struct IDProperty *properties);
+/**
+ * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
+ *
+ * - #wmOperatorType is used instead of operator name since python already has the operator type.
+ * - `poll()` must be called by python before this runs.
+ * - reports can be passed to this function (so python can report them as exceptions).
+ */
int WM_operator_call_py(struct bContext *C,
struct wmOperatorType *ot,
wmOperatorCallContext context,
@@ -495,15 +696,30 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(struct bContext *C,
PointerRNA *properties,
const char *drawstr);
-/* Used for keymap and macro items. */
+/**
+ * Similar to the function above except its uses ID properties used for key-maps and macros.
+ */
void WM_operator_properties_alloc(struct PointerRNA **ptr,
struct IDProperty **properties,
const char *opstring);
-/* Make props context sensitive or not. */
+/**
+ * Make props context sensitive or not.
+ */
void WM_operator_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+/**
+ * Set all props to their default.
+ *
+ * \param do_update: Only update un-initialized props.
+ *
+ * \note There's nothing specific to operators here.
+ * This could be made a general function.
+ */
bool WM_operator_properties_default(struct PointerRNA *ptr, const bool do_update);
+/**
+ * Remove all props without #PROP_SKIP_SAVE.
+ */
void WM_operator_properties_reset(struct wmOperator *op);
void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring);
void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperatorType *ot);
@@ -511,18 +727,28 @@ void WM_operator_properties_clear(struct PointerRNA *ptr);
void WM_operator_properties_free(struct PointerRNA *ptr);
bool WM_operator_check_ui_empty(struct wmOperatorType *ot);
+/**
+ * Return false, if the UI should be disabled.
+ */
bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname);
IDProperty *WM_operator_last_properties_ensure_idprops(struct wmOperatorType *ot);
void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct PointerRNA *ptr);
wmOperator *WM_operator_last_redo(const struct bContext *C);
+/**
+ * Use for drag & drop a path or name with operators invoke() function.
+ */
ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, const short idcode);
bool WM_operator_last_properties_init(struct wmOperator *op);
bool WM_operator_last_properties_store(struct wmOperator *op);
/* wm_operator_props.c */
+
void WM_operator_properties_confirm_or_exec(struct wmOperatorType *ot);
+/**
+ * Default properties for file-select.
+ */
void WM_operator_properties_filesel(struct wmOperatorType *ot,
int filter,
short type,
@@ -530,36 +756,91 @@ void WM_operator_properties_filesel(struct wmOperatorType *ot,
short flag,
short display,
short sort);
+/**
+ * Disable using cursor position,
+ * use when view operators are initialized from buttons.
+ */
void WM_operator_properties_use_cursor_init(struct wmOperatorType *ot);
void WM_operator_properties_border(struct wmOperatorType *ot);
void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect);
void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect);
+/**
+ * Use with #WM_gesture_box_invoke
+ */
void WM_operator_properties_gesture_box_ex(struct wmOperatorType *ot, bool deselect, bool extend);
void WM_operator_properties_gesture_box(struct wmOperatorType *ot);
void WM_operator_properties_gesture_box_select(struct wmOperatorType *ot);
void WM_operator_properties_gesture_box_zoom(struct wmOperatorType *ot);
+/**
+ * Use with #WM_gesture_lasso_invoke
+ */
void WM_operator_properties_gesture_lasso(struct wmOperatorType *ot);
+/**
+ * Use with #WM_gesture_straightline_invoke
+ */
void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int cursor);
+/**
+ * Use with #WM_gesture_circle_invoke
+ */
void WM_operator_properties_gesture_circle(struct wmOperatorType *ot);
void WM_operator_properties_mouse_select(struct wmOperatorType *ot);
void WM_operator_properties_select_all(struct wmOperatorType *ot);
void WM_operator_properties_select_action(struct wmOperatorType *ot,
int default_action,
bool hide_gui);
+/**
+ * Only #SELECT / #DESELECT.
+ */
void WM_operator_properties_select_action_simple(struct wmOperatorType *ot,
int default_action,
bool hide_gui);
+/**
+ * Use for all select random operators.
+ * Adds properties: percent, seed, action.
+ */
void WM_operator_properties_select_random(struct wmOperatorType *ot);
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op);
void WM_operator_properties_select_operation(struct wmOperatorType *ot);
+/**
+ * \note Some tools don't support XOR/AND.
+ */
void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot);
void WM_operator_properties_select_walk_direction(struct wmOperatorType *ot);
+/**
+ * Selecting and tweaking items are overlapping operations. Getting both to work without conflicts
+ * requires special care. See
+ * https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking for the
+ * desired behavior.
+ *
+ * For default click selection (with no modifier keys held), the select operators can do the
+ * following:
+ * - On a mouse press on an unselected item, change selection and finish immediately after.
+ * This sends an undo push and allows transform to take over should a tweak event be caught now.
+ * - On a mouse press on a selected item, don't change selection state, but start modal execution
+ * of the operator. Idea is that we wait with deselecting other items until we know that the
+ * intention wasn't to tweak (mouse press+drag) all selected items.
+ * - If a tweak is recognized before the release event happens, cancel the operator, so that
+ * transform can take over and no undo-push is sent.
+ * - If the release event occurs rather than a tweak one, deselect all items but the one under the
+ * cursor, and finish the modal operator.
+ *
+ * This utility, together with #WM_generic_select_invoke() and #WM_generic_select_modal() should
+ * help getting the wanted behavior to work. Most generic logic should be handled in these, so that
+ * the select operators only have to care for the case dependent handling.
+ *
+ * Every select operator has slightly different requirements, e.g. sequencer strip selection
+ * also needs to account for handle selection. This should be the baseline behavior though.
+ */
void WM_operator_properties_generic_select(struct wmOperatorType *ot);
+
struct CheckerIntervalParams {
int nth; /* bypass when set to zero */
int skip;
int offset;
};
+/**
+ * \param nth_can_disable: Enable if we want to be able to select no interval at all.
+ */
void WM_operator_properties_checker_interval(struct wmOperatorType *ot, bool nth_can_disable);
void WM_operator_properties_checker_interval_from_op(struct wmOperator *op,
struct CheckerIntervalParams *op_params);
@@ -576,7 +857,17 @@ bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalPa
/* Show the properties sidebar by default. */
#define WM_FILESEL_SHOW_PROPS (1 << 5)
-/* operator as a python command (resultuing string must be freed) */
+/**
+ * Operator as a Python command (resulting string must be freed).
+ *
+ * Print a string representation of the operator,
+ * with the arguments that it runs so Python can run it again.
+ *
+ * When calling from an existing #wmOperator, better to use simple version:
+ * `WM_operator_pystring(C, op);`
+ *
+ * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
+ */
char *WM_operator_pystring_ex(struct bContext *C,
struct wmOperator *op,
const bool all_args,
@@ -587,16 +878,32 @@ char *WM_operator_pystring(struct bContext *C,
struct wmOperator *op,
const bool all_args,
const bool macro_args);
+/**
+ * \return true if the string was shortened.
+ */
bool WM_operator_pystring_abbreviate(char *str, int str_len_max);
char *WM_prop_pystring_assign(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
int index);
+/**
+ * Convert: `some.op` -> `SOME_OT_op` or leave as-is.
+ */
void WM_operator_bl_idname(char *to, const char *from);
+/**
+ * Convert: `SOME_OT_op` -> `some.op` or leave as-is.
+ */
void WM_operator_py_idname(char *to, const char *from);
+/**
+ * Sanity check to ensure #WM_operator_bl_idname won't fail.
+ * \returns true when there are no problems with \a idname, otherwise report an error.
+ */
bool WM_operator_py_idname_ok_or_report(struct ReportList *reports,
const char *classname,
const char *idname);
+/**
+ * Calculate the path to `ptr` from context `C`, or return NULL if it can't be calculated.
+ */
char *WM_context_path_resolve_property_full(const struct bContext *C,
const PointerRNA *ptr,
PropertyRNA *prop,
@@ -604,16 +911,46 @@ char *WM_context_path_resolve_property_full(const struct bContext *C,
char *WM_context_path_resolve_full(struct bContext *C, const PointerRNA *ptr);
/* wm_operator_type.c */
+
struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet);
+/**
+ * \note Caller must free.
+ */
void WM_operatortype_iter(struct GHashIterator *ghi);
void WM_operatortype_append(void (*opfunc)(struct wmOperatorType *));
void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata);
void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, void *),
void *userdata);
+/**
+ * Called on initialize WM_exit().
+ */
void WM_operatortype_remove_ptr(struct wmOperatorType *ot);
bool WM_operatortype_remove(const char *idname);
+/**
+ * Remove memory of all previously executed tools.
+ */
void WM_operatortype_last_properties_clear_all(void);
+/**
+ * Tag all operator-properties of \a ot defined after calling this, until
+ * the next #WM_operatortype_props_advanced_end call (if available), with
+ * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
+ *
+ * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
+ * all calls after the first one are ignored. Meaning all proprieties defined after the
+ * first call are tagged as advanced.
+ *
+ * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
+ * called for all operators during registration (see #wm_operatortype_append__end).
+ */
void WM_operatortype_props_advanced_begin(struct wmOperatorType *ot);
+/**
+ * Tags all operator-properties of \a ot defined since the first
+ * #WM_operatortype_props_advanced_begin call,
+ * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
+ *
+ * \note This is called for all operators during registration (see #wm_operatortype_append__end).
+ * So it does not need to be explicitly called in operator-type definition.
+ */
void WM_operatortype_props_advanced_end(struct wmOperatorType *ot);
#define WM_operatortype_prop_tag(property, tags) \
@@ -623,6 +960,9 @@ void WM_operatortype_props_advanced_end(struct wmOperatorType *ot);
} \
(void)0
+/**
+ * \note Names have to be static for now.
+ */
struct wmOperatorType *WM_operatortype_append_macro(const char *idname,
const char *name,
const char *description,
@@ -634,26 +974,57 @@ const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *p
char *WM_operatortype_description(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties);
+/**
+ * Use when we want a label, preferring the description.
+ */
char *WM_operatortype_description_or_name(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties);
/* wm_operator_utils.c */
+
+/**
+ * Allow an operator with only and execute function to run modally,
+ * re-doing the action, using vertex coordinate store/restore instead of operator undo.
+ */
void WM_operator_type_modal_from_exec_for_object_edit_coords(struct wmOperatorType *ot);
/* wm_uilist_type.c */
+
+/**
+ * Called on initialize #WM_init()
+ */
void WM_uilisttype_init(void);
struct uiListType *WM_uilisttype_find(const char *idname, bool quiet);
bool WM_uilisttype_add(struct uiListType *ult);
void WM_uilisttype_remove_ptr(struct Main *bmain, struct uiListType *ult);
void WM_uilisttype_free(void);
+/**
+ * The "full" list-ID is an internal name used for storing and identifying a list. It is built like
+ * this:
+ * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to
+ * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_".
+ *
+ * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it
+ * passed to `UILayout.template_list()`. C code can query that through
+ * #WM_uilisttype_list_id_get().
+ */
void WM_uilisttype_to_full_list_id(const struct uiListType *ult,
const char *list_id,
char r_full_list_id[]);
+/**
+ * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details.
+ *
+ * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()!
+ */
const char *WM_uilisttype_list_id_get(const struct uiListType *ult, struct uiList *list);
/* wm_menu_type.c */
+
+/**
+ * \note Called on initialize #WM_init().
+ */
void WM_menutype_init(void);
struct MenuType *WM_menutype_find(const char *idname, bool quiet);
void WM_menutype_iter(struct GHashIterator *ghi);
@@ -663,6 +1034,10 @@ void WM_menutype_free(void);
bool WM_menutype_poll(struct bContext *C, struct MenuType *mt);
/* wm_panel_type.c */
+
+/**
+ * Called on initialize #WM_init().
+ */
void WM_paneltype_init(void);
void WM_paneltype_clear(void);
struct PanelType *WM_paneltype_find(const char *idname, bool quiet);
@@ -690,6 +1065,11 @@ int WM_gesture_lasso_invoke(struct bContext *C,
const struct wmEvent *event);
int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
void WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op);
+/**
+ * helper function, we may want to add options for conversion to view space
+ *
+ * caller must free.
+ */
const int (*WM_gesture_lasso_path_to_array(struct bContext *C,
struct wmOperator *op,
int *mcoords_len))[2];
@@ -697,18 +1077,38 @@ const int (*WM_gesture_lasso_path_to_array(struct bContext *C,
int WM_gesture_straightline_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This invoke callback starts the straight-line gesture with a viewport preview to the right side
+ * of the line.
+ */
int WM_gesture_straightline_active_side_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This modal callback calls exec once per mouse move event while the gesture is active with the
+ * updated line start and end values, so it can be used for tools that have a real time preview
+ * (like a gradient updating in real time over the mesh).
+ */
int WM_gesture_straightline_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
+/**
+ * This modal one-shot callback only calls exec once after the gesture finishes without any updates
+ * during the gesture execution. Should be used for operations that are intended to be applied once
+ * without real time preview (like a trimming tool that only applies the bisect operation once
+ * after finishing the gesture as the bisect operation is too heavy to be computed in real time for
+ * a preview).
+ */
int WM_gesture_straightline_oneshot_modal(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
void WM_gesture_straightline_cancel(struct bContext *C, struct wmOperator *op);
/* Gesture manager API */
+
+/**
+ * Context checked on having screen, window and area.
+ */
struct wmGesture *WM_gesture_new(struct wmWindow *window,
const struct ARegion *region,
const struct wmEvent *event,
@@ -718,15 +1118,34 @@ void WM_gestures_remove(struct wmWindow *win);
void WM_gestures_free_all(struct wmWindow *win);
bool WM_gesture_is_modal_first(const struct wmGesture *gesture);
-/* fileselecting support */
+/* File-selecting support. */
+
+/**
+ * The idea here is to keep a handler alive on window queue, owning the operator.
+ * The file window can send event to make it execute, thus ensuring
+ * executing happens outside of lower level queues, with UI refreshed.
+ * Should also allow multi-window solutions.
+ */
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval);
+/**
+ * Sets the active region for this space from the context.
+ *
+ * \see #BKE_area_find_region_active_win
+ */
void WM_operator_region_active_win_set(struct bContext *C);
+/**
+ * Only finish + pass through for press events (allowing press-tweak).
+ */
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event);
-/* drag and drop */
+/* Drag and drop. */
+
+/**
+ * Note that the pointer should be valid allocated and not on stack.
+ */
struct wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy);
@@ -748,30 +1167,61 @@ void WM_drag_draw_default_fn(struct bContext *C,
struct wmWindow *win,
struct wmDrag *drag,
const int xy[2]);
+/**
+ * `spaceid` / `regionid` are zero for window drop maps.
+ */
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
/* ID drag and drop */
+
+/**
+ * \param flag_extra: Additional linking flags (from #eFileSel_Params_Flag).
+ */
ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, int flag_extra);
bool WM_drag_asset_will_import_linked(const wmDrag *drag);
void WM_drag_add_local_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent);
struct ID *WM_drag_get_local_ID(const struct wmDrag *drag, short idcode);
struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short idcode);
+/**
+ * Check if the drag data is either a local ID or an external ID asset of type \a idcode.
+ */
bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
+/**
+ * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
+ */
wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset,
struct AssetMetaData *metadata,
const char *path,
int import_type);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);
struct AssetMetaData *WM_drag_get_asset_meta_data(const struct wmDrag *drag, int idcode);
+/**
+ * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
+ * that depending on what was chosen by the drag-box (currently append only in fact).
+ *
+ * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset
+ * import is rolled back if the drop operator fails.
+ */
struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode);
+/**
+ * \brief Free asset ID imported for canceled drop.
+ *
+ * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()`
+ * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop
+ * operator cancels.
+ * This is for use as #wmDropBox.cancel() callback.
+ */
void WM_drag_free_imported_drag_ID(struct Main *bmain,
struct wmDrag *drag,
struct wmDropBox *drop);
struct wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const struct wmDrag *drag);
+/**
+ * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
+ */
void WM_drag_add_asset_list_item(wmDrag *drag,
const struct bContext *C,
const struct AssetLibraryReference *asset_library_ref,
@@ -788,6 +1238,10 @@ void wmWindowViewport(struct wmWindow *win);
/* OpenGL utilities with safety check */
void wmOrtho2(float x1, float x2, float y1, float y2);
/* use for conventions (avoid hard-coded offsets all over) */
+
+/**
+ * Default pixel alignment for regions.
+ */
void wmOrtho2_region_pixelspace(const struct ARegion *region);
void wmOrtho2_pixelspace(const float x, const float y);
void wmGetProjectionMatrix(float mat[4][4], const struct rcti *winrct);
@@ -834,6 +1288,12 @@ enum {
* if having hard coded values is a problem */
};
+/**
+ * \return current job or adds new job, but doesn't run it.
+ *
+ * \note every owner only gets a single job,
+ * adding a new one will stop running job and when stopped it starts the new one.
+ */
struct wmJob *WM_jobs_get(struct wmWindowManager *wm,
struct wmWindow *win,
const void *owner,
@@ -841,9 +1301,15 @@ struct wmJob *WM_jobs_get(struct wmWindowManager *wm,
int flag,
int job_type);
+/**
+ * Returns true if job runs, for UI (progress) indicators.
+ */
bool WM_jobs_test(const struct wmWindowManager *wm, const void *owner, int job_type);
float WM_jobs_progress(const struct wmWindowManager *wm, const void *owner);
const char *WM_jobs_name(const struct wmWindowManager *wm, const void *owner);
+/**
+ * Time that job started.
+ */
double WM_jobs_starttime(const struct wmWindowManager *wm, const void *owner);
void *WM_jobs_customdata(struct wmWindowManager *wm, const void *owner);
void *WM_jobs_customdata_from_type(struct wmWindowManager *wm, int job_type);
@@ -865,12 +1331,28 @@ void WM_jobs_callbacks(struct wmJob *,
void (*update)(void *),
void (*endjob)(void *));
+/**
+ * If job running, the same owner gave it a new job.
+ * if different owner starts existing startjob, it suspends itself
+ */
void WM_jobs_start(struct wmWindowManager *wm, struct wmJob *);
+/**
+ * Signal job(s) from this owner or callback to stop, timer is required to get handled.
+ */
void WM_jobs_stop(struct wmWindowManager *wm, const void *owner, void *startjob);
+/**
+ * Actually terminate thread and job timer.
+ */
void WM_jobs_kill(struct wmWindowManager *wm,
void *owner,
void (*)(void *, short int *, short int *, float *));
+/**
+ * Wait until every job ended.
+ */
void WM_jobs_kill_all(struct wmWindowManager *wm);
+/**
+ * Wait until every job ended, except for one owner (used in undo to keep screen job alive).
+ */
void WM_jobs_kill_all_except(struct wmWindowManager *wm, const void *owner);
void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type);
@@ -879,16 +1361,27 @@ bool WM_jobs_has_running(const struct wmWindowManager *wm);
void WM_job_main_thread_lock_acquire(struct wmJob *job);
void WM_job_main_thread_lock_release(struct wmJob *job);
-/* clipboard */
+/* Clipboard. */
+
+/**
+ * Return text from the clipboard.
+ *
+ * \note Caller needs to check for valid utf8 if this is a requirement.
+ */
char *WM_clipboard_text_get(bool selection, int *r_len);
+/**
+ * Convenience function for pasting to areas of Blender which don't support newlines.
+ */
char *WM_clipboard_text_get_firstline(bool selection, int *r_len);
void WM_clipboard_text_set(const char *buf, bool selection);
/* progress */
+
void WM_progress_set(struct wmWindow *win, float progress);
void WM_progress_clear(struct wmWindow *win);
/* Draw (for screenshot) */
+
void *WM_draw_cb_activate(struct wmWindow *win,
void (*draw)(const struct wmWindow *, void *),
void *customdata);
@@ -900,21 +1393,29 @@ void WM_draw_region_viewport_bind(struct ARegion *region);
void WM_draw_region_viewport_unbind(struct ARegion *region);
/* Region drawing */
+
void WM_draw_region_free(struct ARegion *region, bool hide);
struct GPUViewport *WM_draw_region_get_viewport(struct ARegion *region);
struct GPUViewport *WM_draw_region_get_bound_viewport(struct ARegion *region);
void WM_main_playanim(int argc, const char **argv);
-/* debugging only, convenience function to write on crash */
+/**
+ * Debugging only, convenience function to write on crash.
+ * Convenient to save a blend file from a debugger.
+ */
bool write_crash_blend(void);
-/* Lock the interface for any communication */
+/**
+ * Lock the interface for any communication.
+ */
void WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
void WM_event_tablet_data_default_set(struct wmTabletData *tablet_data);
-/* For testing only 'G_FLAG_EVENT_SIMULATE' */
+/**
+ * For testing only, see #G_FLAG_EVENT_SIMULATE.
+ */
struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add);
const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
@@ -923,28 +1424,60 @@ const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win);
void WM_window_status_area_tag_redraw(struct wmWindow *win);
+/**
+ * Similar to #BKE_screen_area_map_find_area_xy and related functions,
+ * use here since the area is stored in the window manager.
+ */
struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *screen);
bool WM_window_modal_keymap_status_draw(struct bContext *C,
struct wmWindow *win,
struct uiLayout *layout);
/* wm_event_query.c */
+
+/**
+ * For debugging only, getting inspecting events manually is tedious.
+ */
void WM_event_print(const struct wmEvent *event);
int WM_event_modifier_flag(const struct wmEvent *event);
+/**
+ * For modal callbacks, check configuration for how to interpret exit with tweaks.
+ */
bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
bool WM_event_is_last_mousemove(const struct wmEvent *event);
bool WM_event_is_mouse_drag(const struct wmEvent *event);
bool WM_event_is_mouse_drag_or_press(const wmEvent *event);
+/**
+ * Detect motion between selection (callers should only use this for selection picking),
+ * typically mouse press/click events.
+ *
+ * \param mval: Region relative coordinates, call with (-1, -1) resets the last cursor location.
+ * \returns True when there was motion since last called.
+ *
+ * NOTE(@campbellbarton): The logic used here isn't foolproof.
+ * It's possible that users move the cursor past #WM_EVENT_CURSOR_MOTION_THRESHOLD then back to
+ * a position within the threshold (between mouse clicks).
+ * In practice users never reported this since the threshold is very small (a few pixels).
+ * To prevent the unlikely case of values matching from another region,
+ * changing regions resets this value to (-1, -1).
+ */
bool WM_cursor_test_motion_and_update(const int mval[2]) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
int WM_event_drag_threshold(const struct wmEvent *event);
bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]);
-/* event map */
+/**
+ * Event map that takes preferences into account.
+ */
int WM_userdef_event_map(int kmitype);
+/**
+ * Use so we can check if 'wmEvent.type' is released in modal operators.
+ *
+ * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
+ */
int WM_userdef_event_type_from_keymap_type(int kmitype);
#ifdef WITH_INPUT_NDOF
@@ -961,6 +1494,10 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
bool WM_event_is_xr(const struct wmEvent *event);
#endif
+/**
+ * If this is a tablet event, return tablet pressure and set `*pen_flip`
+ * to 1 if the eraser tool is being used, 0 otherwise.
+ */
float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]);
bool WM_event_is_tablet(const struct wmEvent *event);
@@ -972,6 +1509,7 @@ bool WM_event_is_ime_switch(const struct wmEvent *event);
#endif
/* wm_tooltip.c */
+
typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C,
struct ARegion *region,
int *pass,
@@ -1001,6 +1539,7 @@ void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win);
double WM_tooltip_time_closed(void);
/* wm_utils.c */
+
struct wmGenericCallback *WM_generic_callback_steal(struct wmGenericCallback *callback);
void WM_generic_callback_free(struct wmGenericCallback *callback);
@@ -1010,7 +1549,15 @@ bool WM_region_use_viewport(struct ScrArea *area, struct ARegion *region);
#ifdef WITH_XR_OPENXR
/* wm_xr_session.c */
+
+/**
+ * Check if the XR-Session was triggered.
+ * If an error happened while trying to start a session, this returns false too.
+ */
bool WM_xr_session_exists(const wmXrData *xr);
+/**
+ * Check if the session is running, according to the OpenXR definition.
+ */
bool WM_xr_session_is_ready(const wmXrData *xr);
struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr);
struct ScrArea *WM_xr_session_area_get(const wmXrData *xr);
@@ -1043,8 +1590,10 @@ void WM_xr_session_state_navigation_reset(struct wmXrSessionState *state);
struct ARegionType *WM_xr_surface_controller_region_type_get(void);
/* wm_xr_actions.c */
+
/* XR action functions to be called pre-XR session start.
* NOTE: The "destroy" functions can also be called post-session start. */
+
bool WM_xr_action_set_create(wmXrData *xr, const char *action_set_name);
void WM_xr_action_set_destroy(wmXrData *xr, const char *action_set_name);
bool WM_xr_action_create(wmXrData *xr,
@@ -1078,7 +1627,9 @@ void WM_xr_action_binding_destroy(wmXrData *xr,
const char *action_name,
const char *profile_path);
-/* If action_set_name is NULL, then all action sets will be treated as active. */
+/**
+ * If action_set_name is NULL, then all action sets will be treated as active.
+ */
bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name);
bool WM_xr_controller_pose_actions_set(wmXrData *xr,
@@ -1086,7 +1637,9 @@ bool WM_xr_controller_pose_actions_set(wmXrData *xr,
const char *grip_action_name,
const char *aim_action_name);
-/* XR action functions to be called post-XR session start. */
+/**
+ * XR action functions to be called post-XR session start.
+ */
bool WM_xr_action_state_get(const wmXrData *xr,
const char *action_set_name,
const char *action_name,
@@ -1105,9 +1658,13 @@ void WM_xr_haptic_action_stop(wmXrData *xr,
const char *subaction_path);
/* wm_xr_actionmap.c */
+
XrActionMap *WM_xr_actionmap_new(struct wmXrRuntimeData *runtime,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action maps.
+ */
void WM_xr_actionmap_ensure_unique(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
XrActionMap *WM_xr_actionmap_add_copy(struct wmXrRuntimeData *runtime, XrActionMap *am_src);
bool WM_xr_actionmap_remove(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
@@ -1123,15 +1680,25 @@ void WM_xr_actionmap_selected_index_set(struct wmXrRuntimeData *runtime, short i
XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action map items.
+ */
void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami);
XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src);
bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami);
XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *name);
+/**
+ * Similar to #wm_xr_actionmap_item_properties_set()
+ * but checks for the #eXrActionType and #wmOperatorType having changed.
+ */
void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami);
XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami,
const char *name,
bool replace_existing);
+/**
+ * Ensure unique name among all action map bindings.
+ */
void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb);
XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami,
XrActionMapBinding *amb_src);
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 0633ffe55ea..4d1f2d979cb 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -55,6 +55,9 @@ void WM_keyconfig_update_operatortype(void);
void WM_keymap_clear(struct wmKeyMap *keymap);
+/**
+ * Always add item.
+ */
wmKeyMapItem *WM_keymap_add_item(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_item_copy(struct wmKeyMap *keymap, wmKeyMapItem *kmi_src);
@@ -91,16 +94,30 @@ bool WM_keymap_item_compare(const struct wmKeyMapItem *k1, const struct wmKeyMap
/* keymap_utils.c */
-/** Wrappers for #WM_keymap_add_item */
+/* Wrappers for #WM_keymap_add_item */
+
+/**
+ * Menu wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_menu(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Pie-menu wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_menu_pie(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Panel (popover) wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_panel(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/**
+ * Tool wrapper for #WM_keymap_add_item.
+ */
wmKeyMapItem *WM_keymap_add_tool(
struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier);
+/** Useful for mapping numbers to an enum. */
void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
const struct EnumPropertyItem *items,
const char *data_path,
@@ -110,6 +127,12 @@ void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
int keymodifier);
wmKeyMap *WM_keymap_guess_from_context(const struct bContext *C);
+
+/**
+ * Guess an appropriate key-map from the operator name.
+ *
+ * \note Needs to be kept up to date with Key-map and Operator naming.
+ */
wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname);
bool WM_keymap_uses_event_modifier(const wmKeyMap *keymap, const int event_modifier);
@@ -149,6 +172,9 @@ void WM_modalkeymap_assign(struct wmKeyMap *km, const char *opname);
/* Keymap Editor */
void WM_keymap_restore_to_default(struct wmKeyMap *keymap, struct wmWindowManager *wm);
+/**
+ * Properties can be NULL, otherwise the arg passed is used and ownership is given to the `kmi`.
+ */
void WM_keymap_item_properties_reset(struct wmKeyMapItem *kmi, struct IDProperty *properties);
void WM_keymap_item_restore_to_default(wmWindowManager *wm,
struct wmKeyMap *keymap,
@@ -168,6 +194,10 @@ int WM_keymap_item_raw_to_string(const short shift,
const bool compact,
char *result,
const int result_len);
+/**
+ * \param include_mask, exclude_mask:
+ * Event types to include/exclude when looking up keys (#eEventType_Mask).
+ */
wmKeyMapItem *WM_key_event_operator(const struct bContext *C,
const char *opname,
wmOperatorCallContext opcontext,
diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h
index eb89fca7b56..32b9cf1d7ba 100644
--- a/source/blender/windowmanager/WM_toolsystem.h
+++ b/source/blender/windowmanager/WM_toolsystem.h
@@ -69,6 +69,9 @@ void WM_toolsystem_unlink(struct bContext *C, struct WorkSpace *workspace, const
void WM_toolsystem_refresh(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
void WM_toolsystem_reinit(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
+/**
+ * Operate on all active tools.
+ */
void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace);
void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace);
void WM_toolsystem_reinit_all(struct bContext *C, struct wmWindow *win);
@@ -79,6 +82,12 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
const struct bToolRef_Runtime *tref_rt,
const char *idname);
+/**
+ * Sync the internal active state of a tool back into the tool system,
+ * this is needed for active brushes where the real active state is not stored in the tool system.
+ *
+ * \see #toolsystem_ref_link
+ */
void WM_toolsystem_ref_sync_from_context(struct Main *bmain,
struct WorkSpace *workspace,
struct bToolRef *tref);
@@ -98,8 +107,12 @@ void WM_toolsystem_update_from_context(struct bContext *C,
struct ViewLayer *view_layer,
struct ScrArea *area);
+/**
+ * For paint modes to support non-brush tools.
+ */
bool WM_toolsystem_active_tool_is_brush(const struct bContext *C);
+/** Follow #wmMsgNotifyFn spec. */
void WM_toolsystem_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
@@ -129,6 +142,14 @@ void WM_toolsystem_ref_properties_init_for_keymap(struct bToolRef *tref,
struct PointerRNA *src_ptr,
struct wmOperatorType *ot);
+/**
+ * Use to update the active tool (shown in the top bar) in the least disruptive way.
+ *
+ * This is a little involved since there may be multiple valid active tools
+ * depending on the mode and space type.
+ *
+ * Used when undoing since the active mode may have changed.
+ */
void WM_toolsystem_refresh_active(struct bContext *C);
void WM_toolsystem_refresh_screen_area(struct WorkSpace *workspace,
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index b8fe3786bde..3d56303a424 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -972,10 +972,10 @@ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata
#define WM_DRAG_DATASTACK 8
#define WM_DRAG_ASSET_CATALOG 9
-typedef enum wmDragFlags {
+typedef enum eWM_DragFlags {
WM_DRAG_NOP = 0,
WM_DRAG_FREE_DATA = 1,
-} wmDragFlags;
+} eWM_DragFlags;
/* NOTE: structs need not exported? */
@@ -1070,7 +1070,7 @@ typedef struct wmDrag {
wmDragActiveDropState drop_state;
- unsigned int flags;
+ eWM_DragFlags flags;
/** List of wmDragIDs, all are guaranteed to have the same ID type. */
ListBase ids;
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index c7a4b064d0e..497e4f6e5fc 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -61,19 +61,42 @@ extern "C" {
struct wmGizmo *WM_gizmo_new_ptr(const struct wmGizmoType *gzt,
struct wmGizmoGroup *gzgroup,
struct PointerRNA *properties);
+/**
+ * \param idname: Must be a valid gizmo type name,
+ * if you need to check it exists use #WM_gizmo_new_ptr
+ * because callers of this function don't NULL check the return value.
+ */
struct wmGizmo *WM_gizmo_new(const char *idname,
struct wmGizmoGroup *gzgroup,
struct PointerRNA *properties);
+/**
+ * \warning this doesn't check #wmGizmoMap (highlight, selection etc).
+ * Typical use is when freeing the windowing data,
+ * where caller can manage clearing selection, highlight... etc.
+ */
void WM_gizmo_free(struct wmGizmo *gz);
+/**
+ * Free \a gizmo and unlink from \a gizmolist.
+ * \a gizmolist is allowed to be NULL.
+ */
void WM_gizmo_unlink(ListBase *gizmolist,
struct wmGizmoMap *gzmap,
struct wmGizmo *gz,
struct bContext *C);
+/**
+ * Remove from selection array without running callbacks.
+ */
bool WM_gizmo_select_unlink(struct wmGizmoMap *gzmap, struct wmGizmo *gz);
bool WM_gizmo_select_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select);
bool WM_gizmo_highlight_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz);
+/**
+ * Special function to run from setup so gizmos start out interactive.
+ *
+ * We could do this when linking them,
+ * but this complicates things since the window update code needs to run first.
+ */
void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap,
struct bContext *C,
struct wmGizmo *gz,
@@ -87,17 +110,30 @@ struct PointerRNA *WM_gizmo_operator_set(struct wmGizmo *gz,
struct IDProperty *properties);
int WM_gizmo_operator_invoke(struct bContext *C, struct wmGizmo *gz, struct wmGizmoOpElem *gzop);
-/* callbacks */
+/* Callbacks. */
+
void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn);
void WM_gizmo_set_matrix_location(struct wmGizmo *gz, const float origin[3]);
+/**
+ * #wmGizmo.matrix utility, set the orientation by it's Z axis.
+ */
void WM_gizmo_set_matrix_rotation_from_z_axis(struct wmGizmo *gz, const float z_axis[3]);
+/**
+ * #wmGizmo.matrix utility, set the orientation by it's Y/Z axis.
+ */
void WM_gizmo_set_matrix_rotation_from_yz_axis(struct wmGizmo *gz,
const float y_axis[3],
const float z_axis[3]);
void WM_gizmo_set_matrix_offset_location(struct wmGizmo *gz, const float offset[3]);
+/**
+ * #wmGizmo.matrix_offset utility, set the orientation by it's Z axis.
+ */
void WM_gizmo_set_matrix_offset_rotation_from_z_axis(struct wmGizmo *gz, const float z_axis[3]);
+/**
+ * #wmGizmo.matrix_offset utility, set the orientation by it's Y/Z axis.
+ */
void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(struct wmGizmo *gz,
const float y_axis[3],
const float z_axis[3]);
@@ -128,14 +164,30 @@ void WM_gizmo_calc_matrix_final_no_offset(const struct wmGizmo *gz, float r_mat[
void WM_gizmo_calc_matrix_final(const struct wmGizmo *gz, float r_mat[4][4]);
-/* properties */
+/* Properties. */
+
void WM_gizmo_properties_create_ptr(struct PointerRNA *ptr, struct wmGizmoType *gzt);
void WM_gizmo_properties_create(struct PointerRNA *ptr, const char *gtstring);
+/**
+ * Similar to #WM_gizmo_properties_create
+ * except its uses ID properties used for key-maps and macros.
+ */
void WM_gizmo_properties_alloc(struct PointerRNA **ptr,
struct IDProperty **properties,
const char *gtstring);
void WM_gizmo_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+/**
+ * Set all props to their default.
+ *
+ * \param do_update: Only update un-initialized props.
+ *
+ * \note There's nothing specific to gizmos here.
+ * This could be made a general function.
+ */
bool WM_gizmo_properties_default(struct PointerRNA *ptr, const bool do_update);
+/**
+ * Remove all props without #PROP_SKIP_SAVE.
+ */
void WM_gizmo_properties_reset(struct wmGizmo *gz);
void WM_gizmo_properties_clear(struct PointerRNA *ptr);
void WM_gizmo_properties_free(struct PointerRNA *ptr);
@@ -146,7 +198,13 @@ void WM_gizmotype_append(void (*gtfunc)(struct wmGizmoType *));
void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void *userdata);
bool WM_gizmotype_remove(struct bContext *C, struct Main *bmain, const char *idname);
void WM_gizmotype_remove_ptr(struct bContext *C, struct Main *bmain, struct wmGizmoType *gzt);
+/**
+ * Free but don't remove from ghash.
+ */
void WM_gizmotype_free_ptr(struct wmGizmoType *gzt);
+/**
+ * Caller must free.
+ */
void WM_gizmotype_iter(struct GHashIterator *ghi);
/* wm_gizmo_group_type.c */
@@ -155,8 +213,15 @@ struct wmGizmoGroupType *WM_gizmogrouptype_append(void (*wtfunc)(struct wmGizmoG
struct wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(struct wmGizmoGroupType *,
void *),
void *userdata);
+/**
+ * Caller must free.
+ */
void WM_gizmogrouptype_iter(struct GHashIterator *ghi);
+/**
+ * Append and insert into a gizmo typemap.
+ * This is most common for C gizmos which are enabled by default.
+ */
struct wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(
struct wmGizmoMapType *gzmap_type, void (*wtfunc)(struct wmGizmoGroupType *));
@@ -167,6 +232,10 @@ void WM_gizmoconfig_update_tag_group_type_init(struct wmGizmoMapType *gzmap_type
struct wmGizmoGroupType *gzgt);
void WM_gizmoconfig_update_tag_group_type_remove(struct wmGizmoMapType *gzmap_type,
struct wmGizmoGroupType *gzgt);
+/**
+ * Run in case new types have been added (runs often, early exit where possible).
+ * Follows #WM_keyconfig_update conventions.
+ */
void WM_gizmoconfig_update(struct Main *bmain);
void WM_gizmoconfig_update_tag_group_remove(struct wmGizmoMap *gzmap);
@@ -222,7 +291,8 @@ bool WM_gizmo_target_property_float_range_get(const struct wmGizmo *gz,
int WM_gizmo_target_property_array_length(const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop);
-/* definitions */
+/* Definitions. */
+
const struct wmGizmoPropertyType *WM_gizmotype_target_property_find(const struct wmGizmoType *gzt,
const char *idname);
void WM_gizmotype_target_property_def(struct wmGizmoType *gzt,
@@ -230,14 +300,21 @@ void WM_gizmotype_target_property_def(struct wmGizmoType *gzt,
int data_type,
int array_length);
-/* utilities */
+/* Utilities. */
+
void WM_gizmo_do_msg_notify_tag_refresh(struct bContext *C,
struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValue *msg_val);
+/**
+ * Runs on the "prepare draw" pass, drawing the region clears.
+ */
void WM_gizmo_target_property_subscribe_all(struct wmGizmo *gz,
struct wmMsgBus *mbus,
struct ARegion *region);
+/**
+ * Auto-key function if auto-key is enabled.
+ */
void WM_gizmo_target_property_anim_autokey(struct bContext *C,
const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop);
@@ -256,6 +333,7 @@ struct wmKeyMap *WM_gizmogroup_setup_keymap_generic_maybe_drag(const struct wmGi
struct wmKeyConfig *kc);
/* Utility functions (not callbacks). */
+
struct wmKeyMap *WM_gizmo_keymap_generic_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic(struct wmWindowManager *wm);
@@ -268,19 +346,29 @@ struct wmKeyMap *WM_gizmo_keymap_generic_drag(struct wmWindowManager *wm);
struct wmKeyMap *WM_gizmo_keymap_generic_click_drag_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic_click_drag(struct wmWindowManager *wm);
+/**
+ * Drag or press depending on preference.
+ */
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag_with_keyconfig(struct wmKeyConfig *kc);
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag(struct wmWindowManager *wm);
void WM_gizmogroup_ensure_init(const struct bContext *C, struct wmGizmoGroup *gzgroup);
/* Sort utilities for use with 'BLI_listbase_sort'. */
+
int WM_gizmo_cmp_temp_fl(const void *gz_a_ptr, const void *gz_b_ptr);
int WM_gizmo_cmp_temp_fl_reverse(const void *gz_a_ptr, const void *gz_b_ptr);
/* -------------------------------------------------------------------- */
/* wmGizmoMap */
+/**
+ * Creates a gizmo-map with all registered gizmos for that type
+ */
struct wmGizmoMap *WM_gizmomap_new_from_type(const struct wmGizmoMapType_Params *gzmap_params);
+/**
+ * Re-create the gizmos (use when changing theme settings).
+ */
void WM_gizmomap_reinit(struct wmGizmoMap *gzmap);
const struct ListBase *WM_gizmomap_group_list(struct wmGizmoMap *gzmap);
struct wmGizmoGroup *WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idname);
@@ -298,6 +386,12 @@ void WM_gizmomap_draw(struct wmGizmoMap *gzmap,
const struct bContext *C,
const eWM_GizmoFlagMapDrawStep drawstep);
void WM_gizmomap_add_handlers(struct ARegion *region, struct wmGizmoMap *gzmap);
+/**
+ * Select/Deselect all selectable gizmos in \a gzmap.
+ * \return if selection has changed.
+ *
+ * TODO: select all by type.
+ */
bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, const int action);
bool WM_gizmomap_cursor_set(const struct wmGizmoMap *gzmap, struct wmWindow *win);
void WM_gizmomap_message_subscribe(const struct bContext *C,
@@ -305,6 +399,9 @@ void WM_gizmomap_message_subscribe(const struct bContext *C,
struct ARegion *region,
struct wmMsgBus *mbus);
bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap);
+/**
+ * \note We could use a callback to define bounds, for now just use matrix location.
+ */
bool WM_gizmomap_minmax(const struct wmGizmoMap *gzmap,
bool use_hidden,
bool use_select,
@@ -327,6 +424,10 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz
const char *idname);
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find_ptr(struct wmGizmoMapType *gzmap_type,
const struct wmGizmoGroupType *gzgt);
+/**
+ * Use this for registering gizmos on startup.
+ * For runtime, use #WM_gizmomaptype_group_link_runtime.
+ */
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(struct wmGizmoMapType *gzmap_type,
const char *idname);
struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link_ptr(struct wmGizmoMapType *gzmap_type,
@@ -345,6 +446,9 @@ void WM_gizmomaptype_group_unlink(struct bContext *C,
struct wmGizmoMapType *gzmap_type,
const struct wmGizmoGroupType *gzgt);
+/**
+ * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free.
+ */
void WM_gizmomaptype_group_free(struct wmGizmoGroupTypeRef *gzgt);
/* -------------------------------------------------------------------- */
@@ -362,6 +466,9 @@ bool WM_gizmo_group_type_ensure_ptr_ex(struct wmGizmoGroupType *gzgt,
bool WM_gizmo_group_type_ensure_ptr(struct wmGizmoGroupType *gzgt);
bool WM_gizmo_group_type_ensure(const char *idname);
+/**
+ * Call #WM_gizmo_group_type_free_ptr after to remove & free.
+ */
void WM_gizmo_group_type_remove_ptr_ex(struct Main *bmain,
struct wmGizmoGroupType *gzgt,
struct wmGizmoMapType *gzmap_type);
@@ -380,7 +487,9 @@ void WM_gizmo_group_unlink_delayed_ptr_from_space(struct wmGizmoGroupType *gzgt,
void WM_gizmo_group_type_free_ptr(wmGizmoGroupType *gzgt);
bool WM_gizmo_group_type_free(const char *idname);
-/* Has the result of unlinking and linking (re-initializes gizmo's). */
+/**
+ * Has the result of unlinking and linking (re-initializes gizmo's).
+ */
void WM_gizmo_group_type_reinit_ptr_ex(struct Main *bmain,
struct wmGizmoGroupType *gzgt,
struct wmGizmoMapType *gzmap_type);
@@ -388,6 +497,7 @@ void WM_gizmo_group_type_reinit_ptr(struct Main *bmain, struct wmGizmoGroupType
void WM_gizmo_group_type_reinit(struct Main *bmain, const char *idname);
/* Utilities */
+
bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapDrawStep step);
void WM_gizmo_group_remove_by_tool(struct bContext *C,
@@ -398,6 +508,7 @@ void WM_gizmo_group_remove_by_tool(struct bContext *C,
void WM_gizmo_group_tag_remove(struct wmGizmoGroup *gzgroup);
/* Wrap Group Type Callbacks. */
+
bool WM_gizmo_group_type_poll(const struct bContext *C, const struct wmGizmoGroupType *gzgt);
void WM_gizmo_group_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
index cfedd67b2f0..d4f11c79d46 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -106,11 +106,6 @@ wmGizmo *WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, Pointer
return gz;
}
-/**
- * \param idname: Must be a valid gizmo type name,
- * if you need to check it exists use #WM_gizmo_new_ptr
- * because callers of this function don't NULL check the return value.
- */
wmGizmo *WM_gizmo_new(const char *idname, wmGizmoGroup *gzgroup, PointerRNA *properties)
{
const wmGizmoType *gzt = WM_gizmotype_find(idname, false);
@@ -143,11 +138,6 @@ static void wm_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
wm_gizmogroup_gizmo_register(gzgroup, gz);
}
-/**
- * \warning this doesn't check #wmGizmoMap (highlight, selection etc).
- * Typical use is when freeing the windowing data,
- * where caller can manage clearing selection, highlight... etc.
- */
void WM_gizmo_free(wmGizmo *gz)
{
if (gz->type->free != NULL) {
@@ -187,10 +177,6 @@ void WM_gizmo_free(wmGizmo *gz)
MEM_freeN(gz);
}
-/**
- * Free \a gizmo and unlink from \a gizmolist.
- * \a gizmolist is allowed to be NULL.
- */
void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C)
{
if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
@@ -300,9 +286,6 @@ static void wm_gizmo_set_matrix_rotation_from_yz_axis__internal(float matrix[4][
normalize_v3(matrix[0]);
}
-/**
- * wmGizmo.matrix utils.
- */
void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_basis, z_axis);
@@ -318,9 +301,6 @@ void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
copy_v3_v3(gz->matrix_basis[3], origin);
}
-/**
- * wmGizmo.matrix_offset utils.
- */
void WM_gizmo_set_matrix_offset_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_offset, z_axis);
@@ -388,12 +368,7 @@ void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn)
/** \} */
/* -------------------------------------------------------------------- */
-/**
- * Add/Remove \a gizmo to selection.
- * Reallocates memory for selected gizmos so better not call for selecting multiple ones.
- *
- * \return if the selection has changed.
- */
+
bool wm_gizmo_select_set_ex(
wmGizmoMap *gzmap, wmGizmo *gz, bool select, bool use_array, bool use_callback)
{
@@ -429,7 +404,6 @@ bool wm_gizmo_select_set_ex(
return changed;
}
-/* Remove from selection array without running callbacks. */
bool WM_gizmo_select_unlink(wmGizmoMap *gzmap, wmGizmo *gz)
{
return wm_gizmo_select_set_ex(gzmap, gz, false, true, false);
@@ -454,12 +428,6 @@ bool wm_gizmo_select_and_highlight(bContext *C, wmGizmoMap *gzmap, wmGizmo *gz)
return false;
}
-/**
- * Special function to run from setup so gizmos start out interactive.
- *
- * We could do this when linking them,
- * but this complicates things since the window update code needs to run first.
- */
void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap,
struct bContext *C,
struct wmGizmo *gz,
@@ -634,8 +602,6 @@ void WM_gizmo_properties_create(PointerRNA *ptr, const char *gtstring)
}
}
-/* similar to the function above except its uses ID properties
- * used for keymaps and macros */
void WM_gizmo_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *gtstring)
{
if (*properties == NULL) {
@@ -680,14 +646,6 @@ void WM_gizmo_properties_sanitize(PointerRNA *ptr, const bool no_context)
RNA_STRUCT_END;
}
-/**
- * Set all props to their default.
- *
- * \param do_update: Only update un-initialized props.
- *
- * \note There's nothing specific to gizmos here.
- * This could be made a general function.
- */
bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
{
bool changed = false;
@@ -715,7 +673,6 @@ bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
return changed;
}
-/* remove all props without PROP_SKIP_SAVE */
void WM_gizmo_properties_reset(wmGizmo *gz)
{
if (gz->ptr->data) {
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index b6d759eb95f..6f10e4f3f0d 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -63,9 +63,6 @@
/** \name wmGizmoGroup
* \{ */
-/**
- * Create a new gizmo-group from \a gzgt.
- */
wmGizmoGroup *wm_gizmogroup_new_from_type(wmGizmoMap *gzmap, wmGizmoGroupType *gzgt)
{
wmGizmoGroup *gzgroup = MEM_callocN(sizeof(*gzgroup), "gizmo-group");
@@ -148,9 +145,6 @@ void WM_gizmo_group_tag_remove(wmGizmoGroup *gzgroup)
}
}
-/**
- * Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
- */
void wm_gizmogroup_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
{
BLI_assert(BLI_findindex(&gzgroup->gizmos, gz) == -1);
@@ -234,10 +228,6 @@ wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
return NULL;
}
-/**
- * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase.
- * Added items need freeing!
- */
void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm,
const wmGizmoGroup *gzgroup,
const int event_modifier,
@@ -345,10 +335,9 @@ bool wm_gizmogroup_is_any_selected(const wmGizmoGroup *gzgroup)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Gizmo operators
+/** \name Gizmo Operators
*
* Basic operators for gizmo interaction with user configurable keymaps.
- *
* \{ */
static int gizmo_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -641,8 +630,6 @@ void GIZMOGROUP_OT_gizmo_tweak(wmOperatorType *ot)
#endif
}
-/** \} */
-
wmKeyMap *wm_gizmogroup_tweak_modal_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
@@ -774,11 +761,12 @@ wmKeyMap *WM_gizmogroup_setup_keymap_generic_select(const wmGizmoGroupType *UNUS
return WM_gizmogroup_keymap_template_select_ex(kc, "Generic Gizmo Select", &params);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name wmGizmo (Key-map access)
*
* Key config version so these can be called from #wmGizmoGroupFnSetupKeymap.
- *
* \{ */
struct wmKeyMap *WM_gizmo_keymap_generic_with_keyconfig(wmKeyConfig *kc)
@@ -821,7 +809,6 @@ struct wmKeyMap *WM_gizmo_keymap_generic_click_drag(wmWindowManager *wm)
return WM_gizmo_keymap_generic_click_drag_with_keyconfig(wm->defaultconf);
}
-/** Drag or press depending on preference. */
struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag_with_keyconfig(wmKeyConfig *kc)
{
const char *idname = "Generic Gizmo Maybe Drag";
@@ -862,10 +849,6 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz
return NULL;
}
-/**
- * Use this for registering gizmos on startup.
- * For runtime, use #WM_gizmomaptype_group_link_runtime.
- */
wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(wmGizmoMapType *gzmap_type, const char *idname)
{
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
@@ -939,9 +922,6 @@ wmGizmoGroup *WM_gizmomaptype_group_init_runtime_with_region(wmGizmoMapType *gzm
return gzgroup;
}
-/**
- * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free.
- */
void WM_gizmomaptype_group_free(wmGizmoGroupTypeRef *gzgt_ref)
{
MEM_freeN(gzgt_ref);
@@ -1017,7 +997,6 @@ void wm_gizmogrouptype_setup_keymap(wmGizmoGroupType *gzgt, wmKeyConfig *keyconf
* but for general purpose API this is too detailed & annoying.
*
* \note We may want to return a value if there is nothing to remove.
- *
* \{ */
void WM_gizmo_group_type_add_ptr_ex(wmGizmoGroupType *gzgt, wmGizmoMapType *gzmap_type)
@@ -1059,9 +1038,6 @@ bool WM_gizmo_group_type_ensure(const char *idname)
return WM_gizmo_group_type_ensure_ptr(gzgt);
}
-/**
- * Call #WM_gizmo_group_type_free_ptr after to remove & free.
- */
void WM_gizmo_group_type_remove_ptr_ex(struct Main *bmain,
wmGizmoGroupType *gzgt,
wmGizmoMapType *gzmap_type)
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
index 6a793d52f74..0a36068bb21 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
@@ -71,7 +71,6 @@ wmGizmoGroupType *WM_gizmogrouptype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_gizmogrouptype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_gizmogrouptype_hash);
@@ -127,10 +126,6 @@ wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(struct wmGizmoGrou
return gzgt;
}
-/**
- * Append and insert into a gizmo typemap.
- * This is most common for C gizmos which are enabled by default.
- */
wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(wmGizmoMapType *gzmap_type,
void (*wtfunc)(struct wmGizmoGroupType *))
{
@@ -190,7 +185,6 @@ void wm_gizmogrouptype_free(void)
global_gizmogrouptype_hash = NULL;
}
-/* called on initialize WM_init() */
void wm_gizmogrouptype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
index dd2db209771..b6912d79076 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
@@ -29,6 +29,12 @@ struct wmKeyConfig;
/* -------------------------------------------------------------------- */
/* wmGizmo */
+/**
+ * Add/Remove \a gizmo to selection.
+ * Reallocates memory for selected gizmos so better not call for selecting multiple ones.
+ *
+ * \return if the selection has changed.
+ */
bool wm_gizmo_select_set_ex(
struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select, bool use_array, bool use_callback);
bool wm_gizmo_select_and_highlight(bContext *C, struct wmGizmoMap *gzmap, struct wmGizmo *gz);
@@ -54,9 +60,15 @@ enum {
TWEAK_MODAL_SNAP_OFF,
};
+/**
+ * Create a new gizmo-group from \a gzgt.
+ */
struct wmGizmoGroup *wm_gizmogroup_new_from_type(struct wmGizmoMap *gzmap,
struct wmGizmoGroupType *gzgt);
void wm_gizmogroup_free(bContext *C, struct wmGizmoGroup *gzgroup);
+/**
+ * Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
+ */
void wm_gizmogroup_gizmo_register(struct wmGizmoGroup *gzgroup, struct wmGizmo *gz);
struct wmGizmoGroup *wm_gizmogroup_find_by_type(const struct wmGizmoMap *gzmap,
const struct wmGizmoGroupType *gzgt);
@@ -66,6 +78,10 @@ struct wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
const int event_modifier,
const int mval[2],
int *r_part);
+/**
+ * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase.
+ * Added items need freeing!
+ */
void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm,
const struct wmGizmoGroup *gzgroup,
const int event_modifier,
@@ -137,6 +153,10 @@ struct wmGizmoMapType {
};
void wm_gizmomap_select_array_clear(struct wmGizmoMap *gzmap);
+/**
+ * Deselect all selected gizmos in \a gzmap.
+ * \return if selection has changed.
+ */
bool wm_gizmomap_deselect_all(struct wmGizmoMap *gzmap);
void wm_gizmomap_select_array_shrink(struct wmGizmoMap *gzmap, int len_subtract);
void wm_gizmomap_select_array_push_back(struct wmGizmoMap *gzmap, wmGizmo *gz);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 6f952bc9526..d3e682f1490 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -176,9 +176,6 @@ static wmGizmoMap *wm_gizmomap_new_from_type_ex(struct wmGizmoMapType *gzmap_typ
return gzmap;
}
-/**
- * Creates a gizmo-map with all registered gizmos for that type
- */
wmGizmoMap *WM_gizmomap_new_from_type(const struct wmGizmoMapType_Params *gzmap_params)
{
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(gzmap_params);
@@ -207,7 +204,6 @@ void wm_gizmomap_remove(wmGizmoMap *gzmap)
MEM_freeN(gzmap);
}
-/** Re-create the gizmos (use when changing theme settings). */
void WM_gizmomap_reinit(wmGizmoMap *gzmap)
{
wmGizmoMapType *gzmap_type = gzmap->type;
@@ -246,9 +242,6 @@ bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
return gzmap->gzmap_context.select.len != 0;
}
-/**
- * \note We could use a callback to define bounds, for now just use matrix location.
- */
bool WM_gizmomap_minmax(const wmGizmoMap *gzmap,
bool UNUSED(use_hidden),
bool use_select,
@@ -713,10 +706,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
return result;
}
-/**
- * Try to find a gizmo under the mouse position. 2D intersections have priority over
- * 3D ones (could check for smallest screen-space distance but not needed right now).
- */
wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
bContext *C,
const wmEvent *event,
@@ -843,10 +832,6 @@ void wm_gizmomaps_handled_modal_update(bContext *C, wmEvent *event, wmEventHandl
CTX_wm_region_set(C, region);
}
-/**
- * Deselect all selected gizmos in \a gzmap.
- * \return if selection has changed.
- */
bool wm_gizmomap_deselect_all(wmGizmoMap *gzmap)
{
wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
@@ -903,12 +888,6 @@ static bool wm_gizmomap_select_all_intern(bContext *C, wmGizmoMap *gzmap)
return changed;
}
-/**
- * Select/Deselect all selectable gizmos in \a gzmap.
- * \return if selection has changed.
- *
- * TODO: select all by type.
- */
bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action)
{
bool changed = false;
@@ -932,10 +911,6 @@ bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action)
return changed;
}
-/**
- * Prepare context for gizmo handling (but only if area/region is
- * part of screen). Version of #wm_handler_op_context for gizmos.
- */
void wm_gizmomap_handler_context_op(bContext *C, wmEventHandler_Op *handler)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1037,9 +1012,6 @@ wmGizmo *wm_gizmomap_highlight_get(wmGizmoMap *gzmap)
return gzmap->gzmap_context.highlight;
}
-/**
- * Caller should call exit when (enable == False).
- */
void wm_gizmomap_modal_set(
wmGizmoMap *gzmap, bContext *C, wmGizmo *gz, const wmEvent *event, bool enable)
{
@@ -1247,9 +1219,6 @@ void wm_gizmomaptypes_free(void)
}
}
-/**
- * Initialize keymaps for all existing gizmo-groups
- */
void wm_gizmos_keymap(wmKeyConfig *keyconf)
{
LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) {
@@ -1293,10 +1262,6 @@ void WM_gizmoconfig_update_tag_group_remove(wmGizmoMap *gzmap)
wm_gzmap_type_update_flag |= WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE;
}
-/**
- * Run in case new types have been added (runs often, early exit where possible).
- * Follows #WM_keyconfig_update conventions.
- */
void WM_gizmoconfig_update(struct Main *bmain)
{
if (G.background) {
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
index 63e833d73c3..57555fb5416 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -319,10 +319,6 @@ void WM_gizmo_do_msg_notify_tag_refresh(bContext *UNUSED(C),
WM_gizmomap_tag_refresh(gzmap);
}
-/**
- * Runs on the "prepare draw" pass,
- * drawing the region clears.
- */
void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus, ARegion *region)
{
if (gz->type->target_property_defs_len) {
@@ -355,9 +351,6 @@ void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus,
}
}
-/**
- * Auto-key function if auto-key is enabled.
- */
void WM_gizmo_target_property_anim_autokey(bContext *C,
const wmGizmo *UNUSED(gz),
wmGizmoProperty *gz_prop)
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
index 1523246d08b..602100a624e 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
@@ -78,7 +78,6 @@ const wmGizmoType *WM_gizmotype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_gizmotype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_gizmotype_hash);
@@ -118,9 +117,6 @@ void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void
wm_gizmotype_append__end(mt);
}
-/**
- * Free but don't remove from ghash.
- */
void WM_gizmotype_free_ptr(wmGizmoType *gzt)
{
if (gzt->rna_ext.srna) { /* python gizmo, allocs own string */
@@ -195,7 +191,6 @@ void wm_gizmotype_free(void)
global_gizmotype_hash = NULL;
}
-/* called on initialize WM_init() */
void wm_gizmotype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
index 18b3f40aba6..0612ba97db0 100644
--- a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
+++ b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
@@ -40,37 +40,63 @@ extern "C" {
#endif
/* -------------------------------------------------------------------- */
-/* wmGizmo */
+/** \name #wmGizmo
+ * \{ */
/* wm_gizmo_type.c, for init/exit */
+
void wm_gizmotype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_gizmotype_init(void);
/* wm_gizmogroup_type.c, for init/exit */
+
void wm_gizmogrouptype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_gizmogrouptype_init(void);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoGroup */
+/** \name #wmGizmoGroup
+ * \{ */
void GIZMOGROUP_OT_gizmo_select(struct wmOperatorType *ot);
void GIZMOGROUP_OT_gizmo_tweak(struct wmOperatorType *ot);
bool wm_gizmogroup_is_any_selected(const struct wmGizmoGroup *gzgroup);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoMap */
+/** \name #wmGizmoMap
+ * \{ */
void wm_gizmomap_remove(struct wmGizmoMap *gzmap);
+/**
+ * Initialize key-maps for all existing gizmo-groups
+ */
void wm_gizmos_keymap(struct wmKeyConfig *keyconf);
void wm_gizmomaps_handled_modal_update(bContext *C,
struct wmEvent *event,
struct wmEventHandler_Op *handler);
+/**
+ * Prepare context for gizmo handling (but only if area/region is
+ * part of screen). Version of #wm_handler_op_context for gizmos.
+ */
void wm_gizmomap_handler_context_op(bContext *C, struct wmEventHandler_Op *handler);
void wm_gizmomap_handler_context_gizmo(bContext *C, struct wmEventHandler_Gizmo *handler);
+/**
+ * Try to find a gizmo under the mouse position. 2D intersections have priority over
+ * 3D ones (could check for smallest screen-space distance but not needed right now).
+ */
struct wmGizmo *wm_gizmomap_highlight_find(struct wmGizmoMap *gzmap,
bContext *C,
const struct wmEvent *event,
@@ -80,6 +106,9 @@ bool wm_gizmomap_highlight_set(struct wmGizmoMap *gzmap,
struct wmGizmo *gz,
int part);
struct wmGizmo *wm_gizmomap_highlight_get(struct wmGizmoMap *gzmap);
+/**
+ * Caller should call exit when (enable == False).
+ */
void wm_gizmomap_modal_set(struct wmGizmoMap *gzmap,
bContext *C,
struct wmGizmo *gz,
@@ -90,11 +119,16 @@ struct wmGizmo *wm_gizmomap_modal_get(struct wmGizmoMap *gzmap);
struct wmGizmo **wm_gizmomap_selected_get(wmGizmoMap *gzmap, int *r_selected_len);
struct ListBase *wm_gizmomap_groups_get(wmGizmoMap *gzmap);
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* wmGizmoMapType */
+/** \name #wmGizmoMapType
+ * \{ */
void wm_gizmomaptypes_free(void);
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 47ee296823b..40f8da63e11 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -272,6 +272,7 @@ IDTypeInfo IDType_ID_WM = {
.name_plural = "window_managers",
.translation_context = BLT_I18NCONTEXT_ID_WINDOWMANAGER,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA,
+ .asset_type_info = NULL,
.init_data = NULL,
.copy_data = NULL,
@@ -279,6 +280,7 @@ IDTypeInfo IDType_ID_WM = {
.make_local = NULL,
.foreach_id = window_manager_foreach_id,
.foreach_cache = NULL,
+ .foreach_path = NULL,
.owner_get = NULL,
.blend_write = window_manager_blend_write,
@@ -339,13 +341,6 @@ void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
}
}
-/**
- * Use with extreme care!,
- * properties, custom-data etc - must be compatible.
- *
- * \param op: Operator to assign the type to.
- * \param ot: Operator type to assign.
- */
void WM_operator_type_set(wmOperator *op, wmOperatorType *ot)
{
/* Not supported for Python. */
@@ -375,8 +370,6 @@ static void wm_reports_free(wmWindowManager *wm)
WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
}
-/* All operations get registered in the windowmanager here. */
-/* Called on event handling by event_system.c. */
void wm_operator_register(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -413,10 +406,6 @@ void WM_operator_stack_clear(wmWindowManager *wm)
WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
}
-/**
- * This function is needed in the case when an addon id disabled
- * while a modal operator it defined is running.
- */
void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -549,7 +538,6 @@ void wm_clear_default_size(bContext *C)
}
}
-/* On startup, it adds all data, for matching. */
void wm_add_default(Main *bmain, bContext *C)
{
wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0);
@@ -571,7 +559,6 @@ void wm_add_default(Main *bmain, bContext *C)
wm_window_make_drawable(wm, win);
}
-/* Context is allowed to be NULL, do not free wm itself (lib_id.c). */
void wm_close_and_free(bContext *C, wmWindowManager *wm)
{
if (wm->autosavetimer) {
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 9c020b16234..74ec2bcd41f 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -222,7 +222,6 @@ void WM_cursor_modal_restore(wmWindow *win)
win->lastcursor = 0;
}
-/* to allow usage all over, we do entire WM */
void WM_cursor_wait(bool val)
{
if (!G.background) {
@@ -240,9 +239,6 @@ void WM_cursor_wait(bool val)
}
}
-/**
- * \param bounds: can be NULL
- */
void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
{
/* Only grab cursor when not running debug.
@@ -307,9 +303,10 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
WM_cursor_warp(win, cx + x, cy + y);
}
-/* give it a modal keymap one day? */
bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
{
+ /* TODO: give it a modal keymap? Hard coded for now */
+
if (win && event->val == KM_PRESS) {
/* Must move at least this much to avoid rounding in WM_cursor_warp. */
float fac = GHOST_GetNativePixelSize(win->ghostwin);
@@ -334,7 +331,6 @@ bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
return 0;
}
-/* after this you can call restore too */
void WM_cursor_time(wmWindow *win, int nr)
{
/* 10 8x8 digits */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index bc87347b2f3..e1017c4236e 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -89,7 +89,6 @@ typedef struct wmDropBoxMap {
} wmDropBoxMap;
-/* spaceid/regionid is zero for window drop maps */
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
{
LISTBASE_FOREACH (wmDropBoxMap *, dm, &dropboxes) {
@@ -153,7 +152,6 @@ void wm_dropbox_free(void)
/* *********************************** */
-/* note that the pointer should be valid allocated and not on stack */
wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags)
{
@@ -208,11 +206,6 @@ wmDrag *WM_event_start_drag(
return drag;
}
-/**
- * Additional work to cleanly end dragging. Additional because this doesn't actually remove the
- * drag items. Should be called whenever dragging is stopped (successful or not, also when
- * canceled).
- */
void wm_drags_exit(wmWindowManager *wm, wmWindow *win)
{
bool any_active = false;
@@ -403,7 +396,6 @@ void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop)
wm_drags_exit(CTX_wm_manager(C), CTX_wm_window(C));
}
-/* called in inner handler loop, region context */
void wm_drags_check_ops(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -424,11 +416,6 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event)
}
}
-/**
- * The operator of a dropbox should always be executed in the context determined by the mouse
- * coordinates. The dropbox poll should check the context area and region as needed.
- * So this always returns #WM_OP_INVOKE_DEFAULT.
- */
wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *UNUSED(drop))
{
return WM_OP_INVOKE_DEFAULT;
@@ -484,17 +471,11 @@ ID *WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode)
return WM_drag_get_local_ID(lb->first, idcode);
}
-/**
- * Check if the drag data is either a local ID or an external ID asset of type \a idcode.
- */
bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
{
return WM_drag_get_local_ID(drag, idcode) || WM_drag_get_asset_data(drag, idcode);
}
-/**
- * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
- */
wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset,
AssetMetaData *metadata,
const char *path,
@@ -542,9 +523,6 @@ struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode
return NULL;
}
-/**
- * \param flag_extra: Additional linking flags (from #eFileSel_Params_Flag).
- */
ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, const int flag_extra)
{
/* Only support passing in limited flags. */
@@ -603,15 +581,6 @@ bool WM_drag_asset_will_import_linked(const wmDrag *drag)
return asset_drag->import_type == FILE_ASSET_IMPORT_LINK;
}
-/**
- * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
- * that depending on what was chosen by the drag-box (currently append only in fact).
- *
- * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset
- * import is rolled back if the drop operator fails.
- *
- * \param flag: #eFileSel_Params_Flag passed to linking code.
- */
ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
{
if (!ELEM(drag->type, WM_DRAG_ASSET, WM_DRAG_ID)) {
@@ -631,14 +600,6 @@ ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
return WM_drag_asset_id_import(asset_drag, 0);
}
-/**
- * \brief Free asset ID imported for canceled drop.
- *
- * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()`
- * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop
- * operator cancels.
- * This is for use as #wmDropBox.cancel() callback.
- */
void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *drop)
{
if (drag->type != WM_DRAG_ASSET) {
@@ -673,9 +634,6 @@ wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const wmDrag *drag)
return drag->poin;
}
-/**
- * \note: Does not store \a asset in any way, so it's fine to pass a temporary.
- */
void WM_drag_add_asset_list_item(
wmDrag *drag,
/* Context only needed for the hack in #ED_asset_handle_get_full_library_path(). */
@@ -912,7 +870,6 @@ void WM_drag_draw_default_fn(bContext *C, wmWindow *win, wmDrag *drag, const int
wm_drag_draw_default(C, win, drag, xy);
}
-/* Called in #wm_draw_window_onscreen. */
void wm_drags_draw(bContext *C, wmWindow *win)
{
int xy[2];
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index d8d57a9370c..ab9de6ce4d4 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -148,6 +148,7 @@ static void wm_region_draw_overlay(bContext *C, ScrArea *area, ARegion *region)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index ef733837bf7..22cd68ddbd7 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -71,7 +71,6 @@ static void event_ids_from_type_and_value(const short type,
}
}
-/* for debugging only, getting inspecting events manually is tedious */
void WM_event_print(const wmEvent *event)
{
if (event) {
@@ -218,7 +217,6 @@ bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask ma
/** \name Event Motion Queries
* \{ */
-/* for modal callbacks, check configuration for how to interpret exit with tweaks. */
bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
{
/* if the release-confirm userpref setting is enabled,
@@ -276,20 +274,6 @@ bool WM_event_is_mouse_drag_or_press(const wmEvent *event)
(ISMOUSE_BUTTON(event->type) && (event->val == KM_PRESS));
}
-/**
- * Detect motion between selection (callers should only use this for selection picking),
- * typically mouse press/click events.
- *
- * \param mval: Region relative coordinates, call with (-1, -1) resets the last cursor location.
- * \returns True when there was motion since last called.
- *
- * NOTE(@campbellbarton): The logic used here isn't foolproof.
- * It's possible that users move the cursor past #WM_EVENT_CURSOR_MOTION_THRESHOLD then back to
- * a position within the threshold (between mouse clicks).
- * In practice users never reported this since the threshold is very small (a few pixels).
- * To prevent the unlikely case of values matching from another region,
- * changing regions resets this value to (-1, -1).
- */
bool WM_cursor_test_motion_and_update(const int mval[2])
{
static int mval_prev[2] = {-1, -1};
@@ -360,11 +344,6 @@ int WM_userdef_event_map(int kmitype)
return kmitype;
}
-/**
- * Use so we can check if 'wmEvent.type' is released in modal operators.
- *
- * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar.
- */
int WM_userdef_event_type_from_keymap_type(int kmitype)
{
switch (kmitype) {
@@ -447,7 +426,6 @@ bool WM_event_is_xr(const struct wmEvent *event)
/** \name Event Tablet Input Access
* \{ */
-/* applies the global tablet pressure correction curve */
float wm_pressure_curve(float pressure)
{
if (U.pressure_threshold_max != 0.0f) {
@@ -463,8 +441,6 @@ float wm_pressure_curve(float pressure)
return pressure;
}
-/* if this is a tablet event, return tablet pressure and set *pen_flip
- * to 1 if the eraser tool is being used, 0 otherwise */
float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
{
if (tilt) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index f51c8c48c48..1b6df9fb0db 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -64,6 +64,7 @@
#include "ED_asset.h"
#include "ED_fileselect.h"
#include "ED_info.h"
+#include "ED_render.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -83,6 +84,7 @@
#include "wm.h"
#include "wm_event_system.h"
#include "wm_event_types.h"
+#include "wm_surface.h"
#include "wm_window.h"
#include "DEG_depsgraph.h"
@@ -287,9 +289,6 @@ void WM_main_add_notifier(unsigned int type, void *reference)
note->reference = reference;
}
-/**
- * Clear notifiers by reference, Used so listeners don't act on freed data.
- */
void WM_main_remove_notifier_reference(const void *reference)
{
Main *bmain = G_MAIN;
@@ -384,13 +383,10 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
DEG_make_active(depsgraph);
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
+
+ wm_surfaces_do_depsgraph(C);
}
-/**
- * Was part of #wm_event_do_notifiers,
- * split out so it can be called once before entering the #WM_main loop.
- * This ensures operators don't run before the UI and depsgraph are initialized.
- */
void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -427,7 +423,6 @@ static void wm_event_execute_timers(bContext *C)
CTX_wm_window_set(C, NULL);
}
-/* Called in mainloop. */
void wm_event_do_notifiers(bContext *C)
{
/* Run the timer before assigning 'wm' in the unlikely case a timer loads a file, see T80028. */
@@ -457,6 +452,9 @@ void wm_event_do_notifiers(bContext *C)
else if (note->data == ND_DATACHANGED) {
wm_window_title(wm, win);
}
+ else if (note->data == ND_UNDO) {
+ ED_preview_restart_queue_work(C);
+ }
}
if (note->window == win) {
if (note->category == NC_SCREEN) {
@@ -752,9 +750,6 @@ static void wm_event_handler_ui_cancel(bContext *C)
* Access to #wmWindowManager.reports
* \{ */
-/**
- * Show the report in the info header.
- */
void WM_report_banner_show(void)
{
wmWindowManager *wm = G_MAIN->wm.first;
@@ -770,9 +765,6 @@ void WM_report_banner_show(void)
wm_reports->reporttimer->customdata = rti;
}
-/**
- * Hide all currently displayed banners and abort their timer.
- */
void WM_report_banners_cancel(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
@@ -855,9 +847,9 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
return true;
}
-/* sets up the new context and calls 'wm_operator_invoke()' with poll_only */
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
{
+ /* Sets up the new context and calls #wm_operator_invoke() with poll_only. */
return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL);
}
@@ -892,11 +884,6 @@ bool WM_operator_check_ui_empty(wmOperatorType *ot)
return true;
}
-/**
- * Sets the active region for this space from the context.
- *
- * \see #BKE_area_find_region_active_win
- */
void WM_operator_region_active_win_set(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -1103,13 +1090,6 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op)
return retval;
}
-/**
- * For running operators with frozen context (modal handlers, menus).
- *
- * \param store: Store settings for re-use.
- *
- * \warning do not use this within an operator to call its self! T29537.
- */
int WM_operator_call_ex(bContext *C, wmOperator *op, const bool store)
{
return wm_operator_exec(C, op, false, store);
@@ -1120,19 +1100,11 @@ int WM_operator_call(bContext *C, wmOperator *op)
return WM_operator_call_ex(C, op, false);
}
-/**
- * This is intended to be used when an invoke operator wants to call exec on its self
- * and is basically like running op->type->exec() directly, no poll checks no freeing,
- * since we assume whoever called invoke will take care of that
- */
int WM_operator_call_notest(bContext *C, wmOperator *op)
{
return wm_operator_exec_notest(C, op);
}
-/**
- * Execute this operator again, put here so it can share above code
- */
int WM_operator_repeat(bContext *C, wmOperator *op)
{
const int op_flag = OP_IS_REPEAT;
@@ -1149,12 +1121,6 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op)
op->flag &= ~op_flag;
return ret;
}
-/**
- * \return true if #WM_operator_repeat can run.
- * Simple check for now but may become more involved.
- * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
- * checks if #WM_operator_repeat() can run at all, not that it WILL run at any time.
- */
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
{
if (op->type->exec != NULL) {
@@ -1592,7 +1558,6 @@ static int wm_operator_call_internal(bContext *C,
return 0;
}
-/* Invokes operator in context. */
int WM_operator_name_call_ptr(bContext *C,
wmOperatorType *ot,
wmOperatorCallContext context,
@@ -1614,6 +1579,16 @@ int WM_operator_name_call(bContext *C,
return 0;
}
+bool WM_operator_name_poll(bContext *C, const char *opstring)
+{
+ wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ if (!ot) {
+ return false;
+ }
+
+ return WM_operator_poll(C, ot);
+}
+
int WM_operator_name_call_with_properties(struct bContext *C,
const char *opstring,
wmOperatorCallContext context,
@@ -1625,9 +1600,6 @@ int WM_operator_name_call_with_properties(struct bContext *C,
return WM_operator_name_call_ptr(C, ot, context, &props_ptr);
}
-/**
- * Call an existent menu. The menu can be created in C or Python.
- */
void WM_menu_name_call(bContext *C, const char *menu_name, short context)
{
wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false);
@@ -1638,13 +1610,6 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context)
WM_operator_properties_free(&ptr);
}
-/**
- * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
- *
- * - #wmOperatorType is used instead of operator name since python already has the operator type.
- * - `poll()` must be called by python before this runs.
- * - reports can be passed to this function (so python can report them as exceptions).
- */
int WM_operator_call_py(bContext *C,
wmOperatorType *ot,
wmOperatorCallContext context,
@@ -1849,9 +1814,9 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
* General API for different handler types.
* \{ */
-/* Future extra customadata free? */
void wm_event_free_handler(wmEventHandler *handler)
{
+ /* Future extra customa-data free? */
MEM_freeN(handler);
}
@@ -1923,7 +1888,6 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
}
}
-/* Called on exit or remove area, only here call cancel callback. */
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3525,8 +3489,6 @@ static void wm_event_handle_xrevent(bContext *C,
}
#endif /* WITH_XR_OPENXR */
-/* Called in main loop. */
-/* Goes over entire hierarchy: events -> window -> screen -> area -> region. */
void wm_event_do_handlers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3836,12 +3798,6 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
/* Operator is supposed to have a filled "path" property. */
/* Optional property: file-type (XXX enum?) */
-/**
- * The idea here is to keep a handler alive on window queue, owning the operator.
- * The file window can send event to make it execute, thus ensuring
- * executing happens outside of lower level queues, with UI refreshed.
- * Should also allow multiwin solutions.
- */
void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3940,10 +3896,6 @@ wmEventHandler_Op *WM_event_add_modal_handler(bContext *C, wmOperator *op)
return handler;
}
-/**
- * Modal handlers store a pointer to an area which might be freed while the handler runs.
- * Use this function to NULL all handler pointers to \a old_area.
- */
void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
{
LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
@@ -3958,10 +3910,6 @@ void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area,
}
}
-/**
- * Modal handlers store a pointer to a region which might be freed while the handler runs.
- * Use this function to NULL all handler pointers to \a old_region.
- */
void WM_event_modal_handler_region_replace(wmWindow *win,
const ARegion *old_region,
ARegion *new_region)
@@ -4152,7 +4100,6 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
return handler;
}
-/* Priorities not implemented yet, for time being just insert in begin of list. */
wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
wmKeyMap *keymap,
int UNUSED(priority))
@@ -4259,7 +4206,6 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
return handler;
}
-/* Set "postpone" for win->modalhandlers, this is in a running for () loop in wm_handlers_do(). */
void WM_event_remove_ui_handler(ListBase *handlers,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
@@ -4324,9 +4270,10 @@ wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, ListBas
return handler;
}
-/* XXX(ton): solution works, still better check the real cause. */
void WM_event_remove_area_handler(ListBase *handlers, void *area)
{
+ /* XXX(ton): solution works, still better check the real cause. */
+
LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, handlers) {
if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
@@ -4752,9 +4699,6 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
return event_new;
}
-/**
- * Windows store own event queues #wmWindow.event_queue (no #bContext here).
- */
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
@@ -5372,10 +5316,6 @@ const char *WM_window_cursor_keymap_status_get(const wmWindow *win,
return NULL;
}
-/**
- * Similar to #BKE_screen_area_map_find_area_xy and related functions,
- * use here since the area is stored in the window manager.
- */
ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
{
if (screen->state == SCREENFULL) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index a301b17227d..1d3fa158ac1 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -111,6 +111,7 @@
#include "ED_fileselect.h"
#include "ED_image.h"
#include "ED_outliner.h"
+#include "ED_render.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_util.h"
@@ -170,9 +171,6 @@ void WM_file_tag_modified(void)
}
}
-/**
- * Check if there is data that would be lost when closing the current file without saving.
- */
bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm)
{
return !wm->file_saved || ED_image_should_save_modified(bmain) ||
@@ -620,6 +618,8 @@ static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef
/* Always do this as both startup and preferences may have loaded in many font's
* at a different zoom level to the file being loaded. */
UI_view2d_zoom_cache_reset();
+
+ ED_preview_restart_queue_free();
}
/**
@@ -955,16 +955,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* #BKE_blendfile_read_result_setup sets new Main into context. */
Main *bmain = CTX_data_main(C);
- /* When recovering a session from an unsaved file, this can have a blank path. */
- if (BKE_main_blendfile_path(bmain)[0] != '\0') {
- G.save_over = 1;
- G.relbase_valid = 1;
- }
- else {
- G.save_over = 0;
- G.relbase_valid = 0;
- }
-
/* match the read WM with current WM */
wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
WM_check(C); /* opens window(s), checks keymaps */
@@ -1032,12 +1022,6 @@ static struct {
bool override;
} wm_init_state_app_template = {{0}};
-/**
- * Used for setting app-template from the command line:
- * - non-empty string: overrides.
- * - empty string: override, using no app template.
- * - NULL: clears override.
- */
void WM_init_state_app_template_set(const char *app_template)
{
if (app_template) {
@@ -1061,16 +1045,6 @@ const char *WM_init_state_app_template_get(void)
/** \name Read Startup & Preferences Blend-File API
* \{ */
-/**
- * Called on startup, (context entirely filled with NULLs)
- * or called for 'New File' both `startup.blend` and `userpref.blend` are checked.
- *
- * \param r_params_file_read_post: Support postponed initialization,
- * needed for initial startup when only some sub-systems have been initialized.
- * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored
- * in this return argument.
- * The caller is responsible for calling #wm_homefile_read_post with this return argument.
- */
void wm_homefile_read_ex(bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
ReportList *reports,
@@ -1167,8 +1141,6 @@ void wm_homefile_read_ex(bContext *C,
wm_file_read_pre(C, use_data, use_userdef);
if (use_data) {
- G.relbase_valid = 0;
-
/* put aside screens to match with persistent windows later */
wm_window_match_init(C, &wmbase);
}
@@ -1372,10 +1344,7 @@ void wm_homefile_read_ex(bContext *C,
if (use_data) {
WM_check(C); /* opens window(s), checks keymaps */
- bmain->name[0] = '\0';
-
- /* start with save preference untitled.blend */
- G.save_over = 0;
+ bmain->filepath[0] = '\0';
}
{
@@ -1406,10 +1375,6 @@ void wm_homefile_read(bContext *C,
wm_homefile_read_ex(C, params_homefile, reports, NULL);
}
-/**
- * Special case, support deferred execution of #wm_file_read_post,
- * Needed when loading for the first time to workaround order of initialization bug, see T89046.
- */
void wm_homefile_read_post(struct bContext *C,
const struct wmFileReadPost_Params *params_file_read_post)
{
@@ -1417,6 +1382,8 @@ void wm_homefile_read_post(struct bContext *C,
MEM_freeN((void *)params_file_read_post);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Blend-File History API
* \{ */
@@ -1514,18 +1481,18 @@ static void wm_history_file_write(void)
static void wm_history_file_update(void)
{
RecentFile *recent;
- const char *blendfile_name = BKE_main_blendfile_path_from_global();
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
- /* no write history for recovered startup files */
- if (blendfile_name[0] == '\0') {
+ /* No write history for recovered startup files. */
+ if (blendfile_path[0] == '\0') {
return;
}
recent = G.recent_files.first;
/* refresh recent-files.txt of recent opened files, when current file was changed */
- if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_name) != 0)) {
+ if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_path) != 0)) {
- recent = wm_file_history_find(blendfile_name);
+ recent = wm_file_history_find(blendfile_path);
if (recent) {
BLI_remlink(&G.recent_files, recent);
}
@@ -1536,7 +1503,7 @@ static void wm_history_file_update(void)
recent_next = recent->next;
wm_history_file_free(recent);
}
- recent = wm_history_file_new(blendfile_name);
+ recent = wm_history_file_new(blendfile_path);
}
/* add current file to the beginning of list */
@@ -1546,7 +1513,7 @@ static void wm_history_file_update(void)
wm_history_file_write();
/* also update most recent files on System */
- GHOST_addToSystemRecentFiles(blendfile_name);
+ GHOST_addToSystemRecentFiles(blendfile_path);
}
}
@@ -1721,7 +1688,6 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
return ibuf;
}
-/* easy access from gdb */
bool write_crash_blend(void)
{
char path[FILE_MAX];
@@ -1817,8 +1783,9 @@ static bool wm_file_write(bContext *C,
if (file_preview_type == USER_FILE_PREVIEW_AUTO) {
Scene *scene = CTX_data_scene(C);
- bool do_render = (scene != NULL && scene->camera != NULL &&
- (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) != NULL));
+ bScreen *screen = CTX_wm_screen(C);
+ bool do_render = (scene != NULL && scene->camera != NULL && screen != NULL &&
+ (BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0) != NULL));
file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT;
}
@@ -1846,16 +1813,10 @@ static bool wm_file_write(bContext *C,
ED_editors_flush_edits(bmain);
- /* First time saving. */
- /* XXX(ton): temp solution to solve bug, real fix coming. */
- if ((BKE_main_blendfile_path(bmain)[0] == '\0') && (use_save_as_copy == false)) {
- BLI_strncpy(bmain->name, filepath, sizeof(bmain->name));
- }
-
/* XXX(ton): temp solution to solve bug, real fix coming. */
bmain->recovered = 0;
- if (BLO_write_file(CTX_data_main(C),
+ if (BLO_write_file(bmain,
filepath,
fileflags,
&(const struct BlendFileWriteParams){
@@ -1869,10 +1830,7 @@ static bool wm_file_write(bContext *C,
(CTX_wm_manager(C)->op_undo_depth == 0);
if (use_save_as_copy == false) {
- G.relbase_valid = 1;
- BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); /* is guaranteed current file */
-
- G.save_over = 1; /* disable untitled.blend convention */
+ STRNCPY(bmain->filepath, filepath); /* is guaranteed current file */
}
SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
@@ -1923,8 +1881,13 @@ static void wm_autosave_location(char *filepath)
const char *savedir;
#endif
- if (G_MAIN && G.relbase_valid) {
- const char *basename = BLI_path_basename(BKE_main_blendfile_path_from_global());
+ /* Normally there is no need to check for this to be NULL,
+ * however this runs on exit when it may be cleared. */
+ Main *bmain = G_MAIN;
+ const char *blendfile_path = bmain ? BKE_main_blendfile_path(bmain) : NULL;
+
+ if (blendfile_path && (blendfile_path[0] != '\0')) {
+ const char *basename = BLI_path_basename(blendfile_path);
int len = strlen(basename) - 6;
BLI_snprintf(path, sizeof(path), "%.*s_%d_autosave.blend", len, basename, pid);
}
@@ -2006,9 +1969,6 @@ void WM_autosave_init(wmWindowManager *wm)
wm_autosave_timer_begin(wm);
}
-/**
- * Run the auto-save timer action.
- */
void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
{
wm_autosave_timer_end(wm);
@@ -2137,7 +2097,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
fileflags,
&(const struct BlendFileWriteParams){
/* Make all paths absolute when saving the startup file.
- * On load the `G.relbase_valid` will be false so the paths
+ * On load the `G.main->filepath` will be empty so the paths
* won't have a base for resolving the relative paths. */
.remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE,
/* Don't apply any path changes to the current blend file. */
@@ -2150,7 +2110,6 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
printf("ok\n");
BKE_report(op->reports, RPT_INFO, "Startup file saved");
- G.save_over = 0;
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST);
@@ -2637,7 +2596,7 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
Main *bmain = CTX_data_main(C);
- const char *openname = BKE_main_blendfile_path(bmain);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
if (CTX_wm_window(C) == NULL) {
/* in rare cases this could happen, when trying to invoke in background
@@ -2650,10 +2609,10 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
/* if possible, get the name of the most recently used .blend file */
if (G.recent_files.first) {
struct RecentFile *recent = G.recent_files.first;
- openname = recent->filepath;
+ blendfile_path = recent->filepath;
}
- RNA_string_set(op->ptr, "filepath", openname);
+ RNA_string_set(op->ptr, "filepath", blendfile_path);
wm_open_init_load_ui(op, true);
wm_open_init_use_scripts(op, true);
op->customdata = NULL;
@@ -2876,7 +2835,8 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
static bool wm_revert_mainfile_poll(bContext *UNUSED(C))
{
- return G.relbase_valid;
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ return (blendfile_path[0] != '\0');
}
void WM_OT_revert_mainfile(wmOperatorType *ot)
@@ -3033,9 +2993,9 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
* Both #WM_OT_save_as_mainfile & #WM_OT_save_mainfile.
* \{ */
-static void wm_filepath_default(char *filepath)
+static void wm_filepath_default(const Main *bmain, char *filepath)
{
- if (G.save_over == false) {
+ if (bmain->filepath[0] == '\0') {
BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend");
}
}
@@ -3046,7 +3006,8 @@ static void save_set_compress(wmOperator *op)
prop = RNA_struct_find_property(op->ptr, "compress");
if (!RNA_property_is_set(op->ptr, prop)) {
- if (G.save_over) { /* keep flag for existing file */
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') { /* Keep flag for existing file. */
RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
}
else { /* use userdef for new file */
@@ -3059,21 +3020,22 @@ static void save_set_filepath(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
- char name[FILE_MAX];
+ char filepath[FILE_MAX];
prop = RNA_struct_find_property(op->ptr, "filepath");
if (!RNA_property_is_set(op->ptr, prop)) {
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
/* if not saved before, get the name of the most recently used .blend file */
- if (BKE_main_blendfile_path(bmain)[0] == '\0' && G.recent_files.first) {
+ if ((blendfile_path[0] == '\0') && G.recent_files.first) {
struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
+ STRNCPY(filepath, recent->filepath);
}
else {
- BLI_strncpy(name, bmain->name, FILE_MAX);
+ STRNCPY(filepath, blendfile_path);
}
- wm_filepath_default(name);
- RNA_property_string_set(op->ptr, prop, name);
+ wm_filepath_default(bmain, filepath);
+ RNA_property_string_set(op->ptr, prop, filepath);
}
}
@@ -3105,12 +3067,32 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
BLO_WRITE_PATH_REMAP_NONE;
save_set_compress(op);
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ const bool is_filepath_set = RNA_struct_property_is_set(op->ptr, "filepath");
+ if (is_filepath_set) {
RNA_string_get(op->ptr, "filepath", path);
}
else {
- BLI_strncpy(path, BKE_main_blendfile_path(bmain), FILE_MAX);
- wm_filepath_default(path);
+ STRNCPY(path, BKE_main_blendfile_path(bmain));
+ }
+
+ if (path[0] == '\0') {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Unable to save an unsaved file with an empty or unset \"filepath\" property");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* NOTE(@campbellbarton): only check this for file-path properties so saving an already
+ * saved file never fails with an error.
+ * Even though this should never happen, there may be some corner case where a malformed
+ * path is stored in `G.main->filepath`: when the file path is initialized from recovering
+ * a blend file - for example, so in this case failing to save isn't ideal. */
+ if (is_filepath_set && !BLI_path_is_abs_from_cwd(path)) {
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "The \"filepath\" property was not an absolute path: \"%s\"",
+ path);
+ return OPERATOR_CANCELLED;
}
const int fileflags_orig = G.fileflags;
@@ -3227,14 +3209,15 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
/* if we're saving for the first time and prefer relative paths -
* any existing paths will be absolute,
* enable the option to remap paths to avoid confusion T37240. */
- if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if ((blendfile_path[0] == '\0') && (U.flag & USER_RELPATHS)) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, true);
}
}
- if (G.save_over) {
+ if (blendfile_path[0] != '\0') {
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
@@ -3336,6 +3319,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C,
struct ARegion *region,
void *UNUSED(arg1))
{
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
wmWindowManager *wm = CTX_wm_manager(C);
uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS);
@@ -3383,7 +3367,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C,
/* Allow reload if we have a saved file.
* Otherwise just enable scripts and reset the depsgraphs. */
- if (G.relbase_valid && wm->file_saved) {
+ if ((blendfile_path[0] != '\0') && wm->file_saved) {
but = uiDefIconTextBut(block,
UI_BTYPE_BUT,
0,
@@ -3640,10 +3624,10 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C,
uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false);
/* Filename. */
- const char *blendfile_pathpath = BKE_main_blendfile_path(CTX_data_main(C));
+ const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C));
char filename[FILE_MAX];
- if (blendfile_pathpath[0] != '\0') {
- BLI_split_file_part(blendfile_pathpath, filename, sizeof(filename));
+ if (blendfile_path[0] != '\0') {
+ BLI_split_file_part(blendfile_path, filename, sizeof(filename));
}
else {
STRNCPY(filename, "untitled.blend");
@@ -3810,10 +3794,6 @@ static void wm_free_operator_properties_callback(void *user_data)
IDP_FreeProperty(properties);
}
-/**
- * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE
- * then.
- */
bool wm_operator_close_file_dialog_if_needed(bContext *C,
wmOperator *op,
wmGenericCallbackFn post_action_fn)
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index d373ecdac77..cf6ecd55757 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -52,9 +52,8 @@
#include "BLO_readfile.h"
-#include "BLT_translation.h"
-
#include "BKE_armature.h"
+#include "BKE_blendfile_link_append.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_key.h"
@@ -114,12 +113,13 @@ static bool wm_link_append_poll(bContext *C)
static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
if (G.lib[0] != '\0') {
RNA_string_set(op->ptr, "filepath", G.lib);
}
- else if (G.relbase_valid) {
+ else if (blendfile_path[0] != '\0') {
char path[FILE_MAX];
- BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
+ STRNCPY(path, blendfile_path);
BLI_path_parent_dir(path);
RNA_string_set(op->ptr, "filepath", path);
}
@@ -168,841 +168,6 @@ static int wm_link_append_flag(wmOperator *op)
return flag;
}
-typedef struct WMLinkAppendDataItem {
- char *name;
- BLI_bitmap
- *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
- short idcode;
-
- /** Type of action to do to append this item, and other append-specific information. */
- char append_action;
- char append_tag;
-
- ID *new_id;
- Library *source_library;
- void *customdata;
-} WMLinkAppendDataItem;
-
-typedef struct WMLinkAppendData {
- LinkNodePair libraries;
- LinkNodePair items;
- int num_libraries;
- int num_items;
- /**
- * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h
- */
- int flag;
-
- /** Allows to easily find an existing items from an ID pointer. Used by append code. */
- GHash *new_id_to_item;
-
- /** Runtime info used by append code to manage re-use of already appended matching IDs. */
- GHash *library_weak_reference_mapping;
-
- /* Internal 'private' data */
- MemArena *memarena;
-} WMLinkAppendData;
-
-typedef struct WMLinkAppendDataCallBack {
- WMLinkAppendData *lapp_data;
- WMLinkAppendDataItem *item;
- ReportList *reports;
-
-} WMLinkAppendDataCallBack;
-
-enum {
- WM_APPEND_ACT_UNSET = 0,
- WM_APPEND_ACT_KEEP_LINKED,
- WM_APPEND_ACT_REUSE_LOCAL,
- WM_APPEND_ACT_MAKE_LOCAL,
- WM_APPEND_ACT_COPY_LOCAL,
-};
-
-enum {
- WM_APPEND_TAG_INDIRECT = 1 << 0,
-};
-
-static WMLinkAppendData *wm_link_append_data_new(const int flag)
-{
- MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data));
-
- lapp_data->flag = flag;
- lapp_data->memarena = ma;
-
- return lapp_data;
-}
-
-static void wm_link_append_data_free(WMLinkAppendData *lapp_data)
-{
- if (lapp_data->new_id_to_item != NULL) {
- BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL);
- }
-
- BLI_assert(lapp_data->library_weak_reference_mapping == NULL);
-
- BLI_memarena_free(lapp_data->memarena);
-}
-
-/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */
-
-static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname)
-{
- size_t len = strlen(libname) + 1;
- char *libpath = BLI_memarena_alloc(lapp_data->memarena, len);
-
- BLI_strncpy(libpath, libname, len);
- BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena);
- lapp_data->num_libraries++;
-}
-
-static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data,
- const char *idname,
- const short idcode,
- void *customdata)
-{
- WMLinkAppendDataItem *item = BLI_memarena_calloc(lapp_data->memarena, sizeof(*item));
- size_t len = strlen(idname) + 1;
-
- item->name = BLI_memarena_alloc(lapp_data->memarena, len);
- BLI_strncpy(item->name, idname, len);
- item->idcode = idcode;
- item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries);
-
- item->new_id = NULL;
- item->append_action = WM_APPEND_ACT_UNSET;
- item->customdata = customdata;
-
- BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena);
- lapp_data->num_items++;
-
- return item;
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Library appending helper functions.
- *
- * FIXME: Deduplicate code with similar one in readfile.c
- * \{ */
-
-static bool object_in_any_scene(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) {
- if (BKE_scene_object_find(sce, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool object_in_any_collection(Main *bmain, Object *ob)
-{
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- if (BKE_collection_has_object(collection, ob)) {
- return true;
- }
- }
-
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- if (scene->master_collection != NULL &&
- BKE_collection_has_object(scene->master_collection, ob)) {
- return true;
- }
- }
-
- return false;
-}
-
-static ID *wm_append_loose_data_instantiate_process_check(WMLinkAppendDataItem *item)
-{
- /* We consider that if we either kept it linked, or re-used already local data, instantiation
- * status of those should not be modified. */
- if (!ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_MAKE_LOCAL)) {
- return NULL;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- return NULL;
- }
-
- if (item->append_action == WM_APPEND_ACT_COPY_LOCAL) {
- BLI_assert(ID_IS_LINKED(id));
- id = id->newid;
- if (id == NULL) {
- return NULL;
- }
-
- BLI_assert(!ID_IS_LINKED(id));
- return id;
- }
-
- BLI_assert(!ID_IS_LINKED(id));
- return id;
-}
-
-static void wm_append_loose_data_instantiate_ensure_active_collection(
- WMLinkAppendData *lapp_data,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- Collection **r_active_collection)
-{
- /* Find or add collection as needed. */
- if (*r_active_collection == NULL) {
- if (lapp_data->flag & FILE_ACTIVE_COLLECTION) {
- LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
- *r_active_collection = lc->collection;
- }
- else {
- *r_active_collection = BKE_collection_add(
- bmain, scene->master_collection, DATA_("Appended Data"));
- }
- }
-}
-
-/* TODO: De-duplicate this code with the one in readfile.c, think we need some utils code for that
- * in BKE. */
-static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- if (scene == NULL) {
- /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself.
- */
- return;
- }
-
- LinkNode *itemlink;
- Collection *active_collection = NULL;
- const bool do_obdata = (lapp_data->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0;
-
- /* Do NOT make base active here! screws up GUI stuff,
- * if you want it do it at the editor level. */
- const bool object_set_active = false;
-
- /* First pass on obdata to enable their instantiation by default, then do a second pass on
- * objects to clear it for any obdata already in use. */
- if (do_obdata) {
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL) {
- continue;
- }
- const ID_Type idcode = GS(id->name);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
-
- id->tag |= LIB_TAG_DOIT;
- }
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL || GS(id->name) != ID_OB) {
- continue;
- }
-
- Object *ob = (Object *)id;
- Object *new_ob = (Object *)id->newid;
- if (ob->data != NULL) {
- ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT;
- }
- if (new_ob != NULL && new_ob->data != NULL) {
- ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT;
- }
- }
- }
-
- /* First do collections, then objects, then obdata. */
-
- /* NOTE: For collections we only view_layer-instantiate duplicated collections that have
- * non-instantiated objects in them. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL || GS(id->name) != ID_GR) {
- continue;
- }
-
- /* We do not want to force instantiation of indirectly appended collections. Users can now
- * easily instantiate collections (and their objects) as needed by themselves. See T67032. */
- /* We need to check that objects in that collections are already instantiated in a scene.
- * Otherwise, it's better to add the collection to the scene's active collection, than to
- * instantiate its objects in active scene's collection directly. See T61141.
- *
- * NOTE: We only check object directly into that collection, not recursively into its
- * children.
- */
- Collection *collection = (Collection *)id;
- /* We always add collections directly selected by the user. */
- bool do_add_collection = (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0;
- if (!do_add_collection) {
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- if (!object_in_any_scene(bmain, ob)) {
- do_add_collection = true;
- break;
- }
- }
- }
- if (do_add_collection) {
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- /* In case user requested instantiation of collections as empties, we do so for the one they
- * explicitly selected (originally directly linked IDs). */
- if ((lapp_data->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 &&
- (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0) {
- /* BKE_object_add(...) messes with the selection. */
- Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
- ob->type = OB_EMPTY;
- ob->empty_drawsize = U.collection_instance_empty_size;
-
- const bool set_selected = (lapp_data->flag & FILE_AUTOSELECT) != 0;
- /* TODO: why is it OK to make this active here but not in other situations?
- * See other callers of #object_base_instance_init */
- const bool set_active = set_selected;
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, set_active);
-
- /* Assign the collection. */
- ob->instance_collection = collection;
- id_us_plus(&collection->id);
- ob->transflag |= OB_DUPLICOLLECTION;
- copy_v3_v3(ob->loc, scene->cursor.location);
- }
- else {
- /* Add collection as child of active collection. */
- BKE_collection_child_add(bmain, active_collection, collection);
-
- if ((lapp_data->flag & FILE_AUTOSELECT) != 0) {
- LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
- Object *ob = coll_ob->ob;
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base) {
- base->flag |= BASE_SELECTED;
- BKE_scene_object_base_flag_sync_from_base(base);
- }
- }
- }
- }
- }
- }
-
- /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
- * anywhere. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL || GS(id->name) != ID_OB) {
- continue;
- }
-
- Object *ob = (Object *)id;
-
- if (object_in_any_collection(bmain, ob)) {
- continue;
- }
-
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- CLAMP_MIN(ob->id.us, 0);
- ob->mode = OB_MODE_OBJECT;
-
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active);
- }
-
- if (!do_obdata) {
- return;
- }
-
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL) {
- continue;
- }
- const ID_Type idcode = GS(id->name);
- if (!OB_DATA_SUPPORT_ID(idcode)) {
- continue;
- }
- if ((id->tag & LIB_TAG_DOIT) == 0) {
- continue;
- }
-
- wm_append_loose_data_instantiate_ensure_active_collection(
- lapp_data, bmain, scene, view_layer, &active_collection);
-
- const int type = BKE_object_obdata_to_type(id);
- BLI_assert(type != -1);
- Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2);
- ob->data = id;
- id_us_plus(id);
- BKE_object_materials_test(bmain, ob, ob->data);
-
- BLO_object_instantiate_object_base_instance_init(
- bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active);
-
- copy_v3_v3(ob->loc, scene->cursor.location);
-
- id->tag &= ~LIB_TAG_DOIT;
- }
-
- /* Finally, add rigid body objects and constraints to current RB world(s). */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = wm_append_loose_data_instantiate_process_check(item);
- if (id == NULL || GS(id->name) != ID_OB) {
- continue;
- }
- BKE_rigidbody_ensure_local_object(bmain, (Object *)id);
- }
-}
-
-/** \} */
-
-static int foreach_libblock_append_callback(LibraryIDLinkCallbackData *cb_data)
-{
- /* NOTE: It is important to also skip liboverride references here, as those should never be made
- * local. */
- if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK |
- IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
- return IDWALK_RET_NOP;
- }
-
- WMLinkAppendDataCallBack *data = cb_data->user_data;
- ID *id = *cb_data->id_pointer;
-
- if (id == NULL) {
- return IDWALK_RET_NOP;
- }
-
- if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
- /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items,
- * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be
- * processed, so we need to recursively deal with them here. */
- /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it
- * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of
- * shapekey referencing the shapekey itself). */
- if (id != cb_data->id_self) {
- BKE_library_foreach_ID_link(
- cb_data->bmain, id, foreach_libblock_append_callback, data, IDWALK_NOP);
- }
- return IDWALK_RET_NOP;
- }
-
- const bool do_recursive = (data->lapp_data->flag & BLO_LIBLINK_APPEND_RECURSIVE) != 0;
- if (!do_recursive && cb_data->id_owner->lib != id->lib) {
- /* When `do_recursive` is false, we only make local IDs from same library(-ies) as the
- * initially directly linked ones. */
- return IDWALK_RET_NOP;
- }
-
- WMLinkAppendDataItem *item = BLI_ghash_lookup(data->lapp_data->new_id_to_item, id);
- if (item == NULL) {
- item = wm_link_append_data_item_add(data->lapp_data, id->name, GS(id->name), NULL);
- item->new_id = id;
- item->source_library = id->lib;
- /* Since we did not have an item for that ID yet, we know user did not selected it explicitly,
- * it was rather linked indirectly. This info is important for instantiation of collections. */
- item->append_tag |= WM_APPEND_TAG_INDIRECT;
- BLI_ghash_insert(data->lapp_data->new_id_to_item, id, item);
- }
-
- /* NOTE: currently there is no need to do anything else here, but in the future this would be
- * the place to add specific per-usage decisions on how to append an ID. */
-
- return IDWALK_RET_NOP;
-}
-
-/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked,
- * made local, duplicated as local, re-used from local etc.
- *
- * TODO: Expose somehow this logic to the two other parts of code performing actual append
- * (i.e. copy/paste and `bpy` link/append API).
- * Then we can heavily simplify #BKE_library_make_local(). */
-static void wm_append_do(WMLinkAppendData *lapp_data,
- ReportList *reports,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- BLI_assert((lapp_data->flag & FILE_LINK) == 0);
-
- const bool set_fakeuser = (lapp_data->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0;
- const bool do_reuse_local_id = (lapp_data->flag & BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0;
-
- const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY |
- ((lapp_data->flag & BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) !=
- 0 ?
- LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR :
- 0);
-
- LinkNode *itemlink;
-
- /* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as
- * liboverride references as already existing. */
- lapp_data->new_id_to_item = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_ghash_insert(lapp_data->new_id_to_item, id, item);
-
- /* This ensures that if a liboverride reference is also linked/used by some other appended
- * data, it gets a local copy instead of being made directly local, so that the liboverride
- * references remain valid (i.e. linked data). */
- if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
- id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING;
- }
- }
-
- lapp_data->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain);
-
- /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect
- * dependencies), this list will grow and we will process those IDs later, leading to a flatten
- * recursive processing of all the linked dependencies. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(item->customdata == NULL);
-
- /* In Append case linked IDs should never be marked as needing post-processing (instantiation
- * of loose objects etc.). */
- BLI_assert((id->tag & LIB_TAG_DOIT) == 0);
-
- ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ?
- BKE_main_library_weak_reference_search_item(
- lapp_data->library_weak_reference_mapping,
- id->lib->filepath,
- id->name) :
- NULL;
-
- if (item->append_action != WM_APPEND_ACT_UNSET) {
- /* Already set, pass. */
- }
- if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name);
- item->append_action = WM_APPEND_ACT_KEEP_LINKED;
- }
- else if (do_reuse_local_id && existing_local_id != NULL) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name);
- item->append_action = WM_APPEND_ACT_REUSE_LOCAL;
- item->customdata = existing_local_id;
- }
- else if (id->tag & LIB_TAG_PRE_EXISTING) {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name);
- item->append_action = WM_APPEND_ACT_COPY_LOCAL;
- }
- else {
- CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name);
- item->append_action = WM_APPEND_ACT_MAKE_LOCAL;
- }
-
- /* Only check dependencies if we are not keeping linked data, nor re-using existing local data.
- */
- if (!ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) {
- WMLinkAppendDataCallBack cb_data = {
- .lapp_data = lapp_data, .item = item, .reports = reports};
- BKE_library_foreach_ID_link(
- bmain, id, foreach_libblock_append_callback, &cb_data, IDWALK_NOP);
- }
-
- /* If we found a matching existing local id but are not re-using it, we need to properly clear
- * its weak reference to linked data. */
- if (existing_local_id != NULL &&
- !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) {
- BKE_main_library_weak_reference_remove_item(lapp_data->library_weak_reference_mapping,
- id->lib->filepath,
- id->name,
- existing_local_id);
- }
- }
-
- /* Effectively perform required operation on every linked ID. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
-
- ID *local_appended_new_id = NULL;
- char lib_filepath[FILE_MAX];
- BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath));
- char lib_id_name[MAX_ID_NAME];
- BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name));
-
- switch (item->append_action) {
- case WM_APPEND_ACT_COPY_LOCAL:
- BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY);
- local_appended_new_id = id->newid;
- break;
- case WM_APPEND_ACT_MAKE_LOCAL:
- BKE_lib_id_make_local(bmain,
- id,
- make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL |
- LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
- BLI_assert(id->newid == NULL);
- local_appended_new_id = id;
- break;
- case WM_APPEND_ACT_KEEP_LINKED:
- /* Nothing to do here. */
- break;
- case WM_APPEND_ACT_REUSE_LOCAL:
- /* We only need to set `newid` to ID found in previous loop, for proper remapping. */
- ID_NEW_SET(id, item->customdata);
- /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */
- break;
- case WM_APPEND_ACT_UNSET:
- CLOG_ERROR(
- &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name);
- break;
- default:
- BLI_assert(0);
- }
-
- if (local_appended_new_id != NULL) {
- if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) {
- BKE_main_library_weak_reference_add_item(lapp_data->library_weak_reference_mapping,
- lib_filepath,
- lib_id_name,
- local_appended_new_id);
- }
-
- if (set_fakeuser) {
- if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) {
- /* Do not set fake user on objects nor collections (instancing). */
- id_fake_user_set(local_appended_new_id);
- }
- }
- }
- }
-
- BKE_main_library_weak_reference_destroy(lapp_data->library_weak_reference_mapping);
- lapp_data->library_weak_reference_mapping = NULL;
-
- /* Remap IDs as needed. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- if (ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_REUSE_LOCAL)) {
- BLI_assert(ID_IS_LINKED(id));
- id = id->newid;
- if (id == NULL) {
- continue;
- }
- }
-
- BLI_assert(!ID_IS_LINKED(id));
-
- BKE_libblock_relink_to_newid(bmain, id, 0);
- }
-
- /* Remove linked IDs when a local existing data has been reused instead. */
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action != WM_APPEND_ACT_REUSE_LOCAL) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(ID_IS_LINKED(id));
- BLI_assert(id->newid != NULL);
-
- id->tag |= LIB_TAG_DOIT;
- item->new_id = id->newid;
- }
- BKE_id_multi_tagged_delete(bmain);
-
- /* Instantiate newly created (duplicated) IDs as needed. */
- wm_append_loose_data_instantiate(lapp_data, bmain, scene, view_layer, v3d);
-
- /* Attempt to deal with object proxies.
- *
- * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not
- * producing any useful result in any known use case), neither here nor in
- * `BKE_library_make_local` currently.
- * Proxies are end of life anyway, so not worth spending time on this. */
- for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
-
- if (item->append_action != WM_APPEND_ACT_COPY_LOCAL) {
- continue;
- }
-
- ID *id = item->new_id;
- if (id == NULL) {
- continue;
- }
- BLI_assert(ID_IS_LINKED(id));
-
- /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
- * from another blend file into this one, even when that blend file contains proxified
- * armatures that have local references. Since the proxified object needs to be linked
- * (not local), this will only work when the "Localize all" checkbox is disabled.
- * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
- if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
- Object *ob = (Object *)id;
- Object *ob_new = (Object *)id->newid;
- bool is_local = false, is_lib = false;
-
- /* Proxies only work when the proxified object is linked-in from a library. */
- if (!ID_IS_LINKED(ob->proxy)) {
- CLOG_WARN(&LOG,
- "Proxy object %s will lose its link to %s, because the "
- "proxified object is local",
- id->newid->name,
- ob->proxy->id.name);
- continue;
- }
-
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
-
- /* We can only switch the proxy'ing to a made-local proxy if it is no longer
- * referred to from a library. Not checking for local use; if new local proxy
- * was not used locally would be a nasty bug! */
- if (is_local || is_lib) {
- CLOG_WARN(&LOG,
- "Made-local proxy object %s will lose its link to %s, "
- "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)",
- id->newid->name,
- ob->proxy->id.name,
- is_local,
- is_lib);
- }
- else {
- /* we can switch the proxy'ing from the linked-in to the made-local proxy.
- * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
- * was already allocated by object_make_local() (which called BKE_object_copy). */
- ob_new->proxy = ob->proxy;
- ob_new->proxy_group = ob->proxy_group;
- ob_new->proxy_from = ob->proxy_from;
- ob_new->proxy->proxy_from = ob_new;
- ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
- }
- }
- }
-
- BKE_main_id_newptr_and_tag_clear(bmain);
-}
-
-static void wm_link_do(WMLinkAppendData *lapp_data,
- ReportList *reports,
- Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- const View3D *v3d)
-{
- Main *mainl;
- BlendHandle *bh;
- Library *lib;
-
- const int flag = lapp_data->flag;
- const int id_tag_extra = 0;
-
- LinkNode *liblink, *itemlink;
- int lib_idx, item_idx;
-
- BLI_assert(lapp_data->num_items && lapp_data->num_libraries);
-
- for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink;
- lib_idx++, liblink = liblink->next) {
- char *libname = liblink->link;
- BlendFileReadReport bf_reports = {.reports = reports};
-
- if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
- bh = BLO_blendhandle_from_memory(
- datatoc_startup_blend, datatoc_startup_blend_size, &bf_reports);
- }
- else {
- bh = BLO_blendhandle_from_file(libname, &bf_reports);
- }
-
- if (bh == NULL) {
- /* Unlikely since we just browsed it, but possible
- * Error reports will have been made by BLO_blendhandle_from_file() */
- continue;
- }
-
- /* here appending/linking starts */
- struct LibraryLink_Params liblink_params;
- BLO_library_link_params_init_with_context(
- &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d);
- /* In case of append, do not handle instantiation in linking process, but during append phase
- * (see #wm_append_loose_data_instantiate ). */
- if ((flag & FILE_LINK) == 0) {
- liblink_params.flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT;
- }
-
- mainl = BLO_library_link_begin(&bh, libname, &liblink_params);
- lib = mainl->curlib;
- BLI_assert(lib);
- UNUSED_VARS_NDEBUG(lib);
-
- if (mainl->versionfile < 250) {
- BKE_reportf(reports,
- RPT_WARNING,
- "Linking or appending from a very old .blend file format (%d.%d), no animation "
- "conversion will "
- "be done! You may want to re-save your lib file with current Blender",
- mainl->versionfile,
- mainl->subversionfile);
- }
-
- /* For each lib file, we try to link all items belonging to that lib,
- * and tag those successful to not try to load them again with the other libs. */
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *new_id;
-
- if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
- continue;
- }
-
- new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_params);
-
- if (new_id) {
- /* If the link is successful, clear item's libs 'todo' flags.
- * This avoids trying to link same item with other libraries to come. */
- BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries);
- item->new_id = new_id;
- item->source_library = new_id->lib;
- }
- }
-
- BLO_library_link_end(mainl, &bh, &liblink_params);
- BLO_blendhandle_close(bh);
- }
-}
-
/**
* Check if an item defined by \a name and \a group can be appended/linked.
*
@@ -1053,7 +218,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PropertyRNA *prop;
- WMLinkAppendData *lapp_data;
+ BlendfileLinkAppendContext *lapp_context;
char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
char *group, *name;
int totfiles = 0;
@@ -1120,7 +285,14 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* We define our working data...
* Note that here, each item 'uses' one library, and only one. */
- lapp_data = wm_link_append_data_new(flag);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(
+ &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C));
+
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_embedded_blendfile_set(
+ lapp_context, datatoc_startup_blend, datatoc_startup_blend_size);
+
if (totfiles != 0) {
GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
int lib_idx = 0;
@@ -1138,7 +310,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (!BLI_ghash_haskey(libraries, libname)) {
BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx));
lib_idx++;
- wm_link_append_data_library_add(lapp_data, libname);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
}
}
}
@@ -1150,7 +322,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_join_dirfile(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, libname, &group, &name)) {
- WMLinkAppendDataItem *item;
+ BlendfileLinkAppendContextItem *item;
if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) {
continue;
@@ -1158,9 +330,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname));
- item = wm_link_append_data_item_add(
- lapp_data, name, BKE_idtype_idcode_from_name(group), NULL);
- BLI_BITMAP_ENABLE(item->libraries, lib_idx);
+ item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, name, BKE_idtype_idcode_from_name(group), NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, lib_idx);
}
}
RNA_END;
@@ -1168,16 +340,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_ghash_free(libraries, MEM_freeN, NULL);
}
else {
- WMLinkAppendDataItem *item;
+ BlendfileLinkAppendContextItem *item;
- wm_link_append_data_library_add(lapp_data, libname);
- item = wm_link_append_data_item_add(lapp_data, name, BKE_idtype_idcode_from_name(group), NULL);
- BLI_BITMAP_ENABLE(item->libraries, 0);
+ BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL);
+ item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, name, BKE_idtype_idcode_from_name(group), NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
}
- if (lapp_data->num_items == 0) {
+ if (BKE_blendfile_link_append_context_is_empty(lapp_context)) {
/* Early out in case there is nothing to link. */
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* Clear pre existing tag. */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
return OPERATOR_CANCELLED;
@@ -1186,7 +359,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* XXX We'd need re-entrant locking on Main for this to work... */
// BKE_main_lock(bmain);
- wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C));
+ BKE_blendfile_link(lapp_context, op->reports);
// BKE_main_unlock(bmain);
@@ -1196,10 +369,10 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* append, rather than linking */
if (do_append) {
- wm_append_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C));
+ BKE_blendfile_append(lapp_context, op->reports);
}
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* important we unset, otherwise these object won't
* link into other scenes from this blend file */
@@ -1351,33 +524,35 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain,
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* Define working data, with just the one item we want to link. */
- WMLinkAppendData *lapp_data = wm_link_append_data_new(flag);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(&lapp_params, bmain, flag, 0, scene, view_layer, v3d);
+
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_embedded_blendfile_set(
+ lapp_context, datatoc_startup_blend, datatoc_startup_blend_size);
- wm_link_append_data_library_add(lapp_data, filepath);
- WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL);
- BLI_BITMAP_ENABLE(item->libraries, 0);
+ BKE_blendfile_link_append_context_library_add(lapp_context, filepath, NULL);
+ BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add(
+ lapp_context, id_name, id_code, NULL);
+ BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0);
/* Link datablock. */
- wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d);
+ BKE_blendfile_link(lapp_context, NULL);
if (do_append) {
- wm_append_do(lapp_data, NULL, bmain, scene, view_layer, v3d);
+ BKE_blendfile_append(lapp_context, NULL);
}
/* Get linked datablock and free working data. */
- ID *id = item->new_id;
+ ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
return id;
}
-/*
- * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no
- * instantiation of linked objects, collections etc. will be performed.
- */
ID *WM_file_link_datablock(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1392,10 +567,6 @@ ID *WM_file_link_datablock(Main *bmain,
bmain, scene, view_layer, v3d, filepath, id_code, id_name, flag);
}
-/*
- * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no
- * instantiation of appended objects, collections etc. will be performed.
- */
ID *WM_file_append_datablock(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
@@ -1444,291 +615,6 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN
return OPERATOR_CANCELLED;
}
-static void lib_relocate_do_remap(Main *bmain,
- ID *old_id,
- ID *new_id,
- ReportList *reports,
- const bool do_reload,
- const short remap_flags)
-{
- BLI_assert(old_id);
- if (do_reload) {
- /* Since we asked for placeholders in case of missing IDs,
- * we expect to always get a valid one. */
- BLI_assert(new_id);
- }
- if (new_id) {
- CLOG_INFO(&LOG,
- 4,
- "Before remap of %s, old_id users: %d, new_id users: %d",
- old_id->name,
- old_id->us,
- new_id->us);
- BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
-
- if (old_id->flag & LIB_FAKEUSER) {
- id_fake_user_clear(old_id);
- id_fake_user_set(new_id);
- }
-
- CLOG_INFO(&LOG,
- 4,
- "After remap of %s, old_id users: %d, new_id users: %d",
- old_id->name,
- old_id->us,
- new_id->us);
-
- /* In some cases, new_id might become direct link, remove parent of library in this case. */
- if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) {
- if (do_reload) {
- BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */
- }
- new_id->lib->parent = NULL;
- }
- }
-
- if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
- /* Note that this *should* not happen - but better be safe than sorry in this area,
- * at least until we are 100% sure this cannot ever happen.
- * Also, we can safely assume names were unique so far,
- * so just replacing '.' by '~' should work,
- * but this does not totally rules out the possibility of name collision. */
- size_t len = strlen(old_id->name);
- size_t dot_pos;
- bool has_num = false;
-
- for (dot_pos = len; dot_pos--;) {
- char c = old_id->name[dot_pos];
- if (c == '.') {
- break;
- }
- if (c < '0' || c > '9') {
- has_num = false;
- break;
- }
- has_num = true;
- }
-
- if (has_num) {
- old_id->name[dot_pos] = '~';
- }
- else {
- len = MIN2(len, MAX_ID_NAME - 7);
- BLI_strncpy(&old_id->name[len], "~000", 7);
- }
-
- id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL);
-
- BKE_reportf(
- reports,
- RPT_WARNING,
- "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, "
- "old one (%d remaining users) had to be kept and was renamed to '%s'",
- new_id->name,
- old_id->us,
- old_id->name);
- }
-}
-
-static void lib_relocate_do(bContext *C,
- Library *library,
- WMLinkAppendData *lapp_data,
- ReportList *reports,
- const bool do_reload)
-{
- ListBase *lbarray[INDEX_ID_MAX];
- int lba_idx;
-
- LinkNode *itemlink;
- int item_idx;
-
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- /* Remove all IDs to be reloaded from Main. */
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id = lbarray[lba_idx]->first;
- const short idcode = id ? GS(id->name) : 0;
-
- if (!id || !BKE_idtype_idcode_is_linkable(idcode)) {
- /* No need to reload non-linkable datatypes,
- * those will get relinked with their 'users ID'. */
- continue;
- }
-
- for (; id; id = id->next) {
- if (id->lib == library) {
- WMLinkAppendDataItem *item;
-
- /* We remove it from current Main, and add it to items to link... */
- /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */
- BLI_remlink(lbarray[lba_idx], id);
- /* Usual special code for ShapeKeys snowflakes... */
- Key *old_key = BKE_key_from_id(id);
- if (old_key != NULL) {
- BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
- }
-
- item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id);
- BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries);
-
- CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name);
- }
- }
- }
-
- if (lapp_data->num_items == 0) {
- /* Early out in case there is nothing to do. */
- return;
- }
-
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
-
- /* We do not want any instantiation here! */
- wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL);
-
- BKE_main_lock(bmain);
-
- /* We add back old id to bmain.
- * We need to do this in a first, separated loop, otherwise some of those may not be handled by
- * ID remapping, which means they would still reference old data to be deleted... */
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
-
- BLI_assert(old_id);
- BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id);
-
- /* Usual special code for ShapeKeys snowflakes... */
- Key *old_key = BKE_key_from_id(old_id);
- if (old_key != NULL) {
- BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id);
- }
- }
-
- /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking
- * code is wrong, we need to redo it here after adding them back to main. */
- BKE_main_id_refcount_recompute(bmain, false);
-
- /* Note that in reload case, we also want to replace indirect usages. */
- const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
- ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
- (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
- ID *new_id = item->new_id;
-
- lib_relocate_do_remap(bmain, old_id, new_id, reports, do_reload, remap_flags);
- if (new_id == NULL) {
- continue;
- }
- /* Usual special code for ShapeKeys snowflakes... */
- Key **old_key_p = BKE_key_from_id_p(old_id);
- if (old_key_p == NULL) {
- continue;
- }
- Key *old_key = *old_key_p;
- Key *new_key = BKE_key_from_id(new_id);
- if (old_key != NULL) {
- *old_key_p = NULL;
- id_us_min(&old_key->id);
- lib_relocate_do_remap(bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags);
- *old_key_p = old_key;
- id_us_plus_no_lib(&old_key->id);
- }
- }
-
- BKE_main_unlock(bmain);
-
- for (item_idx = 0, itemlink = lapp_data->items.list; itemlink;
- item_idx++, itemlink = itemlink->next) {
- WMLinkAppendDataItem *item = itemlink->link;
- ID *old_id = item->customdata;
-
- if (old_id->us == 0) {
- BKE_id_free(bmain, old_id);
- }
- }
-
- /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable
- * (shape keys e.g.), so we need another loop here to clear old ones if possible. */
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id, *id_next;
- for (id = lbarray[lba_idx]->first; id; id = id_next) {
- id_next = id->next;
- /* XXX That check may be a bit to generic/permissive? */
- if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) {
- BKE_id_free(bmain, id);
- }
- }
- }
-
- /* Get rid of no more used libraries... */
- BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true);
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id;
- for (id = lbarray[lba_idx]->first; id; id = id->next) {
- if (id->lib) {
- id->lib->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- }
- Library *lib, *lib_next;
- for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) {
- lib_next = lib->id.next;
- if (lib->id.tag & LIB_TAG_DOIT) {
- id_us_clear_real(&lib->id);
- if (lib->id.us == 0) {
- BKE_id_free(bmain, (ID *)lib);
- }
- }
- }
-
- /* Update overrides of reloaded linked data-blocks. */
- ID *id;
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) ||
- (id->tag & LIB_TAG_PRE_EXISTING) == 0) {
- continue;
- }
- if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) {
- BKE_lib_override_library_update(bmain, id);
- }
- }
- FOREACH_MAIN_ID_END;
-
- /* Resync overrides if needed. */
- if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
- BKE_lib_override_library_main_resync(bmain,
- scene,
- view_layer,
- &(struct BlendFileReadReport){
- .reports = reports,
- });
- /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
- BKE_lib_override_library_main_operations_create(bmain, true);
- }
-
- BKE_main_collection_sync(bmain);
-
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* important we unset, otherwise these object won't
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DEG_relations_tag_update(bmain);
-}
-
void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
{
if (!BLO_has_bfile_extension(lib->filepath_abs)) {
@@ -1745,14 +631,34 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
return;
}
- WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS |
- BLO_LIBLINK_FORCE_INDIRECT);
+ Main *bmain = CTX_data_main(C);
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(&lapp_params,
+ bmain,
+ BLO_LIBLINK_USE_PLACEHOLDERS |
+ BLO_LIBLINK_FORCE_INDIRECT,
+ 0,
+ CTX_data_scene(C),
+ CTX_data_view_layer(C),
+ NULL);
- wm_link_append_data_library_add(lapp_data, lib->filepath_abs);
+ BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+
+ BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs, NULL);
+
+ BKE_blendfile_library_relocate(lapp_context, reports, lib, true);
+
+ BKE_blendfile_link_append_context_free(lapp_context);
+
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
- lib_relocate_do(C, lib, lapp_data, reports, true);
+ /* Important we unset, otherwise these object won't link into other scenes from this blend file.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- wm_link_append_data_free(lapp_data);
+ /* Recreate dependency graph to include new IDs. */
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
@@ -1768,7 +674,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
if (lib) {
Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
- WMLinkAppendData *lapp_data;
+ BlendfileLinkAppendContext *lapp_context;
char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
short flag = 0;
@@ -1813,13 +719,17 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
return OPERATOR_CANCELLED;
}
+ LibraryLink_Params lapp_params;
+ BLO_library_link_params_init_with_context(
+ &lapp_params, bmain, flag, 0, CTX_data_scene(C), CTX_data_view_layer(C), NULL);
+
if (BLI_path_cmp(lib->filepath_abs, path) == 0) {
CLOG_INFO(&LOG, 4, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us);
do_reload = true;
- lapp_data = wm_link_append_data_new(flag);
- wm_link_append_data_library_add(lapp_data, path);
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
else {
int totfiles = 0;
@@ -1839,7 +749,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
}
- lapp_data = wm_link_append_data_new(flag);
+ lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
if (totfiles) {
RNA_BEGIN (op->ptr, itemptr, "files") {
@@ -1852,27 +762,39 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path);
- wm_link_append_data_library_add(lapp_data, path);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
RNA_END;
}
else {
CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path);
- wm_link_append_data_library_add(lapp_data, path);
+ BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL);
}
}
if (do_reload) {
- lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT;
+ BKE_blendfile_link_append_context_flag_set(
+ lapp_context, BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT, true);
}
- lib_relocate_do(C, lib, lapp_data, op->reports, do_reload);
+ BKE_blendfile_library_relocate(lapp_context, op->reports, lib, do_reload);
- wm_link_append_data_free(lapp_data);
+ BKE_blendfile_link_append_context_free(lapp_context);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, root, FILE_MAX);
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* Important we unset, otherwise these object won't link into other scenes from this blend
+ * file.
+ */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* Recreate dependency graph to include new IDs. */
+ DEG_relations_tag_update(bmain);
+
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index ab971901a20..47f51214a8e 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -50,7 +50,6 @@
#include "BIF_glutil.h"
-/* context checked on having screen, window and area */
wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent *event, int type)
{
wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture");
@@ -129,7 +128,6 @@ bool WM_gesture_is_modal_first(const wmGesture *gesture)
return (gesture->is_active_prev == false);
}
-/* tweak and line gestures */
int wm_gesture_evaluate(wmGesture *gesture, const wmEvent *event)
{
if (gesture->type == WM_GESTURE_TWEAK) {
@@ -515,7 +513,6 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
immUnbindProgram();
}
-/* called in wm_draw.c */
void wm_gesture_draw(wmWindow *win)
{
wmGesture *gt = (wmGesture *)win->gesture.first;
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 19b678d79d8..8d45d5aed67 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -124,6 +124,7 @@ static int UNUSED_FUNCTION(gesture_modal_state_from_operator)(wmOperator *op)
}
return GESTURE_MODAL_NOP;
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -569,7 +570,6 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
}
}
-/* standard tweak, called after window handlers passed on event */
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
{
wmWindow *win = CTX_wm_window(C);
@@ -750,11 +750,6 @@ void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
gesture_modal_end(C, op);
}
-/**
- * helper function, we may want to add options for conversion to view space
- *
- * caller must free.
- */
const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C),
wmOperator *op,
int *r_mcoords_len))[2]
@@ -889,10 +884,6 @@ int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *e
return OPERATOR_RUNNING_MODAL;
}
-/**
- * This invoke callback starts the straightline gesture with a viewport preview to the right side
- * of the line.
- */
int WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
WM_gesture_straightline_invoke(C, op, event);
@@ -928,11 +919,6 @@ static void wm_gesture_straightline_do_angle_snap(rcti *rect)
rect->ymax = (int)line_snapped_end[1];
}
-/**
- * This modal callback calls exec once per mouse move event while the gesture is active with the
- * updated line start and end values, so it can be used for tools that have a real time preview
- * (like a gradient updating in real time over the mesh).
- */
int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
@@ -1012,13 +998,6 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
-/**
- * This modal one-shot callback only calls exec once after the gesture finishes without any updates
- * during the gesture execution. Should be used for operations that are intended to be applied once
- * without real time preview (like a trimming tool that only applies the bisect operation once
- * after finishing the gesture as the bisect operation is too heavy to be computed in real time for
- * a preview).
- */
int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index c382af03c4a..2f87e5789fe 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -223,10 +223,6 @@ static void sound_jack_sync_callback(Main *bmain, int mode, double time)
}
}
-/**
- * Initialize Blender and load the startup file & preferences
- * (only called once).
- */
void WM_init(bContext *C, int argc, const char **argv)
{
@@ -318,9 +314,9 @@ void WM_init(bContext *C, int argc, const char **argv)
NULL,
&params_file_read_post);
- /* NOTE: leave `G_MAIN->name` set to an empty string since this
+ /* NOTE: leave `G_MAIN->filepath` set to an empty string since this
* matches behavior after loading a new file. */
- BLI_assert(G_MAIN->name[0] == '\0');
+ BLI_assert(G_MAIN->filepath[0] == '\0');
/* Call again to set from preferences. */
BLT_lang_set(NULL);
@@ -432,10 +428,6 @@ static int wm_exit_handler(bContext *C, const wmEvent *event, void *userdata)
return WM_UI_HANDLER_BREAK;
}
-/**
- * Cause a delayed #WM_exit()
- * call to avoid leaking memory when trying to exit from within operators.
- */
void wm_exit_schedule_delayed(const bContext *C)
{
/* What we do here is a little bit hacky, but quite simple and doesn't require bigger
@@ -449,9 +441,6 @@ void wm_exit_schedule_delayed(const bContext *C)
WM_event_add_mousemove(win); /* ensure handler actually gets called */
}
-/**
- * \note doesn't run exit() call #WM_exit() for that.
- */
void WM_exit_ex(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
@@ -547,6 +536,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
RE_engines_exit();
ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
+ ED_preview_restart_queue_free();
ED_assetlist_storage_exit();
if (wm) {
@@ -655,11 +645,6 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_tempdir_session_purge();
}
-/**
- * \brief Main exit function to close Blender ordinarily.
- * \note Use #wm_exit_schedule_delayed() to close Blender from an operator.
- * Might leak memory otherwise.
- */
void WM_exit(bContext *C)
{
WM_exit_ex(C, true);
@@ -677,10 +662,6 @@ void WM_exit(bContext *C)
exit(G.is_break == true);
}
-/**
- * Needed for cases when operators are re-registered
- * (when operator type pointers are stored).
- */
void WM_script_tag_reload(void)
{
UI_interface_tag_script_reload();
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index 2604105896d..66277ec57f4 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -187,12 +187,6 @@ static wmJob *wm_job_find(const wmWindowManager *wm, const void *owner, const in
/* ******************* public API ***************** */
-/**
- * \return current job or adds new job, but doesn't run it.
- *
- * \note every owner only gets a single job,
- * adding a new one will stop running job and when stopped it starts the new one.
- */
wmJob *WM_jobs_get(wmWindowManager *wm,
wmWindow *win,
const void *owner,
@@ -223,7 +217,6 @@ wmJob *WM_jobs_get(wmWindowManager *wm,
return wm_job;
}
-/* returns true if job runs, for UI (progress) indicators */
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
{
/* job can be running or about to run (suspended) */
@@ -281,7 +274,6 @@ static void wm_jobs_update_progress_bars(wmWindowManager *wm)
}
}
-/* time that job started */
double WM_jobs_starttime(const wmWindowManager *wm, const void *owner)
{
const wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
@@ -447,10 +439,6 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
#endif
}
-/**
- * if job running, the same owner gave it a new job.
- * if different owner starts existing startjob, it suspends itself
- */
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
{
if (wm_job->running) {
@@ -550,7 +538,6 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
}
}
-/* wait until every job ended */
void WM_jobs_kill_all(wmWindowManager *wm)
{
wmJob *wm_job;
@@ -563,7 +550,6 @@ void WM_jobs_kill_all(wmWindowManager *wm)
SEQ_prefetch_stop_all();
}
-/* wait until every job ended, except for one owner (used in undo to keep screen job alive) */
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
{
LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
@@ -584,7 +570,6 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_ty
}
}
-/* signal job(s) from this owner or callback to stop, timer is required to get handled */
void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob)
{
LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
@@ -596,7 +581,6 @@ void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob)
}
}
-/* actually terminate thread and job timer */
void WM_jobs_kill(wmWindowManager *wm,
void *owner,
void (*startjob)(void *, short int *, short int *, float *))
@@ -608,7 +592,6 @@ void WM_jobs_kill(wmWindowManager *wm,
}
}
-/* kill job entirely, also removes timer itself */
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
{
LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
@@ -619,7 +602,6 @@ void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
}
}
-/* hardcoded to event TIMERJOBS */
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
{
LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 35f6ce40dba..0214fce59b2 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -189,7 +189,6 @@ static bool wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b)
(a->flag & KMI_REPEAT_IGNORE) == (b->flag & KMI_REPEAT_IGNORE)));
}
-/* properties can be NULL, otherwise the arg passed is used and ownership is given to the kmi */
void WM_keymap_item_properties_reset(wmKeyMapItem *kmi, struct IDProperty *properties)
{
if (LIKELY(kmi->ptr)) {
@@ -514,7 +513,6 @@ static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
}
}
-/* always add item */
wmKeyMapItem *WM_keymap_add_item(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -1150,7 +1148,6 @@ const char *WM_key_event_string(const short type, const bool compact)
return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name);
}
-/* TODO: also support (some) value, like e.g. double-click? */
int WM_keymap_item_raw_to_string(const short shift,
const short ctrl,
const short alt,
@@ -1162,6 +1159,8 @@ int WM_keymap_item_raw_to_string(const short shift,
char *result,
const int result_len)
{
+ /* TODO: also support (some) value, like e.g. double-click? */
+
#define ADD_SEP \
if (p != buf) { \
*p++ = ' '; \
@@ -1307,6 +1306,10 @@ char *WM_modalkeymap_operator_items_to_string_buf(wmOperatorType *ot,
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Keymap Finding Utilities
+ * \{ */
+
static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap,
const char *opname,
IDProperty *properties,
@@ -1676,10 +1679,6 @@ static bool kmi_filter_is_visible_type_mask(const wmKeyMap *km,
kmi_filter_is_visible(km, kmi, user_data));
}
-/**
- * \param include_mask, exclude_mask:
- * Event types to include/exclude when looking up keys (#eEventType_Mask).
- */
wmKeyMapItem *WM_key_event_operator(const bContext *C,
const char *opname,
wmOperatorCallContext opcontext,
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 795f78e215f..d424eef8262 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -43,7 +43,6 @@
/** \name Wrappers for #WM_keymap_add_item
* \{ */
-/* menu wrapper for WM_keymap_add_item */
wmKeyMapItem *WM_keymap_add_menu(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -73,7 +72,6 @@ wmKeyMapItem *WM_keymap_add_panel(
return kmi;
}
-/* tool wrapper for WM_keymap_add_item */
wmKeyMapItem *WM_keymap_add_tool(
wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
@@ -83,7 +81,6 @@ wmKeyMapItem *WM_keymap_add_tool(
return kmi;
}
-/** Useful for mapping numbers to an enum. */
void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
const EnumPropertyItem *items,
const char *data_path,
@@ -203,8 +200,6 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C)
return km;
}
-/* Guess an appropriate keymap from the operator name */
-/* Needs to be kept up to date with Keymap and Operator naming */
wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
{
/* Op types purposely skipped for now:
diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c
index bcaa2243f9f..799b6fc2e52 100644
--- a/source/blender/windowmanager/intern/wm_menu_type.c
+++ b/source/blender/windowmanager/intern/wm_menu_type.c
@@ -77,7 +77,6 @@ void WM_menutype_freelink(MenuType *mt)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_menutype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 898671706d1..a5887fc07b3 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -72,7 +72,6 @@ static const EnumPropertyItem *wm_operator_properties_filesel_sort_items_itemf(
return items;
}
-/* default properties for fileselect */
void WM_operator_properties_filesel(wmOperatorType *ot,
int filter,
short type,
@@ -262,9 +261,6 @@ void WM_operator_properties_select_action(wmOperatorType *ot, int default_action
wm_operator_properties_select_action_ex(ot, default_action, select_actions, hide_gui);
}
-/**
- * only SELECT/DESELECT
- */
void WM_operator_properties_select_action_simple(wmOperatorType *ot,
int default_action,
bool hide_gui)
@@ -278,10 +274,6 @@ void WM_operator_properties_select_action_simple(wmOperatorType *ot,
wm_operator_properties_select_action_ex(ot, default_action, select_actions, hide_gui);
}
-/**
- * Use for all select random operators.
- * Adds properties: percent, seed, action.
- */
void WM_operator_properties_select_random(wmOperatorType *ot)
{
RNA_def_float_factor(ot->srna,
@@ -357,9 +349,6 @@ void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
BLI_rctf_rcti_copy(rect, &rect_i);
}
-/**
- * Use with #WM_gesture_box_invoke
- */
void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bool extend)
{
PropertyRNA *prop;
@@ -381,10 +370,6 @@ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bo
}
}
-/**
- * Disable using cursor position,
- * use when view operators are initialized from buttons.
- */
void WM_operator_properties_use_cursor_init(wmOperatorType *ot)
{
PropertyRNA *prop = RNA_def_boolean(ot->srna,
@@ -418,7 +403,6 @@ void WM_operator_properties_select_operation(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Some tools don't support XOR/AND. */
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
{
static const EnumPropertyItem select_mode_items[] = {
@@ -450,31 +434,6 @@ void WM_operator_properties_select_walk_direction(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/**
- * Selecting and tweaking items are overlapping operations. Getting both to work without conflicts
- * requires special care. See
- * https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking for the
- * desired behavior.
- *
- * For default click selection (with no modifier keys held), the select operators can do the
- * following:
- * - On a mouse press on an unselected item, change selection and finish immediately after.
- * This sends an undo push and allows transform to take over should a tweak event be caught now.
- * - On a mouse press on a selected item, don't change selection state, but start modal execution
- * of the operator. Idea is that we wait with deselecting other items until we know that the
- * intention wasn't to tweak (mouse press+drag) all selected items.
- * - If a tweak is recognized before the release event happens, cancel the operator, so that
- * transform can take over and no undo-push is sent.
- * - If the release event occurs rather than a tweak one, deselect all items but the one under the
- * cursor, and finish the modal operator.
- *
- * This utility, together with #WM_generic_select_invoke() and #WM_generic_select_modal() should
- * help getting the wanted behavior to work. Most generic logic should be handled in these, so that
- * the select operators only have to care for the case dependent handling.
- *
- * Every select operator has slightly different requirements, e.g. sequencer strip selection
- * also needs to account for handle selection. This should be the baseline behavior though.
- */
void WM_operator_properties_generic_select(wmOperatorType *ot)
{
/* On the initial mouse press, this is set by #WM_generic_select_modal() to let the select
@@ -499,9 +458,6 @@ void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/**
- * Use with #WM_gesture_lasso_invoke
- */
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -509,9 +465,6 @@ void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/**
- * Use with #WM_gesture_straightline_invoke
- */
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
{
PropertyRNA *prop;
@@ -541,9 +494,6 @@ void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
}
}
-/**
- * Use with #WM_gesture_circle_invoke
- */
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -582,9 +532,6 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/**
- * \param nth_can_disable: Enable if we want to be able to select no interval at all.
- */
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)
{
const int nth_default = nth_can_disable ? 0 : 1;
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 0e30df4ec99..0f6096e7b8b 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -89,7 +89,6 @@ wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
return NULL;
}
-/* caller must free */
void WM_operatortype_iter(GHashIterator *ghi)
{
BLI_ghashIterator_init(ghi, global_ops_hash);
@@ -132,7 +131,8 @@ static void wm_operatortype_append__end(wmOperatorType *ot)
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
-/* all ops in 1 list (for time being... needs evaluation later) */
+/* All ops in 1 list (for time being... needs evaluation later). */
+
void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
{
wmOperatorType *ot = wm_operatortype_append__begin();
@@ -149,7 +149,6 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
/** \} */
-/* called on initialize WM_exit() */
void WM_operatortype_remove_ptr(wmOperatorType *ot)
{
BLI_assert(ot == WM_operatortype_find(ot->idname, false));
@@ -184,7 +183,6 @@ bool WM_operatortype_remove(const char *idname)
return true;
}
-/* called on initialize WM_init() */
void wm_operatortype_init(void)
{
/* reserve size is set based on blender default setup */
@@ -215,18 +213,6 @@ void wm_operatortype_free(void)
global_ops_hash = NULL;
}
-/**
- * Tag all operator-properties of \a ot defined after calling this, until
- * the next #WM_operatortype_props_advanced_end call (if available), with
- * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
- *
- * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
- * all calls after the first one are ignored. Meaning all proprieties defined after the
- * first call are tagged as advanced.
- *
- * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
- * called for all operators during registration (see #wm_operatortype_append__end).
- */
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
{
if (ot_prop_basic_count == -1) {
@@ -235,14 +221,6 @@ void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
}
}
-/**
- * Tags all operator-properties of \a ot defined since the first
- * #WM_operatortype_props_advanced_begin call,
- * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
- *
- * \note This is called for all operators during registration (see #wm_operatortype_append__end).
- * So it does not need to be explicitly called in operator-type definition.
- */
void WM_operatortype_props_advanced_end(wmOperatorType *ot)
{
PointerRNA struct_ptr;
@@ -266,9 +244,6 @@ void WM_operatortype_props_advanced_end(wmOperatorType *ot)
ot_prop_basic_count = -1;
}
-/**
- * Remove memory of all previously executed tools.
- */
void WM_operatortype_last_properties_clear_all(void)
{
GHashIterator iter;
@@ -471,7 +446,6 @@ static void wm_macro_cancel(bContext *C, wmOperator *op)
wm_macro_end(op, OPERATOR_CANCELLED);
}
-/* Names have to be static for now */
wmOperatorType *WM_operatortype_append_macro(const char *idname,
const char *name,
const char *description,
@@ -613,9 +587,6 @@ char *WM_operatortype_description(struct bContext *C,
return NULL;
}
-/**
- * Use when we want a label, preferring the description.
- */
char *WM_operatortype_description_or_name(struct bContext *C,
struct wmOperatorType *ot,
struct PointerRNA *properties)
diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c
index 85a0a28de79..dbcfd814692 100644
--- a/source/blender/windowmanager/intern/wm_operator_utils.c
+++ b/source/blender/windowmanager/intern/wm_operator_utils.c
@@ -44,9 +44,6 @@
/** \name Generic Utilities
* \{ */
-/**
- * Only finish + pass through for press events (allowing press-tweak).
- */
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event)
{
if ((event->val != KM_PRESS) &&
@@ -337,10 +334,6 @@ static int op_generic_value_modal(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
-/**
- * Allow an operator with only and execute function to run modally,
- * re-doing the action, using vertex coordinate store/restore instead of operator undo.
- */
void WM_operator_type_modal_from_exec_for_object_edit_coords(wmOperatorType *ot)
{
PropertyRNA *prop;
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index ffdc99152b1..6c9b0af5186 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -116,13 +116,10 @@
#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
-/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Operator API
* \{ */
-/* SOME_OT_op -> some.op */
void WM_operator_py_idname(char *to, const char *from)
{
const char *sep = strstr(from, "_OT_");
@@ -143,7 +140,6 @@ void WM_operator_py_idname(char *to, const char *from)
}
}
-/* some.op -> SOME_OT_op */
void WM_operator_bl_idname(char *to, const char *from)
{
if (from) {
@@ -167,10 +163,6 @@ void WM_operator_bl_idname(char *to, const char *from)
}
}
-/**
- * Sanity check to ensure #WM_operator_bl_idname won't fail.
- * \returns true when there are no problems with \a idname, otherwise report an error.
- */
bool WM_operator_py_idname_ok_or_report(ReportList *reports,
const char *classname,
const char *idname)
@@ -219,15 +211,6 @@ bool WM_operator_py_idname_ok_or_report(ReportList *reports,
return true;
}
-/**
- * Print a string representation of the operator,
- * with the args that it runs so python can run it again.
- *
- * When calling from an existing wmOperator, better to use simple version:
- * `WM_operator_pystring(C, op);`
- *
- * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
- */
char *WM_operator_pystring_ex(bContext *C,
wmOperator *op,
const bool all_args,
@@ -308,9 +291,6 @@ char *WM_operator_pystring(bContext *C, wmOperator *op, const bool all_args, con
return WM_operator_pystring_ex(C, op, all_args, macro_args, op->type, op->ptr);
}
-/**
- * \return true if the string was shortened
- */
bool WM_operator_pystring_abbreviate(char *str, int str_len_max)
{
const int str_len = strlen(str);
@@ -608,9 +588,6 @@ static const char *wm_context_member_from_ptr(const bContext *C,
}
#endif
-/**
- * Calculate the path to `ptr` from context `C`, or return NULL if it can't be calculated.
- */
char *WM_context_path_resolve_property_full(const bContext *C,
const PointerRNA *ptr,
PropertyRNA *prop,
@@ -711,8 +688,6 @@ void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
}
}
-/* similar to the function above except its uses ID properties
- * used for keymaps and macros */
void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
{
IDProperty *tmp_properties = NULL;
@@ -763,14 +738,6 @@ void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
RNA_STRUCT_END;
}
-/**
- * Set all props to their default.
- *
- * \param do_update: Only update un-initialized props.
- *
- * \note There's nothing specific to operators here.
- * This could be made a general function.
- */
bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
{
bool changed = false;
@@ -798,7 +765,6 @@ bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
return changed;
}
-/* remove all props without PROP_SKIP_SAVE */
void WM_operator_properties_reset(wmOperator *op)
{
if (op->ptr->data) {
@@ -945,13 +911,6 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
/** \name Default Operator Callbacks
* \{ */
-/**
- * Helper to get select and tweak-transform to work conflict free and as desired. See
- * #WM_operator_properties_generic_select() for details.
- *
- * To be used together with #WM_generic_select_invoke() and
- * #WM_operator_properties_generic_select().
- */
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr,
@@ -1012,13 +971,6 @@ int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
}
-/**
- * Helper to get select and tweak-transform to work conflict free and as desired. See
- * #WM_operator_properties_generic_select() for details.
- *
- * To be used together with #WM_generic_select_modal() and
- * #WM_operator_properties_generic_select().
- */
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
@@ -1063,7 +1015,6 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op)
return (op->flag & OP_IS_INVOKE) ? U.smooth_viewtx : 0;
}
-/* invoke callback, uses enum property named "type" */
int WM_menu_invoke_ex(bContext *C, wmOperator *op, wmOperatorCallContext opcontext)
{
PropertyRNA *prop = op->type->prop;
@@ -1184,10 +1135,6 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *region, void *arg)
return block;
}
-/**
- * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
- * be used as invoke callback directly since it needs additional info.
- */
int WM_enum_search_invoke_previews(bContext *C, wmOperator *op, short prv_cols, short prv_rows)
{
static struct EnumSearchMenu search_menu;
@@ -1210,7 +1157,6 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(eve
return OPERATOR_INTERFACE;
}
-/* Can't be used as an invoke directly, needs message arg (can be NULL) */
int WM_operator_confirm_message_ex(bContext *C,
wmOperator *op,
const char *title,
@@ -1255,7 +1201,6 @@ int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *UNUS
return op->type->exec(C, op);
}
-/* op->invoke, opens fileselect if path property not set, otherwise executes */
int WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
@@ -1280,7 +1225,6 @@ bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFor
return false;
}
-/* op->poll */
bool WM_operator_winactive(bContext *C)
{
if (CTX_wm_window(C) == NULL) {
@@ -1289,7 +1233,6 @@ bool WM_operator_winactive(bContext *C)
return 1;
}
-/* return false, if the UI should be disabled */
bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1327,9 +1270,6 @@ void WM_operator_last_properties_ensure(wmOperatorType *ot, PointerRNA *ptr)
RNA_pointer_create(G_MAIN->wm.first, ot->srna, props, ptr);
}
-/**
- * Use for drag & drop a path or name with operators invoke() function.
- */
ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short idcode)
{
Main *bmain = CTX_data_main(C);
@@ -1633,20 +1573,11 @@ static int wm_operator_props_popup_ex(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
-/**
- * Same as #WM_operator_props_popup but don't use operator redo.
- * just wraps #WM_operator_props_dialog_popup.
- */
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, false, false);
}
-/**
- * Same as #WM_operator_props_popup but call the operator first,
- * This way - the button values correspond to the result of the operator.
- * Without this, first access to a button will make the result jump, see T32452.
- */
int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, true, true);
@@ -3999,7 +3930,6 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
}
-/* default keymap for windows and screens, only call once per WM */
void wm_window_keymap(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "Window", 0, 0);
@@ -4067,7 +3997,8 @@ static const EnumPropertyItem *rna_id_itemf(bool *r_free,
return item;
}
-/* can add more as needed */
+/* Can add more ID types as needed. */
+
const EnumPropertyItem *RNA_action_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
diff --git a/source/blender/windowmanager/intern/wm_panel_type.c b/source/blender/windowmanager/intern/wm_panel_type.c
index 24508c377a6..609bb55e075 100644
--- a/source/blender/windowmanager/intern/wm_panel_type.c
+++ b/source/blender/windowmanager/intern/wm_panel_type.c
@@ -69,7 +69,6 @@ void WM_paneltype_remove(PanelType *pt)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_paneltype_init(void)
{
/* reserve size is set based on blender default setup */
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 16a17484f4f..a62ced1a4bf 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -177,10 +177,6 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return true;
}
-/**
- * If needed, adjust \a r_mouse_xy
- * so that drawn cursor and handled mouse position are matching visually.
- */
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2])
{
if (!WM_stereo3d_enabled(win, false)) {
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 0cb76404258..524580ac88f 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -116,7 +116,6 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs)
wmOrtho2(ofs, x + ofs, ofs, y + ofs);
}
-/* Default pixel alignment for regions. */
void wmOrtho2_region_pixelspace(const ARegion *region)
{
wmOrtho2_offset(region->winx, region->winy, -0.01f);
diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c
index 715f72d70cf..385b55f36f9 100644
--- a/source/blender/windowmanager/intern/wm_surface.c
+++ b/source/blender/windowmanager/intern/wm_surface.c
@@ -45,11 +45,24 @@ static wmSurface *g_drawable = NULL;
void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *))
{
- LISTBASE_FOREACH (wmSurface *, surf, &global_surface_list) {
+ /* Mutable iterator in case a surface is freed. */
+ LISTBASE_FOREACH_MUTABLE (wmSurface *, surf, &global_surface_list) {
cb(C, surf);
}
}
+static void wm_surface_do_depsgraph_fn(bContext *C, wmSurface *surface)
+{
+ if (surface->do_depsgraph) {
+ surface->do_depsgraph(C);
+ }
+}
+
+void wm_surfaces_do_depsgraph(bContext *C)
+{
+ wm_surfaces_iter(C, wm_surface_do_depsgraph_fn);
+}
+
void wm_surface_clear_drawable(void)
{
if (g_drawable) {
@@ -107,6 +120,9 @@ void wm_surface_add(wmSurface *surface)
void wm_surface_remove(wmSurface *surface)
{
+ if (surface == g_drawable) {
+ wm_surface_clear_drawable();
+ }
BLI_remlink(&global_surface_list, surface);
surface->free_data(surface);
MEM_freeN(surface);
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index 3ac1a7c0be1..7b8feac45b4 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -251,7 +251,6 @@ void WM_toolsystem_reinit(bContext *C, WorkSpace *workspace, const bToolKey *tke
}
}
-/* Operate on all active tools. */
void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace)
{
LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
@@ -362,12 +361,6 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C,
}
}
-/**
- * Sync the internal active state of a tool back into the tool system,
- * this is needed for active brushes where the real active state is not stored in the tool system.
- *
- * \see #toolsystem_ref_link
- */
void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToolRef *tref)
{
bToolRef_Runtime *tref_rt = tref->runtime;
@@ -505,14 +498,6 @@ bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *area, bToolK
return false;
}
-/**
- * Use to update the active tool (shown in the top bar) in the least disruptive way.
- *
- * This is a little involved since there may be multiple valid active tools
- * depending on the mode and space type.
- *
- * Used when undoing since the active mode may have changed.
- */
void WM_toolsystem_refresh_active(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -800,16 +785,12 @@ void WM_toolsystem_update_from_context(bContext *C,
}
}
-/**
- * For paint modes to support non-brush tools.
- */
bool WM_toolsystem_active_tool_is_brush(const bContext *C)
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
return tref_rt && (tref_rt->data_block[0] != '\0');
}
-/* Follow wmMsgNotifyFn spec */
void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C,
wmMsgSubscribeKey *UNUSED(msg_key),
wmMsgSubscribeValue *msg_val)
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c
index 82ba4aa6e6f..a2ae42d5ead 100644
--- a/source/blender/windowmanager/intern/wm_uilist_type.c
+++ b/source/blender/windowmanager/intern/wm_uilist_type.c
@@ -131,7 +131,6 @@ void WM_uilisttype_remove_ptr(Main *bmain, uiListType *ult)
UNUSED_VARS_NDEBUG(ok);
}
-/* called on initialize WM_init() */
void WM_uilisttype_init(void)
{
uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16);
@@ -151,16 +150,6 @@ void WM_uilisttype_free(void)
uilisttypes_hash = NULL;
}
-/**
- * The "full" list-ID is an internal name used for storing and identifying a list. It is built like
- * this:
- * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to
- * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_".
- *
- * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it
- * passed to `UILayout.template_list()`. C code can query that through
- * #WM_uilisttype_list_id_get().
- */
void WM_uilisttype_to_full_list_id(const uiListType *ult,
const char *list_id,
char r_full_list_id[/*UI_MAX_NAME_STR*/])
@@ -169,11 +158,6 @@ void WM_uilisttype_to_full_list_id(const uiListType *ult,
BLI_snprintf(r_full_list_id, UI_MAX_NAME_STR, "%s_%s", ult->idname, list_id ? list_id : "");
}
-/**
- * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details.
- *
- * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()!
- */
const char *WM_uilisttype_list_id_get(const uiListType *ult, uiList *list)
{
/* Some sanity check for the assumed behavior of #WM_uilisttype_to_full_list_id(). */
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 5f684a752d8..29c9f53f735 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -136,8 +136,6 @@ static struct WMInitStruct {
static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
static bool wm_window_timer(const bContext *C);
-/* XXX this one should correctly check for apple top header...
- * done for Cocoa : returns window contents (and not frame) max size. */
void wm_get_screensize(int *r_width, int *r_height)
{
unsigned int uiwidth;
@@ -148,7 +146,6 @@ void wm_get_screensize(int *r_width, int *r_height)
*r_height = uiheight;
}
-/* size of all screens (desktop), useful since the mouse is bound by this */
void wm_get_desktopsize(int *r_width, int *r_height)
{
unsigned int uiwidth;
@@ -198,8 +195,6 @@ static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
}
}
-/* including window itself, C can be NULL.
- * ED_screen_exit should have been called */
void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
{
/* update context */
@@ -260,7 +255,6 @@ static int find_free_winid(wmWindowManager *wm)
return id;
}
-/* don't change context itself */
wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog)
{
wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
@@ -276,7 +270,6 @@ wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent
return win;
}
-/* part of wm_window.c api */
wmWindow *wm_window_copy(Main *bmain,
wmWindowManager *wm,
wmWindow *win_src,
@@ -307,10 +300,6 @@ wmWindow *wm_window_copy(Main *bmain,
return win_dst;
}
-/**
- * A higher level version of copy that tests the new window can be added.
- * (called from the operator directly)
- */
wmWindow *wm_window_copy_test(bContext *C,
wmWindow *win_src,
const bool duplicate_layout,
@@ -353,13 +342,6 @@ static void wm_confirm_quit(bContext *C)
wm_close_file_dialog(C, action);
}
-/**
- * Call the quit confirmation prompt or exit directly if needed. The use can
- * still cancel via the confirmation popup. Also, this may not quit Blender
- * immediately, but rather schedule the closing.
- *
- * \param win: The window to show the confirmation popup/window in.
- */
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
{
wmWindow *win_ctx = CTX_wm_window(C);
@@ -387,7 +369,6 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
/** \} */
-/* this is event from ghost, or exit-blender op */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
wmWindow *win_other;
@@ -447,13 +428,14 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
else if (win->ghostwin) {
/* this is set to 1 if you don't have startup.blend open */
- if (G.save_over && BKE_main_blendfile_path_from_global()[0]) {
- char str[sizeof(((Main *)NULL)->name) + 24];
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') {
+ char str[sizeof(((Main *)NULL)->filepath) + 24];
BLI_snprintf(str,
sizeof(str),
"Blender%s [%s%s]",
wm->file_saved ? "" : "*",
- BKE_main_blendfile_path_from_global(),
+ blendfile_path,
G_MAIN->recovered ? " (Recovered)" : "");
GHOST_SetTitle(win->ghostwin, str);
}
@@ -679,19 +661,6 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo
ED_screen_global_areas_refresh(win);
}
-/**
- * Initialize #wmWindow without ghostwin, open these and clear.
- *
- * window size is read from window, if 0 it uses prefsize
- * called in #WM_check, also inits stuff after file read.
- *
- * \warning
- * After running, 'win->ghostwin' can be NULL in rare cases
- * (where OpenGL driver fails to create a context for eg).
- * We could remove them with #wm_window_ghostwindows_remove_invalid
- * but better not since caller may continue to use.
- * Instead, caller needs to handle the error case and cleanup.
- */
void wm_window_ghostwindows_ensure(wmWindowManager *wm)
{
BLI_assert(G.background == false);
@@ -715,10 +684,6 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
}
}
-/**
- * Call after #wm_window_ghostwindows_ensure or #WM_check
- * (after loading a new file) in the unlikely event a window couldn't be created.
- */
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
{
BLI_assert(G.background == false);
@@ -756,14 +721,6 @@ static bool wm_window_update_size_position(wmWindow *win)
return false;
}
-/**
- * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type)
- * \param toplevel: Not a child owned by other windows. A peer of main window.
- * \param dialog: whether this should be made as a dialog-style window
- * \param temp: whether this is considered a short-lived window
- * \param alignment: how this window is positioned relative to its parent
- * \return the window or NULL in case of failure.
- */
wmWindow *WM_window_open(bContext *C,
const char *title,
int x,
@@ -952,7 +909,6 @@ int wm_window_new_main_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* fullscreen operator callback */
int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *window = CTX_wm_window(C);
@@ -1083,7 +1039,6 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
}
}
-/* Reset active the current window opengl drawing context. */
void wm_window_reset_drawable(void)
{
BLI_assert(BLI_thread_is_main());
@@ -1585,10 +1540,6 @@ void wm_window_process_events(const bContext *C)
/** \name Ghost Init/Exit
* \{ */
-/**
- * \note #bContext can be null in background mode because we don't
- * need to event handling.
- */
void wm_ghost_init(bContext *C)
{
if (!g_system) {
@@ -1627,7 +1578,6 @@ void wm_ghost_exit(void)
/** \name Event Timer
* \{ */
-/* to (de)activate running timers temporary */
void WM_event_timer_sleep(wmWindowManager *wm,
wmWindow *UNUSED(win),
wmTimer *timer,
@@ -1769,19 +1719,11 @@ static char *wm_clipboard_text_get_ex(bool selection, int *r_len, bool firstline
return newbuf;
}
-/**
- * Return text from the clipboard.
- *
- * \note Caller needs to check for valid utf8 if this is a requirement.
- */
char *WM_clipboard_text_get(bool selection, int *r_len)
{
return wm_clipboard_text_get_ex(selection, r_len, false);
}
-/**
- * Convenience function for pasting to areas of Blender which don't support newlines.
- */
char *WM_clipboard_text_get_firstline(bool selection, int *r_len)
{
return wm_clipboard_text_get_ex(selection, r_len, true);
@@ -1890,9 +1832,6 @@ void wm_window_raise(wmWindow *win)
/** \name Window Buffers
* \{ */
-/**
- * \brief Push rendered buffer to the screen.
- */
void wm_window_swap_buffers(wmWindow *win)
{
GHOST_SwapWindowBuffers(win->ghostwin);
@@ -1913,6 +1852,7 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
/* -------------------------------------------------------------------- */
/** \name Find Window Utility
* \{ */
+
static void wm_window_desktop_pos_get(const wmWindow *win,
const int screen_pos[2],
int r_desk_pos[2])
@@ -2034,7 +1974,6 @@ uint *WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2])
/** \name Initial Window State API
* \{ */
-/* called whem no ghost system was initialized */
void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
{
wm_init_state.start_x = stax; /* left hand pos */
@@ -2044,7 +1983,6 @@ void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
wm_init_state.override_flag |= WIN_OVERRIDE_GEOM;
}
-/* for borderless and border windows set from command-line */
void WM_init_state_fullscreen_set(void)
{
wm_init_state.windowstate = GHOST_kWindowStateFullScreen;
@@ -2097,7 +2035,6 @@ void WM_init_tablet_api(void)
}
}
-/* This function requires access to the GHOST_SystemHandle (g_system) */
void WM_cursor_warp(wmWindow *win, int x, int y)
{
if (win && win->ghostwin) {
@@ -2114,9 +2051,6 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
}
}
-/**
- * Set x, y to values we can actually position the cursor to.
- */
void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
@@ -2132,11 +2066,6 @@ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
/** \name Window Size (public)
* \{ */
-/**
- * Support for native pixel size
- *
- * \note macOS retina opens window in size X, but it has up to 2 x more pixels.
- */
int WM_window_pixels_x(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
@@ -2150,17 +2079,10 @@ int WM_window_pixels_y(const wmWindow *win)
return (int)(f * (float)win->sizey);
}
-/**
- * Get boundaries usable by all window contents, including global areas.
- */
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
{
BLI_rcti_init(r_rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win));
}
-/**
- * Get boundaries usable by screen-layouts, excluding global areas.
- * \note Depends on U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
- */
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
{
rcti window_rect, screen_rect;
@@ -2210,11 +2132,6 @@ bool WM_window_is_maximized(const wmWindow *win)
/** \name Window Screen/Scene/WorkSpaceViewLayer API
* \{ */
-/**
- * Some editor data may need to be synced with scene data (3D View camera and layers).
- * This function ensures data is synced for editors
- * in visible workspaces and their visible layouts.
- */
void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
{
LISTBASE_FOREACH (wmWindow *, win, win_lb) {
@@ -2261,9 +2178,6 @@ Scene *WM_window_get_active_scene(const wmWindow *win)
return win->scene;
}
-/**
- * \warning Only call outside of area/region loops
- */
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2376,9 +2290,6 @@ void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceL
BKE_workspace_active_layout_set(win->workspace_hook, win->winid, workspace, layout);
}
-/**
- * Get the active screen of the active workspace in \a win.
- */
bScreen *WM_window_get_active_screen(const wmWindow *win)
{
const WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -2481,4 +2392,5 @@ void WM_ghost_show_message_box(const char *title,
BLI_assert(g_system);
GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options);
}
+
/** \} */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
index 86a106462c3..81ef8c881f5 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
@@ -147,16 +147,6 @@ void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
// printf("msgbus: keys=%u values=%u\n", a, b);
}
-/**
- * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
- * - msg.params
- * - msg.head.type
- * - msg.head.id
- * .. other values should be zeroed.
- *
- * \return The key for this subscription.
- * note that this is only needed in rare cases when the key needs further manipulation.
- */
wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus,
const wmMsgSubscribeKey *msg_key_test,
const wmMsgSubscribeValue *msg_val_params)
@@ -239,9 +229,6 @@ void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
* \note While we could have a separate type for ID's, use RNA since there is enough overlap.
* \{ */
-/**
- * \note #wmMsgBus.messages_tag_count isn't updated, caller must handle.
- */
void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
{
if (msg_lnk->params.free_data) {
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
index 24c0192fe14..18df17c3d1c 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
@@ -30,6 +30,9 @@ struct wmMsgBus {
uint messages_tag_count;
};
+/**
+ * \note #wmMsgBus.messages_tag_count isn't updated, caller must handle.
+ */
void wm_msg_subscribe_value_free(struct wmMsgSubscribeKey *msg_key,
struct wmMsgSubscribeValueLink *msg_lnk);
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
index 460dca57e4f..bc083793395 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
@@ -35,7 +35,9 @@
#include "RNA_access.h"
-/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
BLI_INLINE uint void_hash_uint(const void *key)
{
@@ -208,7 +210,11 @@ void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_RNA);
}
-/* -------------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA API
+ * \{ */
wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(struct wmMsgBus *mbus,
const wmMsgParams_RNA *msg_key_params)
diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h
index 7ae356cf806..7ee2e5b6ee6 100644
--- a/source/blender/windowmanager/message_bus/wm_message_bus.h
+++ b/source/blender/windowmanager/message_bus/wm_message_bus.h
@@ -79,7 +79,7 @@ typedef struct wmMsg {
} wmMsg;
typedef struct wmMsgSubscribeKey {
- /** Linked list for predicable ordering, otherwise we would depend on ghash bucketing. */
+ /** Linked list for predicable ordering, otherwise we would depend on #GHash bucketing. */
struct wmMsgSubscribeKey *next, *prev;
ListBase values;
/* over-alloc, eg: wmMsgSubscribeKey_RNA */
@@ -124,6 +124,16 @@ void WM_msg_dump(struct wmMsgBus *mbus, const char *info);
void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C);
void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key);
+/**
+ * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
+ * - `msg.params`
+ * - `msg.head.type`
+ * - `msg.head.id`
+ * .. other values should be zeroed.
+ *
+ * \return The key for this subscription.
+ * note that this is only needed in rare cases when the key needs further manipulation.
+ */
wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus,
const wmMsgSubscribeKey *msg_key_test,
const wmMsgSubscribeValue *msg_val_params);
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index cfef70b7dcc..e67b1581875 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -43,49 +43,98 @@ typedef struct wmPaintCursor {
short region_type;
} wmPaintCursor;
+/**
+ * Cause a delayed #WM_exit()
+ * call to avoid leaking memory when trying to exit from within operators.
+ */
void wm_exit_schedule_delayed(const bContext *C);
+/**
+ * Context is allowed to be NULL, do not free wm itself (lib_id.c).
+ */
extern void wm_close_and_free(bContext *C, wmWindowManager *);
extern void wm_close_and_free_all(bContext *C, ListBase *);
+/**
+ * On startup, it adds all data, for matching.
+ */
extern void wm_add_default(struct Main *bmain, bContext *C);
extern void wm_clear_default_size(bContext *C);
/* register to windowmanager for redo or macro */
+
+/**
+ * Called on event handling by `event_system.c`.
+ *
+ * All operations get registered in the windowmanager here.
+ */
void wm_operator_register(bContext *C, wmOperator *op);
/* wm_operator.c, for init/exit */
+
void wm_operatortype_free(void);
+/**
+ * Called on initialize #WM_init().
+ */
void wm_operatortype_init(void);
+/**
+ * Default key-map for windows and screens, only call once per WM.
+ */
void wm_window_keymap(wmKeyConfig *keyconf);
void wm_operatortypes_register(void);
/* wm_gesture.c */
+/* called in wm_draw.c */
+
void wm_gesture_draw(struct wmWindow *win);
+/**
+ * Tweak and line gestures.
+ */
int wm_gesture_evaluate(wmGesture *gesture, const struct wmEvent *event);
void wm_gesture_tag_redraw(struct wmWindow *win);
/* wm_gesture_ops.c */
+
+/**
+ * Standard tweak, called after window handlers passed on event.
+ */
void wm_tweakevent_test(bContext *C, const wmEvent *event, int action);
/* wm_jobs.c */
+
+/**
+ * Hard-coded to event #TIMERJOBS.
+ */
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt);
+/**
+ * Kill job entirely, also removes timer itself.
+ */
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt);
/* wm_files.c */
+
+/**
+ * Run the auto-save timer action.
+ */
void wm_autosave_timer(struct Main *bmain, wmWindowManager *wm, wmTimer *wt);
void wm_autosave_timer_begin(struct wmWindowManager *wm);
void wm_autosave_timer_end(wmWindowManager *wm);
void wm_autosave_delete(void);
/* wm_splash_screen.c */
+
void WM_OT_splash(wmOperatorType *ot);
void WM_OT_splash_about(wmOperatorType *ot);
/* wm_stereo.c */
+
void wm_stereo3d_draw_sidebyside(wmWindow *win, int view);
void wm_stereo3d_draw_topbottom(wmWindow *win, int view);
+/**
+ * If needed, adjust \a r_mouse_xy
+ * so that drawn cursor and handled mouse position are matching visually.
+ */
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2]);
int wm_stereo3d_set_exec(bContext *C, wmOperator *op);
int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event);
@@ -93,7 +142,9 @@ void wm_stereo3d_set_draw(bContext *C, wmOperator *op);
bool wm_stereo3d_set_check(bContext *C, wmOperator *op);
void wm_stereo3d_set_cancel(bContext *C, wmOperator *op);
-/* init operator properties */
+/**
+ * Initialize operator properties.
+ */
void wm_open_init_load_ui(wmOperator *op, bool use_prefs);
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs);
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index 9b0f128d071..925be8ab183 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -144,20 +144,36 @@ typedef struct wmEventHandler_Dropbox {
} wmEventHandler_Dropbox;
/* wm_event_system.c */
+
void wm_event_free_all(wmWindow *win);
void wm_event_free(wmEvent *event);
void wm_event_free_handler(wmEventHandler *handler);
-/* goes over entire hierarchy: events -> window -> screen -> area -> region */
+/**
+ * Goes over entire hierarchy: events -> window -> screen -> area -> region.
+ *
+ * \note Called in main loop.
+ */
void wm_event_do_handlers(bContext *C);
+/**
+ * Windows store own event queues #wmWindow.event_queue (no #bContext here).
+ */
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata);
#ifdef WITH_XR_OPENXR
void wm_event_add_xrevent(wmWindow *win, struct wmXrActionData *actiondata, short val);
#endif
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file);
+/**
+ * Was part of #wm_event_do_notifiers,
+ * split out so it can be called once before entering the #WM_main loop.
+ * This ensures operators don't run before the UI and depsgraph are initialized.
+ */
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
+/**
+ * Called in main-loop.
+ */
void wm_event_do_notifiers(bContext *C);
void wm_event_handler_ui_cancel_ex(bContext *C,
@@ -166,17 +182,36 @@ void wm_event_handler_ui_cancel_ex(bContext *C,
bool reactivate_button);
/* wm_event_query.c */
+
+/**
+ * Applies the global tablet pressure correction curve.
+ */
float wm_pressure_curve(float raw_pressure);
void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab);
-/* wm_keymap.c */
-
/* wm_dropbox.c */
+
void wm_dropbox_free(void);
+/**
+ * Additional work to cleanly end dragging. Additional because this doesn't actually remove the
+ * drag items. Should be called whenever dragging is stopped
+ * (successful or not, also when canceled).
+ */
void wm_drags_exit(wmWindowManager *wm, wmWindow *win);
void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop);
+/**
+ * Called in inner handler loop, region context.
+ */
void wm_drags_check_ops(bContext *C, const wmEvent *event);
+/**
+ * The operator of a dropbox should always be executed in the context determined by the mouse
+ * coordinates. The dropbox poll should check the context area and region as needed.
+ * So this always returns #WM_OP_INVOKE_DEFAULT.
+ */
wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *drop);
+/**
+ * Called in #wm_draw_window_onscreen.
+ */
void wm_drags_draw(bContext *C, wmWindow *win);
#ifdef __cplusplus
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index c175c211db6..437bd1057c2 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -405,7 +405,7 @@ enum {
#define _VA_IS_EVENT_MOD4(v, a, b, c) (_VA_IS_EVENT_MOD3(v, a, b) || ((v)->c))
#define _VA_IS_EVENT_MOD5(v, a, b, c, d) (_VA_IS_EVENT_MOD4(v, a, b, c) || ((v)->d))
-/* reusable IS_EVENT_MOD(event, shift, ctrl, alt, oskey), macro */
+/** Reusable `IS_EVENT_MOD(event, shift, ctrl, alt, oskey)` macro. */
#define IS_EVENT_MOD(...) VA_NARGS_CALL_OVERLOAD(_VA_IS_EVENT_MOD, __VA_ARGS__)
enum eEventType_Mask {
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 135f31cf8ac..e63afb2ed2f 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -33,6 +33,7 @@ extern "C" {
#endif
/* wm_files.c */
+
void wm_history_file_read(void);
struct wmHomeFileRead_Params {
@@ -62,6 +63,16 @@ struct wmHomeFileRead_Params {
const char *app_template_override;
};
+/**
+ * Called on startup, (context entirely filled with NULLs)
+ * or called for 'New File' both `startup.blend` and `userpref.blend` are checked.
+ *
+ * \param r_params_file_read_post: Support postponed initialization,
+ * needed for initial startup when only some sub-systems have been initialized.
+ * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored
+ * in this return argument.
+ * The caller is responsible for calling #wm_homefile_read_post with this return argument.
+ */
void wm_homefile_read_ex(struct bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
struct ReportList *reports,
@@ -70,15 +81,26 @@ void wm_homefile_read(struct bContext *C,
const struct wmHomeFileRead_Params *params_homefile,
struct ReportList *reports);
+/**
+ * Special case, support deferred execution of #wm_file_read_post,
+ * Needed when loading for the first time to workaround order of initialization bug, see T89046.
+ */
void wm_homefile_read_post(struct bContext *C,
const struct wmFileReadPost_Params *params_file_read_post);
void wm_file_read_report(bContext *C, struct Main *bmain);
void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action);
+/**
+ * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE
+ * then.
+ */
bool wm_operator_close_file_dialog_if_needed(bContext *C,
wmOperator *op,
wmGenericCallbackFn exec_fn);
+/**
+ * Check if there is data that would be lost when closing the current file without saving.
+ */
bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm);
void WM_OT_save_homefile(struct wmOperatorType *ot);
@@ -99,6 +121,7 @@ void WM_OT_save_as_mainfile(struct wmOperatorType *ot);
void WM_OT_save_mainfile(struct wmOperatorType *ot);
/* wm_files_link.c */
+
void WM_OT_link(struct wmOperatorType *ot);
void WM_OT_append(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h
index a2483d38154..e924b1e47ad 100644
--- a/source/blender/windowmanager/wm_surface.h
+++ b/source/blender/windowmanager/wm_surface.h
@@ -39,6 +39,8 @@ typedef struct wmSurface {
void *customdata;
void (*draw)(struct bContext *);
+ /* To evaluate the surface's depsgraph. Called as part of the main loop. */
+ void (*do_depsgraph)(struct bContext *C);
/** Free customdata, not the surface itself (done by wm_surface API) */
void (*free_data)(struct wmSurface *);
@@ -56,6 +58,9 @@ void wm_surfaces_free(void);
/* Utils */
void wm_surfaces_iter(struct bContext *C, void (*cb)(struct bContext *, wmSurface *));
+/* Evaluation. */
+void wm_surfaces_do_depsgraph(struct bContext *C);
+
/* Drawing */
void wm_surface_make_drawable(wmSurface *surface);
void wm_surface_clear_drawable(void);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index f205f923ec8..e44a39ecf1a 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -30,41 +30,93 @@ extern "C" {
#endif
/* *************** internal api ************** */
+
+/**
+ * \note #bContext can be null in background mode because we don't
+ * need to event handling.
+ */
void wm_ghost_init(bContext *C);
void wm_ghost_exit(void);
+/**
+ * This one should correctly check for apple top header...
+ * done for Cocoa: returns window contents (and not frame) max size.
+ */
void wm_get_screensize(int *r_width, int *r_height);
+/**
+ * Size of all screens (desktop), useful since the mouse is bound by this.
+ */
void wm_get_desktopsize(int *r_width, int *r_height);
+/**
+ * Don't change context itself.
+ */
wmWindow *wm_window_new(const struct Main *bmain,
wmWindowManager *wm,
wmWindow *parent,
bool dialog);
+/**
+ * Part of `wm_window.c` API.
+ */
wmWindow *wm_window_copy(struct Main *bmain,
wmWindowManager *wm,
wmWindow *win_src,
const bool duplicate_layout,
const bool child);
+/**
+ * A higher level version of copy that tests the new window can be added.
+ * (called from the operator directly).
+ */
wmWindow *wm_window_copy_test(bContext *C,
wmWindow *win_src,
const bool duplicate_layout,
const bool child);
+/**
+ * Including window itself.
+ * \param C: can be NULL.
+ * \note #ED_screen_exit should have been called.
+ */
void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win);
+/**
+ * This is event from ghost, or exit-Blender operator.
+ */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_title(wmWindowManager *wm, wmWindow *win);
+/**
+ * Initialize #wmWindow without `ghostwin`, open these and clear.
+ *
+ * Window size is read from window, if 0 it uses prefsize
+ * called in #WM_check, also initialize stuff after file read.
+ *
+ * \warning After running, `win->ghostwin` can be NULL in rare cases
+ * (where OpenGL driver fails to create a context for eg).
+ * We could remove them with #wm_window_ghostwindows_remove_invalid
+ * but better not since caller may continue to use.
+ * Instead, caller needs to handle the error case and cleanup.
+ */
void wm_window_ghostwindows_ensure(wmWindowManager *wm);
+/**
+ * Call after #wm_window_ghostwindows_ensure or #WM_check
+ * (after loading a new file) in the unlikely event a window couldn't be created.
+ */
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm);
void wm_window_process_events(const bContext *C);
void wm_window_clear_drawable(wmWindowManager *wm);
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win);
+/**
+ * Reset active the current window opengl drawing context.
+ */
void wm_window_reset_drawable(void);
void wm_window_raise(wmWindow *win);
void wm_window_lower(wmWindow *win);
void wm_window_set_size(wmWindow *win, int width, int height);
void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y);
+/**
+ * \brief Push rendered buffer to the screen.
+ */
void wm_window_swap_buffers(wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
@@ -79,8 +131,19 @@ void wm_window_IME_end(wmWindow *win);
#endif
/* *************** window operators ************** */
+
int wm_window_close_exec(bContext *C, struct wmOperator *op);
+/**
+ * Full-screen operator callback.
+ */
int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op);
+/**
+ * Call the quit confirmation prompt or exit directly if needed. The use can
+ * still cancel via the confirmation popup. Also, this may not quit Blender
+ * immediately, but rather schedule the closing.
+ *
+ * \param win: The window to show the confirmation popup/window in.
+ */
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) ATTR_NONNULL();
int wm_window_new_exec(bContext *C, struct wmOperator *op);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
index 8903305adb4..076f279ccbb 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
@@ -85,9 +85,6 @@ static XrActionMapBinding *wm_xr_actionmap_binding_find_except(XrActionMapItem *
return NULL;
}
-/**
- * Ensure unique name among all action map bindings.
- */
void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb)
{
char name[MAX_NAME];
@@ -118,7 +115,6 @@ void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBind
static XrActionMapBinding *wm_xr_actionmap_binding_copy(XrActionMapBinding *amb_src)
{
XrActionMapBinding *amb_dst = MEM_dupallocN(amb_src);
-
amb_dst->prev = amb_dst->next = NULL;
return amb_dst;
@@ -198,10 +194,6 @@ static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami)
}
}
-/**
- * Similar to #wm_xr_actionmap_item_properties_set()
- * but checks for the #eXrActionType and #wmOperatorType having changed.
- */
void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
{
switch (ami->type) {
@@ -278,9 +270,6 @@ static XrActionMapItem *wm_xr_actionmap_item_find_except(XrActionMap *actionmap,
return NULL;
}
-/**
- * Ensure unique name among all action map items.
- */
void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami)
{
char name[MAX_NAME];
@@ -308,25 +297,29 @@ void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem
BLI_strncpy(ami->name, name, MAX_NAME);
}
-static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami)
+static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami_src)
{
- XrActionMapItem *amin = MEM_dupallocN(ami);
-
- amin->prev = amin->next = NULL;
+ XrActionMapItem *ami_dst = MEM_dupallocN(ami_src);
+ ami_dst->prev = ami_dst->next = NULL;
- if (amin->op_properties) {
- amin->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
- WM_operator_properties_create(amin->op_properties_ptr, amin->op);
+ BLI_listbase_clear(&ami_dst->bindings);
+ LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami_src->bindings) {
+ XrActionMapBinding *amb_new = wm_xr_actionmap_binding_copy(amb);
+ BLI_addtail(&ami_dst->bindings, amb_new);
+ }
- amin->op_properties = IDP_CopyProperty(amin->op_properties);
- amin->op_properties_ptr->data = amin->op_properties;
+ if (ami_dst->op_properties) {
+ ami_dst->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
+ WM_operator_properties_create(ami_dst->op_properties_ptr, ami_dst->op);
+ ami_dst->op_properties = IDP_CopyProperty(ami_src->op_properties);
+ ami_dst->op_properties_ptr->data = ami_dst->op_properties;
}
else {
- amin->op_properties = NULL;
- amin->op_properties_ptr = NULL;
+ ami_dst->op_properties = NULL;
+ ami_dst->op_properties_ptr = NULL;
}
- return amin;
+ return ami_dst;
}
XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src)
@@ -411,9 +404,6 @@ static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime,
return NULL;
}
-/**
- * Ensure unique name among all action maps.
- */
void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap)
{
char name[MAX_NAME];
@@ -444,10 +434,9 @@ void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *action
static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
{
XrActionMap *am_dst = MEM_dupallocN(am_src);
-
am_dst->prev = am_dst->next = NULL;
- BLI_listbase_clear(&am_dst->items);
+ BLI_listbase_clear(&am_dst->items);
LISTBASE_FOREACH (XrActionMapItem *, ami, &am_src->items) {
XrActionMapItem *ami_new = wm_xr_actionmap_item_copy(ami);
BLI_addtail(&am_dst->items, ami_new);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
index 72d88bb3043..5d0163af5e1 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
@@ -139,12 +139,6 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true);
}
-/**
- * \brief Draw a viewport for a single eye.
- *
- * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
- * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
- */
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
{
wmXrDrawData *draw_data = customdata;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index 7de1f254224..e2368901757 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -213,6 +213,11 @@ void wm_xr_session_draw_data_update(wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
wmXrDrawData *draw_data);
+/**
+ * Update information that is only stored for external state queries. E.g. for Python API to
+ * request the current (as in, last known) viewer pose.
+ * Controller data and action sets will be updated separately via wm_xr_session_actions_update().
+ */
void wm_xr_session_state_update(const XrSessionSettings *settings,
const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
@@ -230,9 +235,16 @@ void wm_xr_session_controller_data_populate(const wmXrAction *grip_action,
void wm_xr_session_controller_data_clear(wmXrSessionState *state);
/* wm_xr_draw.c */
+
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]);
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4]);
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]);
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4]);
+/**
+ * \brief Draw a viewport for a single eye.
+ *
+ * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
+ * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
+ */
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata);
void wm_xr_draw_controllers(const struct bContext *C, struct ARegion *region, void *customdata);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
index f3470edf2f7..c503f5d4fee 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -553,7 +553,7 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven
wm_xr_navigation_grab_bimanual_state_update(actiondata, data);
- /* Note: KM_PRESS and KM_RELEASE are the only two values supported by XR events during event
+ /* NOTE: #KM_PRESS and #KM_RELEASE are the only two values supported by XR events during event
* dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal
* handling starts when an input is "pressed" (action state exceeds the action threshold) and
* ends when the input is "released" (state falls below the threshold). */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 3224869b04a..bad735ee598 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -30,6 +30,7 @@
#include "BLI_math.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "DNA_camera_types.h"
#include "DNA_space_types.h"
@@ -154,10 +155,6 @@ void wm_xr_session_toggle(wmWindowManager *wm,
}
}
-/**
- * Check if the XR-Session was triggered.
- * If an error happened while trying to start a session, this returns false too.
- */
bool WM_xr_session_exists(const wmXrData *xr)
{
return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
@@ -168,9 +165,6 @@ void WM_xr_session_base_pose_reset(wmXrData *xr)
xr->runtime->session_state.force_reset_to_base_pose = true;
}
-/**
- * Check if the session is running, according to the OpenXR definition.
- */
bool WM_xr_session_is_ready(const wmXrData *xr)
{
return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
@@ -250,10 +244,9 @@ wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
* It's important that the VR session follows some existing window, otherwise it would need to have
* an own depsgraph, which is an expense we should avoid.
*/
-static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain,
- const wmWindowManager *wm,
- Scene **r_scene,
- Depsgraph **r_depsgraph)
+static void wm_xr_session_scene_and_depsgraph_get(const wmWindowManager *wm,
+ Scene **r_scene,
+ Depsgraph **r_depsgraph)
{
const wmWindow *root_win = wm_xr_session_root_window_or_fallback_get(wm, wm->xr.runtime);
@@ -263,7 +256,6 @@ static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain,
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
BLI_assert(scene && view_layer && depsgraph);
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
*r_scene = scene;
*r_depsgraph = depsgraph;
}
@@ -354,11 +346,6 @@ void wm_xr_session_draw_data_update(wmXrSessionState *state,
}
}
-/**
- * Update information that is only stored for external state queries. E.g. for Python API to
- * request the current (as in, last known) viewer pose.
- * Controller data and action sets will be updated separately via wm_xr_session_actions_update().
- */
void wm_xr_session_state_update(const XrSessionSettings *settings,
const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
@@ -1314,7 +1301,6 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state)
static void wm_xr_session_surface_draw(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- Main *bmain = CTX_data_main(C);
wmXrDrawData draw_data;
if (!WM_xr_session_is_ready(&wm->xr)) {
@@ -1323,12 +1309,32 @@ static void wm_xr_session_surface_draw(bContext *C)
Scene *scene;
Depsgraph *depsgraph;
- wm_xr_session_scene_and_evaluated_depsgraph_get(bmain, wm, &scene, &depsgraph);
+ wm_xr_session_scene_and_depsgraph_get(wm, &scene, &depsgraph);
+ /* Might fail when force-redrawing windows with #WM_redraw_windows(), which is done on file
+ * writing for example. */
+ // BLI_assert(DEG_is_fully_evaluated(depsgraph));
wm_xr_session_draw_data_populate(&wm->xr, scene, depsgraph, &draw_data);
GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
- GPU_framebuffer_restore();
+ /* There's no active framebuffer if the session was cancelled (exception while drawing views). */
+ if (GPU_framebuffer_active_get()) {
+ GPU_framebuffer_restore();
+ }
+}
+
+static void wm_xr_session_do_depsgraph(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ if (!WM_xr_session_is_ready(&wm->xr)) {
+ return;
+ }
+
+ Scene *scene;
+ Depsgraph *depsgraph;
+ wm_xr_session_scene_and_depsgraph_get(wm, &scene, &depsgraph);
+ BKE_scene_graph_evaluated_ensure(depsgraph, CTX_data_main(C));
}
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
@@ -1439,6 +1445,7 @@ static wmSurface *wm_xr_session_surface_create(void)
data->controller_art = MEM_callocN(sizeof(*(data->controller_art)), "XrControllerRegionType");
surface->draw = wm_xr_session_surface_draw;
+ surface->do_depsgraph = wm_xr_session_do_depsgraph;
surface->free_data = wm_xr_session_surface_free_data;
surface->activate = DRW_xr_drawing_begin;
surface->deactivate = DRW_xr_drawing_end;